Bug 1827704 - Migrate to the upstream wasm2c for RLBox sandboxing r=glandium

Differential Revision: https://phabricator.services.mozilla.com/D175439
This commit is contained in:
Shravan Narayan 2023-04-21 01:31:35 +00:00
parent 4d6ebc058d
commit ed0bb19d78
183 changed files with 16116 additions and 15441 deletions

View File

@ -21,4 +21,10 @@
// fixed.
#define RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
// When instantiating a wasm sandbox, rlbox requires the name of the wasm module
// being instantiated. LLVM and wasm2c use the module name by choosing the name
// used to generate the wasm file. In Firefox this is a static library called
// rlbox
#define RLBOX_WASM2C_MODULE_NAME rlbox
#endif

View File

@ -6,8 +6,19 @@
EXPORTS.mozilla.rlbox += [
"/third_party/rlbox_wasm2c_sandbox/include/rlbox_wasm2c_sandbox.hpp",
"/third_party/rlbox_wasm2c_sandbox/include/rlbox_wasm2c_tls.hpp",
]
EXPORTS += [
"/third_party/rlbox_wasm2c_sandbox/include/wasm2c_rt_mem.h",
"/third_party/rlbox_wasm2c_sandbox/include/wasm2c_rt_minwasi.h",
]
SOURCES += ["rlbox_wasm2c_thread_locals.cpp"]
SOURCES += [
"/third_party/rlbox_wasm2c_sandbox/src/wasm2c_rt_mem.c",
"/third_party/rlbox_wasm2c_sandbox/src/wasm2c_rt_minwasi.c",
"rlbox_wasm2c_thread_locals.cpp",
]
LOCAL_INCLUDES += ["/third_party/wasm2c/wasm2c/"]
FINAL_LIBRARY = "xul"

View File

@ -7,10 +7,10 @@ bugzilla:
origin:
name: rlbox_wasm2c_sandbox
description: rlbox integration for the wasm2c sandboxed code
url: https://github.com/PLSysSec/rlbox_wasm2c_sandbox
url: https://github.com/PLSysSec/rlbox_wasm2c_sandbox/tree/upstream-wasm2c
release: commit 54e8469095e7929c66aeecdc26f23f502b986218 (2021-12-08T08:12:13Z).
revision: 54e8469095e7929c66aeecdc26f23f502b986218
release: 7e4ff0ebca2c7644a297bfe51a53b9904f0999b2 (2023-04-13T05:07:28Z).
revision: 7e4ff0ebca2c7644a297bfe51a53b9904f0999b2
license: MIT
license-file: LICENSE
@ -32,5 +32,3 @@ vendoring:
- CMakeLists.txt
- LibrarySandbox.md
- README.md

View File

@ -10,10 +10,8 @@
// Load general firefox configuration of RLBox
# include "mozilla/rlbox/rlbox_config.h"
# include "mozilla/rlbox/rlbox_wasm2c_sandbox.hpp"
# include "mozilla/rlbox/rlbox.hpp"
# include "mozilla/rlbox/rlbox_wasm2c_tls.hpp"
# include "wasm-rt.h"
# include "nsExceptionHandler.h"
@ -26,16 +24,13 @@ extern "C" {
// Any error encountered by the wasm2c runtime or wasm sandboxed library code
// is configured to call the below trap handler.
void moz_wasm2c_trap_handler(const char* msg) {
MOZ_CRASH_UNSAFE_PRINTF("wasm2c crash: %s", msg);
void moz_wasm2c_trap_handler(wasm_rt_trap_t code) {
MOZ_CRASH_UNSAFE_PRINTF("wasm2c crash: %s", wasm_rt_strerror(code));
}
// The below function is called if a malloc in sandboxed code returns null
// This indicates that the sandbox has run out of memory.
void moz_wasm2c_malloc_failed(uint32_t size) {
// We don't use the allocation size information for now
(void)size;
void moz_wasm2c_memgrow_failed() {
CrashReporter::AnnotateCrashReport(
CrashReporter::Annotation::WasmLibrarySandboxMallocFailed, true);
}

View File

@ -4,10 +4,13 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
LOCAL_INCLUDES += ["/third_party/wasm2c/"]
LOCAL_INCLUDES += [
"/third_party/picosha2/",
"/third_party/wasm2c/include/",
]
GeneratedFile(
"config.h",
"wabt/config.h",
script="preprocess_wasm2c_config.py",
entry_point="generate_config",
inputs=["/third_party/wasm2c/src/config.h.in"],
@ -18,6 +21,8 @@ HOST_SOURCES += [
"/third_party/wasm2c/src/apply-names.cc",
"/third_party/wasm2c/src/binary-reader-ir.cc",
"/third_party/wasm2c/src/binary-reader-logging.cc",
"/third_party/wasm2c/src/binary-reader-objdump.cc",
"/third_party/wasm2c/src/binary-reader-opcnt.cc",
"/third_party/wasm2c/src/binary-reader.cc",
"/third_party/wasm2c/src/binary-writer-spec.cc",
"/third_party/wasm2c/src/binary-writer.cc",
@ -27,12 +32,12 @@ HOST_SOURCES += [
"/third_party/wasm2c/src/common.cc",
"/third_party/wasm2c/src/config.cc",
"/third_party/wasm2c/src/decompiler.cc",
"/third_party/wasm2c/src/emscripten-helpers.cc",
"/third_party/wasm2c/src/error-formatter.cc",
"/third_party/wasm2c/src/expr-visitor.cc",
"/third_party/wasm2c/src/feature.cc",
"/third_party/wasm2c/src/filenames.cc",
"/third_party/wasm2c/src/generate-names.cc",
"/third_party/wasm2c/src/hash-util.cc",
"/third_party/wasm2c/src/ir-util.cc",
"/third_party/wasm2c/src/ir.cc",
"/third_party/wasm2c/src/leb128.cc",
@ -43,9 +48,9 @@ HOST_SOURCES += [
"/third_party/wasm2c/src/opcode.cc",
"/third_party/wasm2c/src/option-parser.cc",
"/third_party/wasm2c/src/resolve-names.cc",
"/third_party/wasm2c/src/sha256.cc",
"/third_party/wasm2c/src/shared-validator.cc",
"/third_party/wasm2c/src/stream.cc",
"/third_party/wasm2c/src/string-view.cc",
"/third_party/wasm2c/src/token.cc",
"/third_party/wasm2c/src/tracing.cc",
"/third_party/wasm2c/src/type-checker.cc",
@ -59,6 +64,10 @@ HOST_SOURCES += [
# wasm2c sources
HOST_SOURCES += [
"/third_party/wasm2c/src/c-writer.cc",
"/third_party/wasm2c/src/prebuilt/wasm2c_header_bottom.cc",
"/third_party/wasm2c/src/prebuilt/wasm2c_header_top.cc",
"/third_party/wasm2c/src/prebuilt/wasm2c_source_declarations.cc",
"/third_party/wasm2c/src/prebuilt/wasm2c_source_includes.cc",
"/third_party/wasm2c/src/tools/wasm2c.cc",
]

View File

@ -7,44 +7,40 @@ bugzilla:
origin:
name: wasm2c_sandbox_compiler
description: wasm2c fork used for rlbox sandboxing
url: https://github.com/PLSysSec/wasm2c_sandbox_compiler
url: https://github.com/WebAssembly/wabt
release: 3266be52998117f47b490d026b02e4193d5d3338 (2022-11-24T04:56:29Z).
revision: 3266be52998117f47b490d026b02e4193d5d3338
release: ad5f1385fa7afe29e98d69b6167132162675228f (2023-04-13T05:14:45Z).
revision: ad5f1385fa7afe29e98d69b6167132162675228f
license: Apache-2.0
license-file: LICENSE
vendoring:
url: https://github.com/PLSysSec/wasm2c_sandbox_compiler
url: https://github.com/WebAssembly/wabt
source-hosting: github
vendor-directory: third_party/wasm2c
# ideally we would have exclude *, and the explicitly include certain folders, but this does not work
# so just explicitly exclude what we don't want for now
exclude:
# dirs
- cmake
- docs
- fuzz-in
- include/wabt/interp
- man
- scripts
- src/interp
- src/template
- test
- third_party
- src/interp
- wasm2c/examples
# files
- .clang-format
- .flake8
- .gitattributes
- .gitignore
- .gitmodules
- .style.yapf
- .*
- CMakeLists.txt
- Contributing.md
- Makefile
- README.md
- ubsan.blacklist
- wasm2c/examples/hello/.gitignore
- wasm2c/wasm-rt-runner.c
- wasm2c/wasm-rt-static-runner.c
- src/tools/s*
- src/tools/wasm-*
- src/tools/wast*
- src/tools/wat*
- src/tools/wasm2w*

View File

@ -15,13 +15,16 @@ import itertools
# This python script knows how to replace the following variables normally configured by cmake for
# the wasm2c source
known_vars = [
"#cmakedefine CMAKE_PROJECT_VERSION",
'#cmakedefine WABT_VERSION_STRING "@WABT_VERSION_STRING@"',
"#cmakedefine WABT_DEBUG @WABT_DEBUG@",
"#cmakedefine01 HAVE_ALLOCA_H",
"#cmakedefine01 HAVE_UNISTD_H",
"#cmakedefine01 HAVE_SNPRINTF",
"#cmakedefine01 HAVE_SSIZE_T",
"#cmakedefine01 HAVE_STRCASECMP",
"#cmakedefine01 HAVE_WIN32_VT100",
"#cmakedefine01 WABT_BIG_ENDIAN",
"#cmakedefine01 HAVE_OPENSSL_SHA_H",
"#cmakedefine01 COMPILER_IS_CLANG",
"#cmakedefine01 COMPILER_IS_GNU",
"#cmakedefine01 COMPILER_IS_MSVC",
@ -31,13 +34,14 @@ known_vars = [
# The above variables are replaced with the code shown below
replaced_variables = """
#include "mozilla-config.h"
#define CMAKE_PROJECT_VERSION "Firefox-in-tree-version"
// mozilla-config.h defines the following which is used
// - HAVE_ALLOCA_H
// - HAVE_UNISTD_H
#include "mozilla-config.h"
#define WABT_VERSION_STRING "Firefox-in-tree-version"
#define WABT_DEBUG 0
#ifdef _WIN32
// Ignore whatever is set in mozilla-config.h wrt alloca because it is
@ -55,6 +59,21 @@ replaced_variables = """
#define HAVE_WIN32_VT100 0
#endif
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define WABT_BIG_ENDIAN 0
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define WABT_BIG_ENDIAN 1
# else
# error "Can't handle mixed-endian architectures"
# endif
#else
# error "Don't know how to determine endianness"
#endif
/* Use internal Pico-SHA. Never use OpenSSL */
#define HAVE_OPENSSL_SHA_H 0
/* Whether snprintf is defined by stdio.h */
#define HAVE_SNPRINTF 1

View File

@ -499,7 +499,7 @@ $(LIBRARY): $(OBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(WASM_ARCHIVE): $(CWASMOBJS) $(CPPWASMOBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD_VERBOSE)
$(RM) $(WASM_ARCHIVE)
$(WASM_CXX) -o $@ -Wl,--export-all -Wl,--stack-first -Wl,-z,stack-size=$(if $(MOZ_OPTIMIZE),262144,1048576) -Wl,--no-entry -Wl,--growable-table $(CWASMOBJS) $(CPPWASMOBJS) -lwasi-emulated-process-clocks
$(WASM_CXX) -o $@ -Wl,--export-all -Wl,--stack-first -Wl,-z,stack-size=$(if $(MOZ_OPTIMIZE),262144,1048576) -Wl,--no-entry -Wl,--growable-table -Wl,--import-memory -Wl,--import-table $(CWASMOBJS) $(CPPWASMOBJS) -lwasi-emulated-process-clocks
$(addsuffix .c,$(WASM_ARCHIVE)): $(WASM_ARCHIVE) $(DIST)/host/bin/wasm2c$(HOST_BIN_SUFFIX)
$(DIST)/host/bin/wasm2c$(HOST_BIN_SUFFIX) -o $@ $<

View File

@ -36,15 +36,12 @@ RLBoxHunspell* RLBoxHunspell::Create(const nsCString& affpath,
#if defined(MOZ_WASM_SANDBOXING_HUNSPELL) && !defined(HAVE_64BIT_BUILD)
// By default, the rlbox sandbox size is smaller on 32-bit builds than the max
// 4GB We may need to ask for a larger sandbox size for hunspell to spellcheck
// in some locales See Bug 1739669 for more details
// 4GB. We may need to ask for a larger sandbox size for hunspell to
// spellcheck in some locales See Bug 1739669 for more details
const uint64_t defaultMaxSizeForSandbox =
wasm_rt_get_default_max_linear_memory_size();
// We first get the size of the dictionary.
// This is actually the first read we try on dpath and it might fail for
// whatever filesystem reasons (invalid path, unaccessible, ...).
// We first get the size of the dictionary. This is actually the first read we
// try on dpath and it might fail for whatever filesystem reasons (invalid
// path, unaccessible, ...).
Result<int64_t, nsresult> dictSizeResult =
mozHunspellFileMgrHost::GetSize(dpath);
NS_ENSURE_TRUE(dictSizeResult.isOk(), nullptr);
@ -59,13 +56,12 @@ RLBoxHunspell* RLBoxHunspell::Create(const nsCString& affpath,
// and bug 1739761 for the analysis behind this.
const uint64_t expectedMaxMemory = static_cast<uint64_t>(4.8 * dictSize);
// If we expect a higher memory usage, override the defaults
// else stick with the defaults for the sandbox
const uint64_t selectedMaxMemory =
std::max(expectedMaxMemory, defaultMaxSizeForSandbox);
// Get a capacity of at least the expected size
const w2c_mem_capacity capacity = get_valid_wasm2c_memory_capacity(
expectedMaxMemory, true /* wasm's 32-bit memory */);
bool success = sandbox->create_sandbox(/* shouldAbortOnFailure = */ false,
selectedMaxMemory);
bool success =
sandbox->create_sandbox(/* shouldAbortOnFailure = */ false, &capacity);
#elif defined(MOZ_WASM_SANDBOXING_HUNSPELL)
bool success = sandbox->create_sandbox(/* shouldAbortOnFailure = */ false);
#else

View File

@ -55,7 +55,9 @@ UniquePtr<RLBoxSandboxDataBase> RLBoxWOFF2SandboxPool::CreateSandboxData(
auto sandbox = MakeUnique<rlbox_sandbox_woff2>();
#if defined(MOZ_WASM_SANDBOXING_WOFF2)
bool createOK = sandbox->create_sandbox(/* infallible = */ false, aSize);
const w2c_mem_capacity capacity =
get_valid_wasm2c_memory_capacity(aSize, true /* 32-bit wasm memory*/);
bool createOK = sandbox->create_sandbox(/* infallible = */ false, &capacity);
#else
bool createOK = sandbox->create_sandbox();
#endif

View File

@ -1415,7 +1415,9 @@ RLBoxExpatSandboxPool::CreateSandboxData(uint64_t aSize) {
auto sandbox = mozilla::MakeUnique<rlbox_sandbox_expat>();
#ifdef MOZ_WASM_SANDBOXING_EXPAT
bool create_ok = sandbox->create_sandbox(/* infallible = */ false, aSize);
const w2c_mem_capacity capacity =
get_valid_wasm2c_memory_capacity(aSize, true /* 32-bit wasm memory*/);
bool create_ok = sandbox->create_sandbox(/* infallible = */ false, &capacity);
#else
bool create_ok = sandbox->create_sandbox();
#endif

View File

@ -17,20 +17,26 @@ EXPORTS += [
SOURCES += [
"!rlbox.wasm.c",
"/third_party/wasm2c/wasm2c/wasm-rt-impl.c",
"/third_party/wasm2c/wasm2c/wasm-rt-os-unix.c",
"/third_party/wasm2c/wasm2c/wasm-rt-os-win.c",
"/third_party/wasm2c/wasm2c/wasm-rt-wasi.c",
]
# Configure the wasm runtime to use a custom trap handler that calls MOZ_CRASH
DEFINES["WASM_RT_CUSTOM_TRAP_HANDLER"] = "moz_wasm2c_trap_handler"
# Configuration for the wasm2c runtime used by RLBox
# Configure the wasm runtime to invoke a callback when a malloc fails inside
# the sandbox. This information is used to annotate crash reports
DEFINES["WASM2C_MALLOC_FAIL_CALLBACK"] = "moz_wasm2c_malloc_failed"
# Use a mmap style allocation
DEFINES["WASM_RT_USE_MMAP"] = 1
# Don't use internal signal handler as Firefox already provides one
DEFINES["WASM_RT_SKIP_SIGNAL_RECOVERY"] = 1
# We provide a custom trap handler that calls MOZ_CRASH
DEFINES["WASM_RT_TRAP_HANDLER"] = "moz_wasm2c_trap_handler"
# Don't limit the nested call depth
DEFINES["WASM_RT_USE_STACK_DEPTH_COUNT"] = 0
# Configure the wasm runtime to invoke a callback when a Wasm memory growth
# fails inside the sandbox. This information is used to annotate crash reports.
DEFINES["WASM_RT_GROW_FAILED_HANDLER"] = "moz_wasm2c_memgrow_failed"
# Configuration that removes the wasm2c functions from shared library exports
DEFINES["WASM_DONT_EXPORT_FUNCS"] = True
FINAL_LIBRARY = "xul"

21
third_party/picosha2/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 okdshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

138
third_party/picosha2/README.md vendored Normal file
View File

@ -0,0 +1,138 @@
# PicoSHA2 - a C++ SHA256 hash generator
Copyright &copy; 2017 okdshin
## Introduction
PicoSHA2 is a tiny SHA256 hash generator for C++ with following properties:
- header-file only
- no external dependencies (only uses standard C++ libraries)
- STL-friendly
- licensed under MIT License
## Generating SHA256 hash and hash hex string
```c++
// any STL sequantial container (vector, list, dequeue...)
std::string src_str = "The quick brown fox jumps over the lazy dog";
std::vector<unsigned char> hash(picosha2::k_digest_size);
picosha2::hash256(src_str.begin(), src_str.end(), hash.begin(), hash.end());
std::string hex_str = picosha2::bytes_to_hex_string(hash.begin(), hash.end());
```
## Generating SHA256 hash and hash hex string from byte stream
```c++
picosha2::hash256_one_by_one hasher;
...
hasher.process(block.begin(), block.end());
...
hasher.finish();
std::vector<unsigned char> hash(picosha2::k_digest_size);
hasher.get_hash_bytes(hash.begin(), hash.end());
std::string hex_str = picosha2::get_hash_hex_string(hasher);
```
The file `example/interactive_hasher.cpp` has more detailed information.
## Generating SHA256 hash from a binary file
```c++
std::ifstream f("file.txt", std::ios::binary);
std::vector<unsigned char> s(picosha2::k_digest_size);
picosha2::hash256(f, s.begin(), s.end());
```
This `hash256` may use less memory than reading whole of the file.
## Generating SHA256 hash hex string from std::string
```c++
std::string src_str = "The quick brown fox jumps over the lazy dog";
std::string hash_hex_str;
picosha2::hash256_hex_string(src_str, hash_hex_str);
std::cout << hash_hex_str << std::endl;
//this output is "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"
```
```c++
std::string src_str = "The quick brown fox jumps over the lazy dog";
std::string hash_hex_str = picosha2::hash256_hex_string(src_str);
std::cout << hash_hex_str << std::endl;
//this output is "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"
```
```c++
std::string src_str = "The quick brown fox jumps over the lazy dog.";//add '.'
std::string hash_hex_str = picosha2::hash256_hex_string(src_str.begin(), src_str.end());
std::cout << hash_hex_str << std::endl;
//this output is "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"
```
## Generating SHA256 hash hex string from byte sequence
```c++
std::vector<unsigned char> src_vect(...);
std::string hash_hex_str;
picosha2::hash256_hex_string(src_vect, hash_hex_str);
```
```c++
std::vector<unsigned char> src_vect(...);
std::string hash_hex_str = picosha2::hash256_hex_string(src_vect);
```
```c++
unsigned char src_c_array[picosha2::k_digest_size] = {...};
std::string hash_hex_str;
picosha2::hash256_hex_string(src_c_array, src_c_array+picosha2::k_digest_size, hash_hex_str);
```
```c++
unsigned char src_c_array[picosha2::k_digest_size] = {...};
std::string hash_hex_str = picosha2::hash256_hex_string(src_c_array, src_c_array+picosha2::k_digest_size);
```
## Generating SHA256 hash byte sequence from STL sequential container
```c++
//any STL sequantial container (vector, list, dequeue...)
std::string src_str = "The quick brown fox jumps over the lazy dog";
//any STL sequantial containers (vector, list, dequeue...)
std::vector<unsigned char> hash(picosha2::k_digest_size);
// in: container, out: container
picosha2::hash256(src_str, hash);
```
```c++
//any STL sequantial container (vector, list, dequeue...)
std::string src_str = "The quick brown fox jumps over the lazy dog";
//any STL sequantial containers (vector, list, dequeue...)
std::vector<unsigned char> hash(picosha2::k_digest_size);
// in: iterator pair, out: contaner
picosha2::hash256(src_str.begin(), src_str.end(), hash);
```
```c++
std::string src_str = "The quick brown fox jumps over the lazy dog";
unsigned char hash_byte_c_array[picosha2::k_digest_size];
// in: container, out: iterator(pointer) pair
picosha2::hash256(src_str, hash_byte_c_array, hash_byte_c_array+picosha2::k_digest_size);
```
```c++
std::string src_str = "The quick brown fox jumps over the lazy dog";
std::vector<unsigned char> hash(picosha2::k_digest_size);
// in: iterator pair, out: iterator pair
picosha2::hash256(src_str.begin(), src_str.end(), hash.begin(), hash.end());
```

25
third_party/picosha2/moz.yaml vendored Normal file
View File

@ -0,0 +1,25 @@
schema: 1
bugzilla:
product: Core
component: "General"
origin:
name: picosha2
description: tiny header-only SHA256 hash generator for C++
url: https://github.com/okdshin/PicoSHA2
release: 27fcf6979298949e8a462e16d09a0351c18fcaf2 (2022-08-08T10:31:07Z).
revision: 27fcf6979298949e8a462e16d09a0351c18fcaf2
license: MIT
license-file: LICENSE
vendoring:
url: https://github.com/okdshin/PicoSHA2
source-hosting: github
vendor-directory: third_party/picosha2
exclude:
- example/*
- test/*
- CMakeLists.txt

377
third_party/picosha2/picosha2.h vendored Normal file
View File

@ -0,0 +1,377 @@
/*
The MIT License (MIT)
Copyright (C) 2017 okdshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PICOSHA2_H
#define PICOSHA2_H
// picosha2:20140213
#ifndef PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR
#define PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR \
1048576 //=1024*1024: default is 1MB memory
#endif
#include <algorithm>
#include <cassert>
#include <iterator>
#include <sstream>
#include <vector>
#include <fstream>
namespace picosha2 {
typedef unsigned long word_t;
typedef unsigned char byte_t;
static const size_t k_digest_size = 32;
namespace detail {
inline byte_t mask_8bit(byte_t x) { return x & 0xff; }
inline word_t mask_32bit(word_t x) { return x & 0xffffffff; }
const word_t add_constant[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
const word_t initial_message_digest[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372,
0xa54ff53a, 0x510e527f, 0x9b05688c,
0x1f83d9ab, 0x5be0cd19};
inline word_t ch(word_t x, word_t y, word_t z) { return (x & y) ^ ((~x) & z); }
inline word_t maj(word_t x, word_t y, word_t z) {
return (x & y) ^ (x & z) ^ (y & z);
}
inline word_t rotr(word_t x, std::size_t n) {
assert(n < 32);
return mask_32bit((x >> n) | (x << (32 - n)));
}
inline word_t bsig0(word_t x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); }
inline word_t bsig1(word_t x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); }
inline word_t shr(word_t x, std::size_t n) {
assert(n < 32);
return x >> n;
}
inline word_t ssig0(word_t x) { return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3); }
inline word_t ssig1(word_t x) { return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10); }
template <typename RaIter1, typename RaIter2>
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last) {
assert(first + 64 == last);
static_cast<void>(last); // for avoiding unused-variable warning
word_t w[64];
std::fill(w, w + 64, word_t(0));
for (std::size_t i = 0; i < 16; ++i) {
w[i] = (static_cast<word_t>(mask_8bit(*(first + i * 4))) << 24) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 1))) << 16) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 2))) << 8) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 3))));
}
for (std::size_t i = 16; i < 64; ++i) {
w[i] = mask_32bit(ssig1(w[i - 2]) + w[i - 7] + ssig0(w[i - 15]) +
w[i - 16]);
}
word_t a = *message_digest;
word_t b = *(message_digest + 1);
word_t c = *(message_digest + 2);
word_t d = *(message_digest + 3);
word_t e = *(message_digest + 4);
word_t f = *(message_digest + 5);
word_t g = *(message_digest + 6);
word_t h = *(message_digest + 7);
for (std::size_t i = 0; i < 64; ++i) {
word_t temp1 = h + bsig1(e) + ch(e, f, g) + add_constant[i] + w[i];
word_t temp2 = bsig0(a) + maj(a, b, c);
h = g;
g = f;
f = e;
e = mask_32bit(d + temp1);
d = c;
c = b;
b = a;
a = mask_32bit(temp1 + temp2);
}
*message_digest += a;
*(message_digest + 1) += b;
*(message_digest + 2) += c;
*(message_digest + 3) += d;
*(message_digest + 4) += e;
*(message_digest + 5) += f;
*(message_digest + 6) += g;
*(message_digest + 7) += h;
for (std::size_t i = 0; i < 8; ++i) {
*(message_digest + i) = mask_32bit(*(message_digest + i));
}
}
} // namespace detail
template <typename InIter>
void output_hex(InIter first, InIter last, std::ostream& os) {
os.setf(std::ios::hex, std::ios::basefield);
while (first != last) {
os.width(2);
os.fill('0');
os << static_cast<unsigned int>(*first);
++first;
}
os.setf(std::ios::dec, std::ios::basefield);
}
template <typename InIter>
void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str) {
std::ostringstream oss;
output_hex(first, last, oss);
hex_str.assign(oss.str());
}
template <typename InContainer>
void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str) {
bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str);
}
template <typename InIter>
std::string bytes_to_hex_string(InIter first, InIter last) {
std::string hex_str;
bytes_to_hex_string(first, last, hex_str);
return hex_str;
}
template <typename InContainer>
std::string bytes_to_hex_string(const InContainer& bytes) {
std::string hex_str;
bytes_to_hex_string(bytes, hex_str);
return hex_str;
}
class hash256_one_by_one {
public:
hash256_one_by_one() { init(); }
void init() {
buffer_.clear();
std::fill(data_length_digits_, data_length_digits_ + 4, word_t(0));
std::copy(detail::initial_message_digest,
detail::initial_message_digest + 8, h_);
}
template <typename RaIter>
void process(RaIter first, RaIter last) {
add_to_data_length(static_cast<word_t>(std::distance(first, last)));
std::copy(first, last, std::back_inserter(buffer_));
std::size_t i = 0;
for (; i + 64 <= buffer_.size(); i += 64) {
detail::hash256_block(h_, buffer_.begin() + i,
buffer_.begin() + i + 64);
}
buffer_.erase(buffer_.begin(), buffer_.begin() + i);
}
void finish() {
byte_t temp[64];
std::fill(temp, temp + 64, byte_t(0));
std::size_t remains = buffer_.size();
std::copy(buffer_.begin(), buffer_.end(), temp);
temp[remains] = 0x80;
if (remains > 55) {
std::fill(temp + remains + 1, temp + 64, byte_t(0));
detail::hash256_block(h_, temp, temp + 64);
std::fill(temp, temp + 64 - 4, byte_t(0));
} else {
std::fill(temp + remains + 1, temp + 64 - 4, byte_t(0));
}
write_data_bit_length(&(temp[56]));
detail::hash256_block(h_, temp, temp + 64);
}
template <typename OutIter>
void get_hash_bytes(OutIter first, OutIter last) const {
for (const word_t* iter = h_; iter != h_ + 8; ++iter) {
for (std::size_t i = 0; i < 4 && first != last; ++i) {
*(first++) = detail::mask_8bit(
static_cast<byte_t>((*iter >> (24 - 8 * i))));
}
}
}
private:
void add_to_data_length(word_t n) {
word_t carry = 0;
data_length_digits_[0] += n;
for (std::size_t i = 0; i < 4; ++i) {
data_length_digits_[i] += carry;
if (data_length_digits_[i] >= 65536u) {
carry = data_length_digits_[i] >> 16;
data_length_digits_[i] &= 65535u;
} else {
break;
}
}
}
void write_data_bit_length(byte_t* begin) {
word_t data_bit_length_digits[4];
std::copy(data_length_digits_, data_length_digits_ + 4,
data_bit_length_digits);
// convert byte length to bit length (multiply 8 or shift 3 times left)
word_t carry = 0;
for (std::size_t i = 0; i < 4; ++i) {
word_t before_val = data_bit_length_digits[i];
data_bit_length_digits[i] <<= 3;
data_bit_length_digits[i] |= carry;
data_bit_length_digits[i] &= 65535u;
carry = (before_val >> (16 - 3)) & 65535u;
}
// write data_bit_length
for (int i = 3; i >= 0; --i) {
(*begin++) = static_cast<byte_t>(data_bit_length_digits[i] >> 8);
(*begin++) = static_cast<byte_t>(data_bit_length_digits[i]);
}
}
std::vector<byte_t> buffer_;
word_t data_length_digits_[4]; // as 64bit integer (16bit x 4 integer)
word_t h_[8];
};
inline void get_hash_hex_string(const hash256_one_by_one& hasher,
std::string& hex_str) {
byte_t hash[k_digest_size];
hasher.get_hash_bytes(hash, hash + k_digest_size);
return bytes_to_hex_string(hash, hash + k_digest_size, hex_str);
}
inline std::string get_hash_hex_string(const hash256_one_by_one& hasher) {
std::string hex_str;
get_hash_hex_string(hasher, hex_str);
return hex_str;
}
namespace impl {
template <typename RaIter, typename OutIter>
void hash256_impl(RaIter first, RaIter last, OutIter first2, OutIter last2, int,
std::random_access_iterator_tag) {
hash256_one_by_one hasher;
// hasher.init();
hasher.process(first, last);
hasher.finish();
hasher.get_hash_bytes(first2, last2);
}
template <typename InputIter, typename OutIter>
void hash256_impl(InputIter first, InputIter last, OutIter first2,
OutIter last2, int buffer_size, std::input_iterator_tag) {
std::vector<byte_t> buffer(buffer_size);
hash256_one_by_one hasher;
// hasher.init();
while (first != last) {
int size = buffer_size;
for (int i = 0; i != buffer_size; ++i, ++first) {
if (first == last) {
size = i;
break;
}
buffer[i] = *first;
}
hasher.process(buffer.begin(), buffer.begin() + size);
}
hasher.finish();
hasher.get_hash_bytes(first2, last2);
}
}
template <typename InIter, typename OutIter>
void hash256(InIter first, InIter last, OutIter first2, OutIter last2,
int buffer_size = PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR) {
picosha2::impl::hash256_impl(
first, last, first2, last2, buffer_size,
typename std::iterator_traits<InIter>::iterator_category());
}
template <typename InIter, typename OutContainer>
void hash256(InIter first, InIter last, OutContainer& dst) {
hash256(first, last, dst.begin(), dst.end());
}
template <typename InContainer, typename OutIter>
void hash256(const InContainer& src, OutIter first, OutIter last) {
hash256(src.begin(), src.end(), first, last);
}
template <typename InContainer, typename OutContainer>
void hash256(const InContainer& src, OutContainer& dst) {
hash256(src.begin(), src.end(), dst.begin(), dst.end());
}
template <typename InIter>
void hash256_hex_string(InIter first, InIter last, std::string& hex_str) {
byte_t hashed[k_digest_size];
hash256(first, last, hashed, hashed + k_digest_size);
std::ostringstream oss;
output_hex(hashed, hashed + k_digest_size, oss);
hex_str.assign(oss.str());
}
template <typename InIter>
std::string hash256_hex_string(InIter first, InIter last) {
std::string hex_str;
hash256_hex_string(first, last, hex_str);
return hex_str;
}
inline void hash256_hex_string(const std::string& src, std::string& hex_str) {
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template <typename InContainer>
void hash256_hex_string(const InContainer& src, std::string& hex_str) {
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template <typename InContainer>
std::string hash256_hex_string(const InContainer& src) {
return hash256_hex_string(src.begin(), src.end());
}
template<typename OutIter>void hash256(std::ifstream& f, OutIter first, OutIter last){
hash256(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>(), first,last);
}
}// namespace picosha2
#endif // PICOSHA2_H

View File

@ -1,7 +1,7 @@
This directory contains the rlbox source from the upstream repo:
https://github.com/PLSysSec/rlbox_sandboxing_api/
Current version: [commit 7c77f721507749e18269f05d70f3ae00ad3e0a22]
Current version: [commit 358fb5bb02a326c631efaebdfb59b0df2ab9c602]
UPDATING:

View File

@ -40,7 +40,6 @@ public:
* @brief Unwrap a tainted value without verification. This is an unsafe
* operation and should be used with care.
*/
inline auto UNSAFE_unverified() { return impl().get_raw_value(); }
inline auto UNSAFE_unverified() const { return impl().get_raw_value(); }
/**
* @brief Like UNSAFE_unverified, but get the underlying sandbox
@ -51,10 +50,6 @@ public:
* For the Wasm-based sandbox, this function additionally validates the
* unwrapped value against the machine model of the sandbox (LP32).
*/
inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox)
{
return impl().get_raw_sandbox_value(sandbox);
}
inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const
{
return impl().get_raw_sandbox_value(sandbox);
@ -66,44 +61,41 @@ public:
*
* @param reason An explanation why the unverified unwrapping is safe.
*/
rlbox_detail_member_and_const(
template<size_t N>
inline auto unverified_safe_because(const char (&reason)[N]),
template<size_t N>
inline auto unverified_safe_because(const char (&reason)[N]) const
{
RLBOX_UNUSED(reason);
static_assert(!std::is_pointer_v<T>,
"unverified_safe_because does not support pointers. Use "
"unverified_safe_pointer_because.");
return UNSAFE_unverified();
}
template<size_t N>
inline auto unverified_safe_pointer_because(size_t count,
const char (&reason)[N]) const
{
RLBOX_UNUSED(reason);
static_assert(std::is_pointer_v<T>, "Expected pointer type");
using T_Pointed = std::remove_pointer_t<T>;
if_constexpr_named(cond1, std::is_pointer_v<T_Pointed>)
{
RLBOX_UNUSED(reason);
static_assert(!std::is_pointer_v<T>,
"unverified_safe_because does not support pointers. Use "
"unverified_safe_pointer_because.");
return UNSAFE_unverified();
});
rlbox_detail_static_fail_because(
cond1,
"There is no way to use unverified_safe_pointer_because for "
"'pointers to pointers' safely. Use copy_and_verify instead.");
return nullptr;
}
rlbox_detail_member_and_const(
template<size_t N>
inline auto unverified_safe_pointer_because(size_t count,
const char (&reason)[N]),
{
RLBOX_UNUSED(reason);
auto ret = UNSAFE_unverified();
if (ret != nullptr) {
size_t bytes = sizeof(T) * count;
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(ret, bytes);
}
return ret;
}
static_assert(std::is_pointer_v<T>, "Expected pointer type");
using T_Pointed = std::remove_pointer_t<T>;
if_constexpr_named(cond1, std::is_pointer_v<T_Pointed>)
{
rlbox_detail_static_fail_because(
cond1,
"There is no way to use unverified_safe_pointer_because for "
"'pointers to pointers' safely. Use copy_and_verify instead.");
return nullptr;
}
auto ret = UNSAFE_unverified();
if (ret != nullptr) {
size_t bytes = sizeof(T) * count;
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(ret, bytes);
}
return ret;
});
inline auto INTERNAL_unverified_safe() { return UNSAFE_unverified(); }
inline auto INTERNAL_unverified_safe() const { return UNSAFE_unverified(); }
#define BinaryOpValAndPtr(opSymbol) \
@ -163,7 +155,8 @@ public:
\
auto raw = impl().get_raw_value(); \
auto raw_rhs = detail::unwrap_value(rhs); \
static_assert(std::is_integral_v<decltype(raw_rhs)>, \
static_assert(std::is_integral_v<decltype(raw_rhs)> \
|| std::is_floating_point_v<decltype(raw_rhs)>, \
"Can only operate on numeric types"); \
\
auto ret = raw opSymbol raw_rhs; \
@ -427,7 +420,7 @@ public:
template<typename T_Rhs>
inline T_OpSubscriptArrRet& operator[](T_Rhs&& rhs)
{
rlbox_detail_forward_to_const_a(operator[], T_OpSubscriptArrRet&, rhs);
return const_cast<T_OpSubscriptArrRet&>(std::as_const(*this)[rhs]);
}
private:
@ -446,29 +439,20 @@ public:
return *ret_ptr;
}
inline T_OpDerefRet& operator*()
{
rlbox_detail_forward_to_const(operator*, T_OpDerefRet&);
}
// We need to implement the -> operator even if T is not a struct
// So that we can support code patterns such as the below
// tainted<T*> a;
// a->UNSAFE_unverified();
inline auto operator->() const
inline const T_OpDerefRet* operator->() const
{
static_assert(std::is_pointer_v<T>,
"Operator -> only supported for pointer types");
auto ret = impl().get_raw_value();
using T_Ret = std::remove_pointer_t<T>;
using T_RetWrap = const tainted_volatile<T_Ret, T_Sbx>;
return reinterpret_cast<T_RetWrap*>(ret);
return reinterpret_cast<const T_OpDerefRet*>(impl().get_raw_value());
}
inline auto operator->()
inline T_OpDerefRet* operator->()
{
using T_Ret = tainted_volatile<std::remove_pointer_t<T>, T_Sbx>*;
rlbox_detail_forward_to_const(operator->, T_Ret);
return const_cast<T_OpDerefRet*>(std::as_const(*this).operator->());
}
inline auto operator!()
@ -495,7 +479,7 @@ public:
/**
* @brief Copy tainted value from sandbox and verify it.
*
* @param verifer Function used to verify the copied value.
* @param verifier Function used to verify the copied value.
* @tparam T_Func the type of the verifier.
* @return Whatever the verifier function returns.
*/
@ -628,7 +612,7 @@ public:
/**
* @brief Copy a range of tainted values from sandbox and verify them.
*
* @param verifer Function used to verify the copied value.
* @param verifier Function used to verify the copied value.
* @param count Number of elements to copy.
* @tparam T_Func the type of the verifier. If the tainted type is ``int*``
* then ``T_Func = T_Ret(*)(unique_ptr<int[]>)``.
@ -654,7 +638,7 @@ public:
/**
* @brief Copy a tainted string from sandbox and verify it.
*
* @param verifer Function used to verify the copied value.
* @param verifier Function used to verify the copied value.
* @tparam T_Func the type of the verifier either
* ``T_Ret(*)(unique_ptr<char[]>)`` or ``T_Ret(*)(std::string)``
* @return Whatever the verifier function returns.
@ -737,7 +721,7 @@ public:
* @return Whatever the verifier function returns.
*/
template<typename T_Func>
inline auto copy_and_verify_address(T_Func verifier)
inline auto copy_and_verify_address(T_Func verifier) const
{
static_assert(std::is_pointer_v<T>,
"copy_and_verify_address must be used on pointers");
@ -760,7 +744,8 @@ public:
* @return Whatever the verifier function returns.
*/
template<typename T_Func>
inline auto copy_and_verify_buffer_address(T_Func verifier, std::size_t size)
inline auto copy_and_verify_buffer_address(T_Func verifier,
std::size_t size) const
{
static_assert(std::is_pointer_v<T>,
"copy_and_verify_address must be used on pointers");
@ -929,18 +914,6 @@ private:
return ret;
};
inline std::remove_cv_t<T_AppType> get_raw_value() noexcept
{
rlbox_detail_forward_to_const(get_raw_value, std::remove_cv_t<T_AppType>);
}
inline std::remove_cv_t<T_SandboxedType> get_raw_sandbox_value(
rlbox_sandbox<T_Sbx>& sandbox)
{
rlbox_detail_forward_to_const_a(
get_raw_sandbox_value, std::remove_cv_t<T_SandboxedType>, sandbox);
};
inline const void* find_example_pointer_or_null() const noexcept
{
if constexpr (std::is_array_v<T>) {
@ -1195,25 +1168,6 @@ private:
return data;
};
inline std::remove_cv_t<T_AppType> get_raw_value()
{
rlbox_detail_forward_to_const(get_raw_value, std::remove_cv_t<T_AppType>);
}
inline std::remove_cv_t<T_SandboxedType> get_raw_sandbox_value() noexcept
{
rlbox_detail_forward_to_const(get_raw_sandbox_value,
std::remove_cv_t<T_SandboxedType>);
};
inline std::remove_cv_t<T_SandboxedType> get_raw_sandbox_value(
rlbox_sandbox<T_Sbx>& sandbox) noexcept
{
RLBOX_UNUSED(sandbox);
rlbox_detail_forward_to_const(get_raw_sandbox_value,
std::remove_cv_t<T_SandboxedType>);
};
tainted_volatile() = default;
tainted_volatile(const tainted_volatile<T, T_Sbx>& p) = default;
@ -1223,14 +1177,12 @@ public:
auto ref =
detail::remove_volatile_from_ptr_cast(&this->get_sandbox_value_ref());
auto ref_cast = reinterpret_cast<const T*>(ref);
auto ret = tainted<const T*, T_Sbx>::internal_factory(ref_cast);
return ret;
return tainted<const T*, T_Sbx>::internal_factory(ref_cast);
}
inline tainted<T*, T_Sbx> operator&() noexcept
{
using T_Ret = tainted<T*, T_Sbx>;
rlbox_detail_forward_to_const(operator&, T_Ret);
return sandbox_const_cast<T*>(&std::as_const(*this));
}
// Needed as the definition of unary & above shadows the base's binary &

View File

@ -98,48 +98,6 @@ namespace detail {
} \
RLBOX_REQUIRE_SEMI_COLON
#define rlbox_detail_forward_to_const(func_name, result_type) \
using T_ConstClassPtr = std::add_pointer_t< \
std::add_const_t<std::remove_pointer_t<decltype(this)>>>; \
if constexpr (detail::rlbox_is_tainted_v<result_type> && \
!std::is_reference_v<result_type>) { \
return sandbox_const_cast<detail::rlbox_remove_wrapper_t<result_type>>( \
const_cast<T_ConstClassPtr>(this)->func_name()); \
} else if constexpr (detail::is_fundamental_or_enum_v<result_type> || \
detail::is_std_array_v<result_type> || \
detail::is_func_ptr_v<result_type> || \
std::is_class_v<result_type>) { \
return const_cast<T_ConstClassPtr>(this)->func_name(); \
} else { \
return const_cast<result_type>( \
const_cast<T_ConstClassPtr>(this)->func_name()); \
}
#define rlbox_detail_forward_to_const_a(func_name, result_type, ...) \
using T_ConstClassPtr = std::add_pointer_t< \
std::add_const_t<std::remove_pointer_t<decltype(this)>>>; \
if constexpr (detail::rlbox_is_tainted_v<result_type> && \
!std::is_reference_v<result_type>) { \
static_assert(detail::rlbox_is_tainted_v<result_type>); \
return sandbox_const_cast<detail::rlbox_remove_wrapper_t<result_type>>( \
const_cast<T_ConstClassPtr>(this)->func_name(__VA_ARGS__)); \
} else if constexpr (detail::is_fundamental_or_enum_v<result_type> || \
detail::is_std_array_v<result_type> || \
detail::is_func_ptr_v<result_type> || \
std::is_class_v<result_type>) { \
return const_cast<T_ConstClassPtr>(this)->func_name(__VA_ARGS__); \
} else { \
return const_cast<result_type>( \
const_cast<T_ConstClassPtr>(this)->func_name(__VA_ARGS__)); \
}
#define rlbox_detail_member_and_const(sig, ...) \
sig __VA_ARGS__ \
\
sig const __VA_ARGS__ \
\
static_assert(true)
template<typename T>
inline auto remove_volatile_from_ptr_cast(T* ptr)
{

View File

@ -100,11 +100,6 @@ private:
{
return callback_trampoline;
}
inline T_Callback get_raw_value() noexcept { return callback; }
inline T_Trampoline get_raw_sandbox_value() noexcept
{
return callback_trampoline;
}
// Keep constructor private as only rlbox_sandbox should be able to create
// this object
@ -177,12 +172,6 @@ public:
RLBOX_UNUSED(sandbox);
return get_raw_sandbox_value();
}
inline auto UNSAFE_unverified() noexcept { return get_raw_value(); }
inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) noexcept
{
RLBOX_UNUSED(sandbox);
return get_raw_sandbox_value();
}
};
template<typename T, typename T_Sbx>
@ -213,11 +202,6 @@ private:
{
return idx;
}
inline T get_raw_value() noexcept { return to_tainted().get_raw_value(); }
inline typename T_Sbx::T_PointerType get_raw_sandbox_value() noexcept
{
return idx;
}
app_pointer(app_pointer_map<typename T_Sbx::T_PointerType>* a_map,
typename T_Sbx::T_PointerType a_idx,
@ -286,12 +270,6 @@ public:
RLBOX_UNUSED(sandbox);
return get_raw_sandbox_value();
}
inline auto UNSAFE_unverified() noexcept { return get_raw_value(); }
inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) noexcept
{
RLBOX_UNUSED(sandbox);
return get_raw_sandbox_value();
}
};
/**
@ -315,7 +293,7 @@ public:
val = rhs;
return *this;
}
inline tainted_boolean_hint operator!() { return tainted_boolean_hint(!val); }
inline tainted_boolean_hint operator!() const { return tainted_boolean_hint(!val); }
template<size_t N>
inline bool unverified_safe_because(const char (&reason)[N]) const
{
@ -323,8 +301,6 @@ public:
return val;
}
inline bool UNSAFE_unverified() const { return val; }
inline bool UNSAFE_unverified() { return val; }
inline auto INTERNAL_unverified_safe() { return UNSAFE_unverified(); }
inline auto INTERNAL_unverified_safe() const { return UNSAFE_unverified(); }
// Add a template parameter to make sure the assert only fires when called
@ -373,7 +349,7 @@ public:
val = rhs;
return *this;
}
inline tainted_boolean_hint operator!() { return tainted_boolean_hint(!val); }
inline tainted_boolean_hint operator!() const { return tainted_boolean_hint(!val); }
template<size_t N>
inline int unverified_safe_because(const char (&reason)[N]) const
{
@ -381,8 +357,6 @@ public:
return val;
}
inline int UNSAFE_unverified() const { return val; }
inline int UNSAFE_unverified() { return val; }
inline auto INTERNAL_unverified_safe() { return UNSAFE_unverified(); }
inline auto INTERNAL_unverified_safe() const { return UNSAFE_unverified(); }
// Add a template parameter to make sure the assert only fires when called

View File

@ -368,7 +368,7 @@ public:
/**
* @brief Create a new sandbox.
*
* @tparam T_args Arguments passed to the underlying sandbox
* @tparam T_Args Arguments passed to the underlying sandbox
* implementation. For the null sandbox, no arguments are necessary.
*/
template<typename... T_Args>

View File

@ -227,30 +227,35 @@ tainted<T*, T_Sbx> copy_memory_or_grant_access(rlbox_sandbox<T_Sbx>& sandbox,
{
copied = false;
// Malloc in sandbox takes a uint32_t as the parameter, need a bounds check
detail::dynamic_check(num <= std::numeric_limits<uint32_t>::max(),
"Granting access too large a region");
uint32_t num_trunc = num;
// This function is meant for byte buffers only - so char and char16
static_assert(sizeof(T) <= 2);
// overflow ok
size_t source_size = num * sizeof(T);
// sandbox can grant access if it includes the following line
// using can_grant_deny_access = void;
if constexpr (detail::has_member_using_can_grant_deny_access_v<T_Sbx>) {
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(src, num_trunc);
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(src, source_size);
bool success;
auto ret = sandbox.INTERNAL_grant_access(src, num_trunc, success);
auto ret = sandbox.INTERNAL_grant_access(src, num, success);
if (success) {
return ret;
}
}
// Malloc in sandbox takes a uint32_t as the parameter, need a bounds check
detail::dynamic_check(num <= std::numeric_limits<uint32_t>::max(),
"Granting access too large a region");
using T_nocv = std::remove_cv_t<T>;
tainted<T_nocv*, T_Sbx> copy =
sandbox.template malloc_in_sandbox<T_nocv>(num_trunc);
sandbox.template malloc_in_sandbox<T_nocv>(static_cast<uint32_t>(num));
if (!copy) {
return nullptr;
}
rlbox::memcpy(sandbox, copy, src, num * sizeof(T));
rlbox::memcpy(sandbox, copy, src, source_size);
if (free_source_on_copy) {
free(const_cast<void*>(reinterpret_cast<const void*>(src)));
}
@ -267,9 +272,9 @@ tainted<T*, T_Sbx> copy_memory_or_grant_access(rlbox_sandbox<T_Sbx>& sandbox,
* - if the sandbox allows, moves the buffer out of existing sandbox memory
* @param sandbox Target sandbox
* @param src Raw pointer to the buffer
* @param num Number of bytes in the buffer
* @param num Number of T-sized elements in the buffer
* @param free_source_on_copy If the source buffer was copied, this variable
* controls whether copy_memory_or_grant_access should call delete on the src.
* controls whether copy_memory_or_deny_access should call delete on the src.
* This calls delete[] if num > 1.
* @param copied out parameter indicating if the source was copied or transfered
*/
@ -283,26 +288,36 @@ T* copy_memory_or_deny_access(rlbox_sandbox<T_Sbx>& sandbox,
bool free_source_on_copy,
bool& copied)
{
copied = false;
// This function is meant for byte buffers only - so char and char16
static_assert(sizeof(T) <= 2);
// overflow ok
size_t source_size = num * sizeof(T);
// sandbox can grant access if it includes the following line
// using can_grant_deny_access = void;
if constexpr (detail::has_member_using_can_grant_deny_access_v<T_Sbx>) {
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(
src.INTERNAL_unverified_safe(), num);
src.INTERNAL_unverified_safe(), source_size);
bool success;
auto ret = sandbox.INTERNAL_deny_access(src, num, success);
if (success) {
copied = false;
return ret;
}
}
auto copy = static_cast<T*>(malloc(num));
auto copy = static_cast<T*>(malloc(source_size));
if (!copy) {
return nullptr;
}
tainted<T*, T_Sbx> src_tainted = src;
char* src_raw = src_tainted.copy_and_verify_buffer_address(
[](uintptr_t val) { return reinterpret_cast<char*>(val); }, num);
std::memcpy(copy, src_raw, num);
std::memcpy(copy, src_raw, source_size);
if (free_source_on_copy) {
sandbox.free_in_sandbox(src);
}

View File

@ -30,6 +30,9 @@ template<typename T, typename T_Sbx>
using convert_to_sandbox_equivalent_t =
typename convert_to_sandbox_equivalent_helper<T, T_Sbx>::type;
// This is used by rlbox_load_structs_from_library to test the current namespace
struct markerStruct
{};
}
#define helper_create_converted_field(fieldType, fieldName, isFrozen) \
@ -124,18 +127,6 @@ using convert_to_sandbox_equivalent_t =
return *ret_ptr; \
} \
\
inline std::remove_cv_t<T> get_raw_value() noexcept \
{ \
rlbox_detail_forward_to_const(get_raw_value, std::remove_cv_t<T>); \
} \
\
inline std::remove_cv_t<Sbx_##libId##_##T<T_Sbx>> \
get_raw_sandbox_value() noexcept \
{ \
rlbox_detail_forward_to_const( \
get_raw_sandbox_value, std::remove_cv_t<Sbx_##libId##_##T<T_Sbx>>); \
} \
\
tainted_volatile() = default; \
tainted_volatile(const tainted_volatile<MaybeConst T, T_Sbx>& p) = \
default; \
@ -146,8 +137,7 @@ using convert_to_sandbox_equivalent_t =
helper_no_op, \
MaybeConst) \
\
inline tainted<MaybeConst T*, T_Sbx> \
operator&() noexcept \
inline tainted<MaybeConst T*, T_Sbx> operator&() const noexcept \
{ \
auto ref_cast = \
reinterpret_cast<MaybeConst T*>(&get_sandbox_value_ref()); \
@ -155,24 +145,13 @@ using convert_to_sandbox_equivalent_t =
return ret; \
} \
\
inline auto UNSAFE_unverified() { return get_raw_value(); } \
inline auto UNSAFE_unverified() const { return get_raw_value(); } \
inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) \
{ \
return get_raw_sandbox_value(sandbox); \
} \
inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const \
{ \
return get_raw_sandbox_value(sandbox); \
} \
\
template<size_t N> \
inline auto unverified_safe_because(const char (&reason)[N]) \
{ \
RLBOX_UNUSED(reason); \
return UNSAFE_unverified(); \
} \
template<size_t N> \
inline auto unverified_safe_because(const char (&reason)[N]) const \
{ \
RLBOX_UNUSED(reason); \
@ -231,20 +210,6 @@ using convert_to_sandbox_equivalent_t =
return lhs; \
} \
\
inline std::remove_cv_t<T> get_raw_value() noexcept \
{ \
rlbox_detail_forward_to_const(get_raw_value, std::remove_cv_t<T>); \
} \
\
inline std::remove_cv_t<Sbx_##libId##_##T<T_Sbx>> get_raw_sandbox_value( \
rlbox_sandbox<T_Sbx>& sandbox) noexcept \
{ \
rlbox_detail_forward_to_const_a( \
get_raw_sandbox_value, \
std::remove_cv_t<Sbx_##libId##_##T<T_Sbx>>, \
sandbox); \
} \
\
inline const void* find_example_pointer_or_null() const noexcept \
{ \
sandbox_fields_reflection_##libId##_class_##T( \
@ -258,7 +223,7 @@ using convert_to_sandbox_equivalent_t =
helper_no_op, \
MaybeConst) \
\
tainted() = default; \
tainted() = default; \
tainted(const tainted<MaybeConst T, T_Sbx>& p) = default; \
\
tainted(const tainted_volatile<T, T_Sbx>& p) \
@ -281,24 +246,13 @@ using convert_to_sandbox_equivalent_t =
return *reinterpret_cast<tainted_opaque<MaybeConst T, T_Sbx>*>(this); \
} \
\
inline auto UNSAFE_unverified() { return get_raw_value(); } \
inline auto UNSAFE_unverified() const { return get_raw_value(); } \
inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) \
{ \
return get_raw_sandbox_value(sandbox); \
} \
inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const \
{ \
return get_raw_sandbox_value(sandbox); \
} \
\
template<size_t N> \
inline auto unverified_safe_because(const char (&reason)[N]) \
{ \
RLBOX_UNUSED(reason); \
return UNSAFE_unverified(); \
} \
template<size_t N> \
inline auto unverified_safe_because(const char (&reason)[N]) const \
{ \
RLBOX_UNUSED(reason); \
@ -333,8 +287,8 @@ using convert_to_sandbox_equivalent_t =
}
#define tainted_data_specialization(T, libId) \
tainted_data_specialization_helper(, T, libId) \
tainted_data_specialization_helper(const, T, libId)
tainted_data_specialization_helper( , T, libId) \
tainted_data_specialization_helper(const, T, libId)
#define convert_type_specialization(T, libId) \
namespace detail { \
@ -380,10 +334,6 @@ using convert_to_sandbox_equivalent_t =
// clang-format off
#define rlbox_load_structs_from_library(libId) \
namespace rlbox { \
namespace detail { \
struct markerStruct \
{}; \
} \
/* check that this macro is called in a global namespace */ \
static_assert( \
::rlbox::detail::is_member_of_rlbox_detail<detail::markerStruct>, \

View File

@ -64,3 +64,24 @@ class rlbox_dylib_sandbox;
template<typename T> \
using app_pointer_##SBXNAME = \
rlbox::app_pointer<T, rlbox_##SBXNAME##_sandbox_type>;
// This is like RLBOX_DEFINE_BASE_TYPES_FOR but with an explicit sandbox type
#define RLBOX_DEFINE_BASE_TYPES_FOR_TYPE(SBXNAME, SBXTYPE) \
using rlbox_##SBXNAME##_sandbox_type = SBXTYPE; \
using rlbox_sandbox_##SBXNAME = \
rlbox::rlbox_sandbox<rlbox_##SBXNAME##_sandbox_type>; \
template<typename T> \
using sandbox_callback_##SBXNAME = \
rlbox::sandbox_callback<T, rlbox_##SBXNAME##_sandbox_type>; \
template<typename T> \
using tainted_##SBXNAME = rlbox::tainted<T, rlbox_##SBXNAME##_sandbox_type>; \
template<typename T> \
using tainted_opaque_##SBXNAME = \
rlbox::tainted_opaque<T, rlbox_##SBXNAME##_sandbox_type>; \
template<typename T> \
using tainted_volatile_##SBXNAME = \
rlbox::tainted_volatile<T, rlbox_##SBXNAME##_sandbox_type>; \
using rlbox::tainted_boolean_hint; \
template<typename T> \
using app_pointer_##SBXNAME = \
rlbox::app_pointer<T, rlbox_##SBXNAME##_sandbox_type>;

540
third_party/rlbox_wasm2c_sandbox/include/rlbox_wasm2c_sandbox.hpp vendored Executable file → Normal file
View File

@ -1,6 +1,9 @@
#pragma once
#include "rlbox_wasm2c_tls.hpp"
#include "wasm-rt.h"
#include "wasm2c_rt_mem.h"
#include "wasm2c_rt_minwasi.h"
// Pull the helper header from the main repo for dynamic_check and scope_exit
#include "rlbox_helpers.hpp"
@ -21,13 +24,14 @@
#include <vector>
#if defined(_WIN32)
// Ensure the min/max macro in the header doesn't collide with functions in std::
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
// Ensure the min/max macro in the header doesn't collide with functions in
// std::
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
#else
#include <dlfcn.h>
# include <dlfcn.h>
#endif
#define RLBOX_WASM2C_UNUSED(...) (void)__VA_ARGS__
@ -48,6 +52,76 @@
# endif
#endif
#define DEFINE_RLBOX_WASM2C_MODULE_TYPE(modname) \
struct rlbox_wasm2c_module_type_##modname \
{ \
using instance_t = w2c_##modname; \
\
using create_instance_t = void (*)(instance_t*, \
struct w2c_env*, \
struct w2c_wasi__snapshot__preview1*); \
static constexpr create_instance_t create_instance = \
&wasm2c_##modname##_instantiate; \
\
using free_instance_t = void (*)(instance_t*); \
static constexpr free_instance_t free_instance = &wasm2c_##modname##_free; \
\
using get_func_type_t = wasm_rt_func_type_t (*)(uint32_t, uint32_t, ...); \
static constexpr get_func_type_t get_func_type = \
&wasm2c_##modname##_get_func_type; \
\
static constexpr const uint64_t* initial_memory_pages = \
&wasm2c_##modname##_min_env_memory; \
static constexpr const uint8_t* is_memory_64 = \
&wasm2c_##modname##_is64_env_memory; \
static constexpr const uint32_t* initial_func_elements = \
&wasm2c_##modname##_min_env_0x5F_indirect_function_table; \
\
static constexpr const char* prefix = #modname; \
\
/* A function that returns the address of the func specified as a \
* constexpr string */ \
/* Unfortunately, there is no way to implement the below in C++. */ \
/* Implement this to fully support multiple static modules. */ \
/* static constexpr void* dlsym_in_w2c_module(const char* func_name) { */ \
/* return &w2c_##modname##_%func%; */ \
/* } */ \
\
static constexpr auto malloc_address = &w2c_##modname##_malloc; \
static constexpr auto free_address = &w2c_##modname##_free; \
}
// wasm_module_name module name used when compiling with wasm2c
#ifndef RLBOX_WASM2C_MODULE_NAME
# error "Expected definition for RLBOX_WASM2C_MODULE_NAME"
#endif
// Need an extra macro to expand RLBOX_WASM2C_MODULE_NAME
#define INVOKE_DEFINE_RLBOX_WASM2C_MODULE_TYPE(modname) \
DEFINE_RLBOX_WASM2C_MODULE_TYPE(modname)
INVOKE_DEFINE_RLBOX_WASM2C_MODULE_TYPE(RLBOX_WASM2C_MODULE_NAME);
// Concat after macro expansion
#define RLBOX_WASM2C_CONCAT2(x, y) x##y
#define RLBOX_WASM2C_CONCAT(x, y) RLBOX_WASM2C_CONCAT2(x, y)
#define RLBOX_WASM_MODULE_TYPE_CURR \
RLBOX_WASM2C_CONCAT(rlbox_wasm2c_module_type_, RLBOX_WASM2C_MODULE_NAME)
#define RLBOX_WASM2C_STRINGIFY(x) RLBOX_WASM2C_STRINGIFY2(x)
#define RLBOX_WASM2C_STRINGIFY2(x) #x
#define RLBOX_WASM2C_MODULE_NAME_STR \
RLBOX_WASM2C_STRINGIFY(RLBOX_WASM2C_MODULE_NAME)
#define RLBOX_WASM2C_MODULE_FUNC_HELPER2(part1, part2, part3) \
part1##part2##part3
#define RLBOX_WASM2C_MODULE_FUNC_HELPER(part1, part2, part3) \
RLBOX_WASM2C_MODULE_FUNC_HELPER2(part1, part2, part3)
#define RLBOX_WASM2C_MODULE_FUNC(name) \
RLBOX_WASM2C_MODULE_FUNC_HELPER(w2c_, RLBOX_WASM2C_MODULE_NAME, name)
namespace rlbox {
namespace wasm2c_detail {
@ -211,29 +285,13 @@ namespace wasm2c_detail {
} // namespace wasm2c_detail
class rlbox_wasm2c_sandbox;
struct rlbox_wasm2c_sandbox_thread_data
{
rlbox_wasm2c_sandbox* sandbox;
uint32_t last_callback_invoked;
};
#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
rlbox_wasm2c_sandbox_thread_data* get_rlbox_wasm2c_sandbox_thread_data();
# define RLBOX_WASM2C_SANDBOX_STATIC_VARIABLES() \
thread_local rlbox::rlbox_wasm2c_sandbox_thread_data \
rlbox_wasm2c_sandbox_thread_info{ 0, 0 }; \
namespace rlbox { \
rlbox_wasm2c_sandbox_thread_data* get_rlbox_wasm2c_sandbox_thread_data() \
{ \
return &rlbox_wasm2c_sandbox_thread_info; \
} \
} \
static_assert(true, "Enforce semi-colon")
// declare the static symbol with weak linkage to keep this header only
#if defined(_MSC_VER)
__declspec(selectany)
#else
__attribute__((weak))
#endif
std::once_flag rlbox_wasm2c_initialized;
class rlbox_wasm2c_sandbox
{
@ -245,22 +303,16 @@ public:
using T_ShortType = int16_t;
private:
void* sandbox = nullptr;
wasm2c_sandbox_funcs_t sandbox_info;
#if !defined(_MSC_VER)
__attribute__((weak))
#endif
static std::once_flag wasm2c_runtime_initialized;
wasm_rt_memory_t* sandbox_memory_info = nullptr;
#ifndef RLBOX_USE_STATIC_CALLS
void* library = nullptr;
#endif
mutable typename RLBOX_WASM_MODULE_TYPE_CURR::instance_t wasm2c_instance{ 0 };
struct w2c_env sandbox_memory_env;
struct w2c_wasi__snapshot__preview1 wasi_env;
bool instance_initialized = false;
wasm_rt_memory_t sandbox_memory_info;
mutable wasm_rt_funcref_table_t sandbox_callback_table;
uintptr_t heap_base;
void* exec_env = 0;
void* malloc_index = 0;
void* free_index = 0;
size_t return_slot_size = 0;
T_PointerType return_slot = 0;
mutable std::vector<T_PointerType> callback_free_list;
static const size_t MAX_CALLBACKS = 128;
mutable RLBOX_SHARED_LOCK(callback_mutex);
@ -271,7 +323,8 @@ __attribute__((weak))
mutable std::map<uint32_t, const void*> slot_assignments;
#ifndef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
thread_local static inline rlbox_wasm2c_sandbox_thread_data thread_data{ 0, 0 };
thread_local static inline rlbox_wasm2c_sandbox_thread_data thread_data{ 0,
0 };
#endif
template<typename T_FormalRet, typename T_ActualRet>
@ -309,7 +362,8 @@ __attribute__((weak))
// Callbacks are invoked through function pointers, cannot use std::forward
// as we don't have caller context for T_Args, which means they are all
// effectively passed by value
return func(thread_data.sandbox->serialize_to_sandbox<T_Args>(params)...);
return func(
thread_data.sandbox->template serialize_to_sandbox<T_Args>(params)...);
}
template<uint32_t N, typename T_Ret, typename... T_Args>
@ -333,8 +387,8 @@ __attribute__((weak))
// Callbacks are invoked through function pointers, cannot use std::forward
// as we don't have caller context for T_Args, which means they are all
// effectively passed by value
auto ret_val =
func(thread_data.sandbox->serialize_to_sandbox<T_Args>(params)...);
auto ret_val = func(
thread_data.sandbox->template serialize_to_sandbox<T_Args>(params)...);
// Copy the return value back
auto ret_ptr = reinterpret_cast<T_Ret*>(
thread_data.sandbox->template impl_get_unsandboxed_pointer<T_Ret*>(ret));
@ -342,35 +396,31 @@ __attribute__((weak))
}
template<typename T_Ret, typename... T_Args>
inline uint32_t get_wasm2c_func_index(
inline wasm_rt_func_type_t get_wasm2c_func_index(
// dummy for template inference
T_Ret (*)(T_Args...) = nullptr
) const
T_Ret (*)(T_Args...) = nullptr) const
{
// Class return types as promoted to args
constexpr bool promoted = std::is_class_v<T_Ret>;
constexpr uint32_t param_count =
promoted ? (sizeof...(T_Args) + 1) : (sizeof...(T_Args));
constexpr uint32_t ret_count =
promoted ? 0 : (std::is_void_v<T_Ret> ? 0 : 1);
// If return type is void, then there is no return type
// But it is fine if we add it anyway as it as at the end of the array
// and we pass in counts to lookup_wasm2c_func_index that would result in this
// element not being accessed
wasm_rt_type_t ret_param_types[] = {
wasm2c_detail::convert_type_to_wasm_type<T_Args>::wasm2c_type...,
wasm2c_detail::convert_type_to_wasm_type<T_Ret>::wasm2c_type
};
uint32_t param_count = 0;
uint32_t ret_count = 0;
if constexpr (promoted) {
param_count = sizeof...(T_Args) + 1;
ret_count = 0;
wasm_rt_func_type_t ret = nullptr;
if constexpr (ret_count == 0) {
ret = RLBOX_WASM_MODULE_TYPE_CURR::get_func_type(
param_count,
ret_count,
wasm2c_detail::convert_type_to_wasm_type<T_Args>::wasm2c_type...);
} else {
param_count = sizeof...(T_Args);
ret_count = std::is_void_v<T_Ret>? 0 : 1;
ret = RLBOX_WASM_MODULE_TYPE_CURR::get_func_type(
param_count,
ret_count,
wasm2c_detail::convert_type_to_wasm_type<T_Args>::wasm2c_type...,
wasm2c_detail::convert_type_to_wasm_type<T_Ret>::wasm2c_type);
}
auto ret = sandbox_info.lookup_wasm2c_func_index(sandbox, param_count, ret_count, ret_param_types);
return ret;
}
@ -388,78 +438,21 @@ __attribute__((weak))
}
}
#ifndef RLBOX_USE_STATIC_CALLS
inline void* symbol_lookup(std::string prefixed_name) {
#if defined(_WIN32)
void* ret = (void*) GetProcAddress((HMODULE) library, prefixed_name.c_str());
#else
void* ret = dlsym(library, prefixed_name.c_str());
#endif
if (ret == nullptr) {
// Some lookups such as globals are not exposed as shared library symbols
uint32_t* heap_index_pointer = (uint32_t*) sandbox_info.lookup_wasm2c_nonfunc_export(sandbox, prefixed_name.c_str());
if (heap_index_pointer != nullptr) {
uint32_t heap_index = *heap_index_pointer;
ret = &(reinterpret_cast<char*>(heap_base)[heap_index]);
}
}
return ret;
}
#endif
// function takes a 32-bit value and returns the next power of 2
// return is a 64-bit value as large 32-bit values will return 2^32
static inline uint64_t next_power_of_two(uint32_t value) {
static inline uint64_t next_power_of_two(uint32_t value)
{
uint64_t power = 1;
while(power < value) {
while (power < value) {
power *= 2;
}
return power;
}
public:
#define WASM_PAGE_SIZE 65536
#define WASM_HEAP_MAX_ALLOWED_PAGES 65536
#define WASM_MAX_HEAP (static_cast<uint64_t>(1) << 32)
static uint64_t rlbox_wasm2c_get_adjusted_heap_size(uint64_t heap_size)
{
if (heap_size == 0){
return 0;
}
if(heap_size <= WASM_PAGE_SIZE) {
return WASM_PAGE_SIZE;
} else if (heap_size >= WASM_MAX_HEAP) {
return WASM_MAX_HEAP;
}
return next_power_of_two(static_cast<uint32_t>(heap_size));
}
static uint64_t rlbox_wasm2c_get_heap_page_count(uint64_t heap_size)
{
const uint64_t pages = heap_size / WASM_PAGE_SIZE;
return pages;
}
#undef WASM_MAX_HEAP
#undef WASM_HEAP_MAX_ALLOWED_PAGES
#undef WASM_PAGE_SIZE
protected:
#ifndef RLBOX_USE_STATIC_CALLS
void* impl_lookup_symbol(const char* func_name)
{
std::string prefixed_name = "w2c_";
prefixed_name += func_name;
void* ret = symbol_lookup(prefixed_name);
return ret;
}
#else
#define rlbox_wasm2c_sandbox_lookup_symbol(func_name) \
reinterpret_cast<void*>(&w2c_##func_name) /* NOLINT */
#define rlbox_wasm2c_sandbox_lookup_symbol(func_name) \
reinterpret_cast<void*>(&RLBOX_WASM2C_MODULE_FUNC(_##func_name)) /* NOLINT \
*/
// adding a template so that we can use static_assert to fire only if this
// function is invoked
@ -474,116 +467,90 @@ protected:
"to their code, to ensure that static calls are handled correctly.");
return nullptr;
}
#endif
#if defined(_WIN32)
using path_buf = const LPCWSTR;
#else
using path_buf = const char*;
#endif
#define FALLIBLE_DYNAMIC_CHECK(infallible, cond, msg) \
if (infallible) { \
detail::dynamic_check(cond, msg); \
} else if(!(cond)) { \
impl_destroy_sandbox(); \
return false; \
public:
#define FALLIBLE_DYNAMIC_CHECK(infallible, cond, msg) \
if (infallible) { \
detail::dynamic_check(cond, msg); \
} else if (!(cond)) { \
impl_destroy_sandbox(); \
return false; \
}
/**
* @brief creates the Wasm sandbox from the given shared library
*
* @param wasm2c_module_path path to shared library compiled with wasm2c. This param is not specified if you are creating a statically linked sandbox.
* @param infallible if set to true, the sandbox aborts on failure. If false, the sandbox returns creation status as a return value
* @param override_max_heap_size optional override of the maximum size of the wasm heap allowed for this sandbox instance. When the value is zero, platform defaults are used. Non-zero values are rounded to max(64k, next power of 2).
* @param wasm_module_name optional module name used when compiling with wasm2c
* @return true when sandbox is successfully created
* @return false when infallible if set to false and sandbox was not successfully created. If infallible is set to true, this function will never return false.
* @param infallible if set to true, the sandbox aborts on failure. If false,
* the sandbox returns creation status as a return value
* @param custom_capacity allows optionally overriding the platform-specified
* maximum size of the wasm heap allowed for this sandbox instance.
* @return true when sandbox is successfully created. false when infallible is
* set to false and sandbox was not successfully created. If infallible is set
* to true, this function will never return false.
*/
inline bool impl_create_sandbox(
#ifndef RLBOX_USE_STATIC_CALLS
path_buf wasm2c_module_path,
#endif
bool infallible = true, uint64_t override_max_heap_size = 0, const char* wasm_module_name = "")
bool infallible = true,
const w2c_mem_capacity* custom_capacity = nullptr)
{
FALLIBLE_DYNAMIC_CHECK(infallible, sandbox == nullptr, "Sandbox already initialized");
FALLIBLE_DYNAMIC_CHECK(
infallible, instance_initialized == false, "Sandbox already initialized");
#ifndef RLBOX_USE_STATIC_CALLS
#if defined(_WIN32)
library = (void*) LoadLibraryW(wasm2c_module_path);
#else
library = dlopen(wasm2c_module_path, RTLD_LAZY);
#endif
bool minwasi_init_succeeded = true;
if (!library) {
std::string error_msg = "Could not load wasm2c dynamic library: ";
#if defined(_WIN32)
DWORD errorMessageID = GetLastError();
if (errorMessageID != 0) {
LPSTR messageBuffer = nullptr;
//The api creates the buffer that holds the message
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
//Copy the error message into a std::string.
std::string message(messageBuffer, size);
error_msg += message;
LocalFree(messageBuffer);
}
#else
error_msg += dlerror();
#endif
FALLIBLE_DYNAMIC_CHECK(infallible, false, error_msg.c_str());
}
#endif
#ifndef RLBOX_USE_STATIC_CALLS
std::string info_func_name = wasm_module_name;
info_func_name += "get_wasm2c_sandbox_info";
auto get_info_func = reinterpret_cast<wasm2c_sandbox_funcs_t(*)()>(symbol_lookup(info_func_name));
#else
// only permitted if there is no custom module name
std::string wasm_module_name_str = wasm_module_name;
FALLIBLE_DYNAMIC_CHECK(infallible, wasm_module_name_str.empty(), "Static calls not supported with non empty module names");
auto get_info_func = reinterpret_cast<wasm2c_sandbox_funcs_t(*)()>(get_wasm2c_sandbox_info);
#endif
FALLIBLE_DYNAMIC_CHECK(infallible, get_info_func != nullptr, "wasm2c could not find <MODULE_NAME>get_wasm2c_sandbox_info");
sandbox_info = get_info_func();
std::call_once(wasm2c_runtime_initialized, [&](){
sandbox_info.wasm_rt_sys_init();
std::call_once(rlbox_wasm2c_initialized, [&]() {
wasm_rt_init();
minwasi_init_succeeded = minwasi_init();
});
override_max_heap_size = rlbox_wasm2c_get_adjusted_heap_size(override_max_heap_size);
const uint64_t override_max_wasm_pages = rlbox_wasm2c_get_heap_page_count(override_max_heap_size);
FALLIBLE_DYNAMIC_CHECK(infallible, override_max_wasm_pages <= 65536, "Wasm allows a max heap size of 4GB");
FALLIBLE_DYNAMIC_CHECK(
infallible, minwasi_init_succeeded, "Could not initialize min wasi");
sandbox = sandbox_info.create_wasm2c_sandbox(static_cast<uint32_t>(override_max_wasm_pages));
FALLIBLE_DYNAMIC_CHECK(infallible, sandbox != nullptr, "Sandbox could not be created");
const bool minwasi_init_inst_succeeded = minwasi_init_instance(&wasi_env);
FALLIBLE_DYNAMIC_CHECK(
infallible, minwasi_init_inst_succeeded, "Could not initialize min wasi instance");
sandbox_memory_info = (wasm_rt_memory_t*) sandbox_info.lookup_wasm2c_nonfunc_export(sandbox, "w2c_memory");
FALLIBLE_DYNAMIC_CHECK(infallible, sandbox_memory_info != nullptr, "Could not get wasm2c sandbox memory info");
if (custom_capacity) {
FALLIBLE_DYNAMIC_CHECK(
infallible, custom_capacity->is_valid, "Invalid capacity");
}
sandbox_memory_info = create_wasm2c_memory(
*RLBOX_WASM_MODULE_TYPE_CURR::initial_memory_pages, custom_capacity);
FALLIBLE_DYNAMIC_CHECK(infallible,
sandbox_memory_info.data != nullptr,
"Could not allocate a heap for the wasm2c sandbox");
FALLIBLE_DYNAMIC_CHECK(infallible,
*RLBOX_WASM_MODULE_TYPE_CURR::is_memory_64 == 0,
"Does not support Wasm with memory64");
const uint32_t max_table_size = 0xffffffffu; /* this means unlimited */
wasm_rt_allocate_funcref_table(
&sandbox_callback_table,
*RLBOX_WASM_MODULE_TYPE_CURR::initial_func_elements,
max_table_size);
sandbox_memory_env.sandbox_memory_info = &sandbox_memory_info;
sandbox_memory_env.sandbox_callback_table = &sandbox_callback_table;
wasi_env.instance_memory = &sandbox_memory_info;
RLBOX_WASM_MODULE_TYPE_CURR::create_instance(
&wasm2c_instance, &sandbox_memory_env, &wasi_env);
heap_base = reinterpret_cast<uintptr_t>(impl_get_memory_location());
if constexpr (sizeof(uintptr_t) != sizeof(uint32_t)) {
// On larger platforms, check that the heap is aligned to the pointer size
// i.e. 32-bit pointer => aligned to 4GB. The implementations of
// impl_get_unsandboxed_pointer_no_ctx and impl_get_sandboxed_pointer_no_ctx
// below rely on this.
// impl_get_unsandboxed_pointer_no_ctx and
// impl_get_sandboxed_pointer_no_ctx below rely on this.
uintptr_t heap_offset_mask = std::numeric_limits<T_PointerType>::max();
FALLIBLE_DYNAMIC_CHECK(infallible, (heap_base & heap_offset_mask) == 0,
"Sandbox heap not aligned to 4GB");
FALLIBLE_DYNAMIC_CHECK(infallible,
(heap_base & heap_offset_mask) == 0,
"Sandbox heap not aligned to 4GB");
}
// cache these for performance
exec_env = sandbox;
#ifndef RLBOX_USE_STATIC_CALLS
malloc_index = impl_lookup_symbol("malloc");
free_index = impl_lookup_symbol("free");
#else
malloc_index = rlbox_wasm2c_sandbox_lookup_symbol(malloc);
free_index = rlbox_wasm2c_sandbox_lookup_symbol(free);
#endif
instance_initialized = true;
return true;
}
@ -595,21 +562,14 @@ protected:
impl_free_in_sandbox(return_slot);
}
if (sandbox != nullptr) {
sandbox_info.destroy_wasm2c_sandbox(sandbox);
sandbox = nullptr;
if (instance_initialized) {
instance_initialized = false;
RLBOX_WASM_MODULE_TYPE_CURR::free_instance(&wasm2c_instance);
}
#ifndef RLBOX_USE_STATIC_CALLS
if (library != nullptr) {
#if defined(_WIN32)
FreeLibrary((HMODULE) library);
#else
dlclose(library);
#endif
library = nullptr;
}
#endif
destroy_wasm2c_memory(&sandbox_memory_info);
wasm_rt_free_funcref_table(&sandbox_callback_table);
minwasi_cleanup_instance(&wasi_env);
}
template<typename T>
@ -641,16 +601,22 @@ protected:
slot_number = found->second;
} else {
auto func_type_idx = get_wasm2c_func_index(static_cast<T>(nullptr));
slot_number =
sandbox_info.add_wasm2c_callback(sandbox, func_type_idx, const_cast<void*>(p), WASM_RT_INTERNAL_FUNCTION);
slot_number = new_callback_slot();
wasm_rt_funcref_t func_val;
func_val.func_type = get_wasm2c_func_index(static_cast<T>(nullptr));
func_val.func =
reinterpret_cast<wasm_rt_function_ptr_t>(const_cast<void*>(p));
func_val.module_instance = &wasm2c_instance;
sandbox_callback_table.data[slot_number] = func_val;
internal_callbacks[p] = slot_number;
slot_assignments[slot_number] = p;
}
return static_cast<T_PointerType>(slot_number);
} else {
if constexpr (sizeof(uintptr_t) == sizeof(uint32_t)) {
return static_cast<T_PointerType>(reinterpret_cast<uintptr_t>(p) - heap_base);
return static_cast<T_PointerType>(reinterpret_cast<uintptr_t>(p) -
heap_base);
} else {
return static_cast<T_PointerType>(reinterpret_cast<uintptr_t>(p));
}
@ -667,13 +633,13 @@ protected:
// on 32-bit platforms we don't assume the heap is aligned
if constexpr (sizeof(uintptr_t) == sizeof(uint32_t)) {
auto sandbox = expensive_sandbox_finder(example_unsandboxed_ptr);
return sandbox->impl_get_unsandboxed_pointer<T>(p);
return sandbox->template impl_get_unsandboxed_pointer<T>(p);
} else {
if constexpr (std::is_function_v<std::remove_pointer_t<T>>) {
// swizzling function pointers needs access to the function pointer tables
// and thus cannot be done without context
// swizzling function pointers needs access to the function pointer
// tables and thus cannot be done without context
auto sandbox = expensive_sandbox_finder(example_unsandboxed_ptr);
return sandbox->impl_get_unsandboxed_pointer<T>(p);
return sandbox->template impl_get_unsandboxed_pointer<T>(p);
} else {
// grab the memory base from the example_unsandboxed_ptr
uintptr_t heap_base_mask =
@ -697,13 +663,13 @@ protected:
// on 32-bit platforms we don't assume the heap is aligned
if constexpr (sizeof(uintptr_t) == sizeof(uint32_t)) {
auto sandbox = expensive_sandbox_finder(example_unsandboxed_ptr);
return sandbox->impl_get_sandboxed_pointer<T>(p);
return sandbox->template impl_get_sandboxed_pointer<T>(p);
} else {
if constexpr (std::is_function_v<std::remove_pointer_t<T>>) {
// swizzling function pointers needs access to the function pointer tables
// and thus cannot be done without context
// swizzling function pointers needs access to the function pointer
// tables and thus cannot be done without context
auto sandbox = expensive_sandbox_finder(example_unsandboxed_ptr);
return sandbox->impl_get_sandboxed_pointer<T>(p);
return sandbox->template impl_get_sandboxed_pointer<T>(p);
} else {
// Just clear the memory base to leave the offset
RLBOX_WASM2C_UNUSED(example_unsandboxed_ptr);
@ -734,11 +700,11 @@ protected:
return !(impl_is_pointer_in_sandbox_memory(p));
}
inline size_t impl_get_total_memory() { return sandbox_memory_info->size; }
inline size_t impl_get_total_memory() { return sandbox_memory_info.size; }
inline void* impl_get_memory_location() const
{
return sandbox_memory_info->data;
return sandbox_memory_info.data;
}
template<typename T, typename T_Converted, typename... T_Args>
@ -749,9 +715,8 @@ protected:
#endif
auto old_sandbox = thread_data.sandbox;
thread_data.sandbox = this;
auto on_exit = detail::make_scope_exit([&] {
thread_data.sandbox = old_sandbox;
});
auto on_exit =
detail::make_scope_exit([&] { thread_data.sandbox = old_sandbox; });
// WASM functions are mangled in the following manner
// 1. All primitive types are left as is and follow an LP32 machine model
@ -819,7 +784,9 @@ protected:
wasm2c_detail::change_class_arg_types<T_Converted, T_PointerType>;
// Handle Point 5
using T_ConvHeap = wasm2c_detail::prepend_arg_type<T_ConvNoClass, void*>;
using T_ConvHeap = wasm2c_detail::prepend_arg_type<
T_ConvNoClass,
typename RLBOX_WASM_MODULE_TYPE_CURR::instance_t*>;
// Function invocation
auto func_ptr_conv =
@ -831,9 +798,9 @@ protected:
if constexpr (std::is_void_v<T_Ret>) {
RLBOX_WASM2C_UNUSED(ret);
func_ptr_conv(exec_env, serialize_class_arg(params)...);
func_ptr_conv(&wasm2c_instance, serialize_class_arg(params)...);
} else {
ret = func_ptr_conv(exec_env, serialize_class_arg(params)...);
ret = func_ptr_conv(&wasm2c_instance, serialize_class_arg(params)...);
}
for (size_t i = 0; i < alloc_length; i++) {
@ -847,14 +814,15 @@ protected:
inline T_PointerType impl_malloc_in_sandbox(size_t size)
{
if constexpr(sizeof(size) > sizeof(uint32_t)) {
if constexpr (sizeof(size) > sizeof(uint32_t)) {
detail::dynamic_check(size <= std::numeric_limits<uint32_t>::max(),
"Attempting to malloc more than the heap size");
}
using T_Func = void*(size_t);
using T_Converted = T_PointerType(uint32_t);
T_PointerType ret = impl_invoke_with_func_ptr<T_Func, T_Converted>(
reinterpret_cast<T_Converted*>(malloc_index),
reinterpret_cast<T_Converted*>(
RLBOX_WASM_MODULE_TYPE_CURR::malloc_address),
static_cast<uint32_t>(size));
return ret;
}
@ -864,15 +832,56 @@ protected:
using T_Func = void(void*);
using T_Converted = void(T_PointerType);
impl_invoke_with_func_ptr<T_Func, T_Converted>(
reinterpret_cast<T_Converted*>(free_index), p);
reinterpret_cast<T_Converted*>(RLBOX_WASM_MODULE_TYPE_CURR::free_address),
p);
}
private:
// Should be called with callback_mutex held
uint32_t new_callback_slot() const
{
if (callback_free_list.size() > 0) {
uint32_t ret = callback_free_list.back();
callback_free_list.pop_back();
return ret;
}
const uint32_t curr_size = sandbox_callback_table.size;
detail::dynamic_check(
curr_size < sandbox_callback_table.max_size,
"Could not find an empty row in Wasm instance table. This would "
"happen if you have registered too many callbacks, or unsandboxed "
"too many function pointers.");
wasm_rt_funcref_t func_val{ 0 };
// on success, this returns the previous number of elements in the table
const uint32_t ret =
wasm_rt_grow_funcref_table(&sandbox_callback_table, 1, func_val);
detail::dynamic_check(
ret != 0 && ret != (uint32_t)-1,
"Adding a new callback slot to the wasm instance failed.");
// We have expanded the number of slots
// Previous slots size: ret
// New slot is at index: ret
const uint32_t slot_number = ret;
return slot_number;
}
void free_callback_slot(uint32_t slot) const
{
callback_free_list.push_back(slot);
}
public:
template<typename T_Ret, typename... T_Args>
inline T_PointerType impl_register_callback(void* key, void* callback)
{
bool found = false;
uint32_t found_loc = 0;
void* chosen_interceptor = nullptr;
wasm_rt_function_ptr_t chosen_interceptor = nullptr;
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex);
@ -885,11 +894,11 @@ protected:
found_loc = i;
if constexpr (std::is_class_v<T_Ret>) {
chosen_interceptor = reinterpret_cast<void*>(
chosen_interceptor = (wasm_rt_function_ptr_t)(
callback_interceptor_promoted<i, T_Ret, T_Args...>);
} else {
chosen_interceptor =
reinterpret_cast<void*>(callback_interceptor<i, T_Ret, T_Args...>);
(wasm_rt_function_ptr_t)(callback_interceptor<i, T_Ret, T_Args...>);
}
}
});
@ -902,9 +911,13 @@ protected:
"increase the maximum allowed callbacks or unsadnboxed functions "
"pointers");
auto func_type_idx = get_wasm2c_func_index<T_Ret, T_Args...>();
uint32_t slot_number =
sandbox_info.add_wasm2c_callback(sandbox, func_type_idx, chosen_interceptor, WASM_RT_EXTERNAL_FUNCTION);
wasm_rt_funcref_t func_val;
func_val.func_type = get_wasm2c_func_index<T_Ret, T_Args...>();
func_val.func = chosen_interceptor;
func_val.module_instance = &wasm2c_instance;
const uint32_t slot_number = new_callback_slot();
sandbox_callback_table.data[slot_number] = func_val;
callback_unique_keys[found_loc] = key;
callbacks[found_loc] = callback;
@ -935,7 +948,10 @@ protected:
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex);
for (; i < MAX_CALLBACKS; i++) {
if (callback_unique_keys[i] == key) {
sandbox_info.remove_wasm2c_callback(sandbox, callback_slot_assignment[i]);
const uint32_t slot_number = callback_slot_assignment[i];
wasm_rt_funcref_t func_val{ 0 };
sandbox_callback_table.data[slot_number] = func_val;
callback_unique_keys[i] = nullptr;
callbacks[i] = nullptr;
callback_slot_assignment[i] = 0;
@ -952,12 +968,4 @@ protected:
}
};
// declare the static symbol with weak linkage to keep this header only
#if defined(_MSC_VER)
__declspec(selectany)
#else
__attribute__((weak))
#endif
std::once_flag rlbox_wasm2c_sandbox::wasm2c_runtime_initialized;
} // namespace rlbox

View File

@ -0,0 +1,33 @@
#pragma once
#include <stdint.h>
namespace rlbox {
class rlbox_wasm2c_sandbox;
struct rlbox_wasm2c_sandbox_thread_data
{
rlbox_wasm2c_sandbox* sandbox;
uint32_t last_callback_invoked;
};
#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
rlbox_wasm2c_sandbox_thread_data* get_rlbox_wasm2c_sandbox_thread_data();
# define RLBOX_WASM2C_SANDBOX_STATIC_VARIABLES() \
thread_local rlbox::rlbox_wasm2c_sandbox_thread_data \
rlbox_wasm2c_sandbox_thread_info{ 0, 0 }; \
\
namespace rlbox { \
rlbox_wasm2c_sandbox_thread_data* get_rlbox_wasm2c_sandbox_thread_data() \
{ \
return &rlbox_wasm2c_sandbox_thread_info; \
} \
} \
static_assert(true, "Enforce semi-colon")
#endif
} // namespace rlbox

View File

@ -0,0 +1,46 @@
#ifndef WASM_RT_OS_H_
#define WASM_RT_OS_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include "wasm-rt.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct w2c_env
{
wasm_rt_memory_t* sandbox_memory_info;
wasm_rt_funcref_table_t* sandbox_callback_table;
} w2c_env;
wasm_rt_memory_t* w2c_env_memory(struct w2c_env* instance);
wasm_rt_funcref_table_t* w2c_env_0x5F_indirect_function_table(
struct w2c_env*);
typedef struct w2c_mem_capacity
{
bool is_valid;
bool is_mem_32;
uint64_t max_pages;
uint64_t max_size;
} w2c_mem_capacity;
w2c_mem_capacity get_valid_wasm2c_memory_capacity(uint64_t min_capacity,
bool is_mem_32);
wasm_rt_memory_t create_wasm2c_memory(
uint32_t initial_pages,
const w2c_mem_capacity* custom_capacity);
void destroy_wasm2c_memory(wasm_rt_memory_t* memory);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,38 @@
#ifndef WASM_RT_MINWASI_H_
#define WASM_RT_MINWASI_H_
/* A minimum wasi implementation supporting only stdin, stdout, stderr, argv
* (upto 100 args) and clock functions. */
#include <stdbool.h>
#include <stdint.h>
#include "wasm-rt.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct w2c_wasi__snapshot__preview1
{
wasm_rt_memory_t* instance_memory;
uint32_t main_argc;
const char** main_argv;
uint32_t env_count;
const char** env;
void* clock_data;
} w2c_wasi__snapshot__preview1;
bool minwasi_init();
bool minwasi_init_instance(w2c_wasi__snapshot__preview1* wasi_data);
void minwasi_cleanup_instance(w2c_wasi__snapshot__preview1* wasi_data);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,454 @@
#include "wasm2c_rt_mem.h"
#include "wasm-rt.h"
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum
{
MMAP_PROT_NONE = 0,
MMAP_PROT_READ = 1,
MMAP_PROT_WRITE = 2,
MMAP_PROT_EXEC = 4
};
/* Memory map flags */
enum
{
MMAP_MAP_NONE = 0,
/* Put the mapping into 0 to 2 G, supported only on x86_64 */
MMAP_MAP_32BIT = 1,
/* Don't interpret addr as a hint: place the mapping at exactly
that address. */
MMAP_MAP_FIXED = 2
};
// Try reserving an aligned memory space.
// Returns pointer to allocated space on success, 0 on failure.
static void* os_mmap_aligned(void* addr,
size_t requested_length,
int prot,
int flags,
size_t alignment,
size_t alignment_offset);
// Unreserve the memory space
static void os_munmap(void* addr, size_t size);
// Allocates and sets the permissions on the previously reserved memory space
// Returns 0 on success, non zero on failure.
static int os_mmap_commit(void* curr_heap_end_pointer,
size_t expanded_size,
int prot);
wasm_rt_memory_t* w2c_env_memory(struct w2c_env* instance)
{
return instance->sandbox_memory_info;
}
wasm_rt_funcref_table_t* w2c_env_0x5F_indirect_function_table(
struct w2c_env* instance)
{
return instance->sandbox_callback_table;
}
#define WASM_PAGE_SIZE 65536
#define RLBOX_FOUR_GIG 0x100000000ull
#if UINTPTR_MAX == 0xffffffffffffffff
// Guard page of 4GiB
# define WASM_HEAP_GUARD_PAGE_SIZE 0x100000000ull
// Heap aligned to 4GB
# define WASM_HEAP_ALIGNMENT 0x100000000ull
// By default max heap is 4GB
# define WASM_HEAP_DEFAULT_MAX_PAGES 65536
#elif UINTPTR_MAX == 0xffffffff
// No guard pages
# define WASM_HEAP_GUARD_PAGE_SIZE 0
// Unaligned heap
# define WASM_HEAP_ALIGNMENT 0
// Default max heap is 16MB
# define WASM_HEAP_DEFAULT_MAX_PAGES 256
#else
# error "Unknown pointer size"
#endif
static uint64_t compute_heap_reserve_space(uint32_t chosen_max_pages)
{
const uint64_t heap_reserve_size =
((uint64_t)chosen_max_pages) * WASM_PAGE_SIZE + WASM_HEAP_GUARD_PAGE_SIZE;
return heap_reserve_size;
}
w2c_mem_capacity get_valid_wasm2c_memory_capacity(uint64_t min_capacity,
bool is_mem_32)
{
const w2c_mem_capacity err_val = { false /* is_valid */,
false /* is_mem_32 */,
0 /* max_pages */,
0 /* max_size */ };
// We do not handle memory 64
if (!is_mem_32) {
return err_val;
}
const uint64_t default_capacity =
((uint64_t)WASM_HEAP_DEFAULT_MAX_PAGES) * WASM_PAGE_SIZE;
if (min_capacity <= default_capacity) {
// Handle 0 case and small values
const w2c_mem_capacity ret = { true /* is_valid */,
true /* is_mem_32 */,
WASM_HEAP_DEFAULT_MAX_PAGES /* max_pages */,
default_capacity /* max_size */ };
return ret;
} else if (min_capacity > UINT32_MAX) {
// Handle out of range values
return err_val;
}
const uint64_t page_size_minus_1 = WASM_PAGE_SIZE - 1;
// Get number of pages greater than min_capacity
const uint64_t capacity_pages = ((min_capacity - 1) / page_size_minus_1) + 1;
const w2c_mem_capacity ret = { true /* is_valid */,
true /* is_mem_32 */,
capacity_pages /* max_pages */,
capacity_pages *
WASM_PAGE_SIZE /* max_size */ };
return ret;
}
wasm_rt_memory_t create_wasm2c_memory(uint32_t initial_pages,
const w2c_mem_capacity* custom_capacity)
{
if (custom_capacity && !custom_capacity->is_valid) {
wasm_rt_memory_t ret = { 0 };
return ret;
}
const uint32_t byte_length = initial_pages * WASM_PAGE_SIZE;
const uint64_t chosen_max_pages =
custom_capacity ? custom_capacity->max_pages : WASM_HEAP_DEFAULT_MAX_PAGES;
const uint64_t heap_reserve_size =
compute_heap_reserve_space(chosen_max_pages);
uint8_t* data = 0;
const uint64_t retries = 10;
for (uint64_t i = 0; i < retries; i++) {
data = (uint8_t*)os_mmap_aligned(0,
heap_reserve_size,
MMAP_PROT_NONE,
MMAP_MAP_NONE,
WASM_HEAP_ALIGNMENT,
0 /* alignment_offset */);
if (data) {
int ret =
os_mmap_commit(data, byte_length, MMAP_PROT_READ | MMAP_PROT_WRITE);
if (ret != 0) {
// failed to set permissions
os_munmap(data, heap_reserve_size);
data = 0;
}
break;
}
}
wasm_rt_memory_t ret;
ret.data = data;
ret.max_pages = chosen_max_pages;
ret.pages = initial_pages;
ret.size = byte_length;
return ret;
}
void destroy_wasm2c_memory(wasm_rt_memory_t* memory)
{
if (memory->data != 0) {
const uint64_t heap_reserve_size =
compute_heap_reserve_space(memory->max_pages);
os_munmap(memory->data, heap_reserve_size);
memory->data = 0;
}
}
#undef WASM_HEAP_DEFAULT_MAX_PAGES
#undef WASM_HEAP_ALIGNMENT
#undef WASM_HEAP_GUARD_PAGE_SIZE
#undef RLBOX_FOUR_GIG
#undef WASM_PAGE_SIZE
// Based on
// https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#BSD
// Check for windows (non cygwin) environment
#if defined(_WIN32)
# include <windows.h>
static size_t os_getpagesize()
{
SYSTEM_INFO S;
GetNativeSystemInfo(&S);
return S.dwPageSize;
}
static void* win_mmap(void* hint,
size_t size,
int prot,
int flags,
DWORD alloc_flag)
{
DWORD flProtect = PAGE_NOACCESS;
size_t request_size, page_size;
void* addr;
page_size = os_getpagesize();
request_size = (size + page_size - 1) & ~(page_size - 1);
if (request_size < size)
/* integer overflow */
return NULL;
if (request_size == 0)
request_size = page_size;
if (prot & MMAP_PROT_EXEC) {
if (prot & MMAP_PROT_WRITE)
flProtect = PAGE_EXECUTE_READWRITE;
else
flProtect = PAGE_EXECUTE_READ;
} else if (prot & MMAP_PROT_WRITE)
flProtect = PAGE_READWRITE;
else if (prot & MMAP_PROT_READ)
flProtect = PAGE_READONLY;
addr = VirtualAlloc((LPVOID)hint, request_size, alloc_flag, flProtect);
return addr;
}
static void* os_mmap_aligned(void* addr,
size_t requested_length,
int prot,
int flags,
size_t alignment,
size_t alignment_offset)
{
size_t padded_length = requested_length + alignment + alignment_offset;
uintptr_t unaligned =
(uintptr_t)win_mmap(addr, padded_length, prot, flags, MEM_RESERVE);
if (!unaligned) {
return (void*)unaligned;
}
// Round up the next address that has addr % alignment = 0
const size_t alignment_corrected = alignment == 0 ? 1 : alignment;
uintptr_t aligned_nonoffset =
(unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1);
// Currently offset 0 is aligned according to alignment
// Alignment needs to be enforced at the given offset
uintptr_t aligned = 0;
if ((aligned_nonoffset - alignment_offset) >= unaligned) {
aligned = aligned_nonoffset - alignment_offset;
} else {
aligned = aligned_nonoffset - alignment_offset + alignment;
}
if (aligned == unaligned && padded_length == requested_length) {
return (void*)aligned;
}
// Sanity check
if (aligned < unaligned ||
(aligned + (requested_length - 1)) > (unaligned + (padded_length - 1)) ||
(aligned + alignment_offset) % alignment_corrected != 0) {
os_munmap((void*)unaligned, padded_length);
return NULL;
}
// windows does not support partial unmapping, so unmap and remap
os_munmap((void*)unaligned, padded_length);
aligned = (uintptr_t)win_mmap(
(void*)aligned, requested_length, prot, flags, MEM_RESERVE);
return (void*)aligned;
}
static void os_munmap(void* addr, size_t size)
{
DWORD alloc_flag = MEM_RELEASE;
if (addr) {
if (VirtualFree(addr, 0, alloc_flag) == 0) {
size_t page_size = os_getpagesize();
size_t request_size = (size + page_size - 1) & ~(page_size - 1);
int64_t curr_err = errno;
printf("os_munmap error addr:%p, size:0x%zx, errno:%" PRId64 "\n",
addr,
request_size,
curr_err);
}
}
}
static int os_mmap_commit(void* curr_heap_end_pointer,
size_t expanded_size,
int prot)
{
uintptr_t addr = (uintptr_t)win_mmap(
curr_heap_end_pointer, expanded_size, prot, MMAP_MAP_NONE, MEM_COMMIT);
int ret = addr ? 0 : -1;
return ret;
}
#elif !defined(_WIN32) && (defined(__unix__) || defined(__unix) || \
(defined(__APPLE__) && defined(__MACH__)))
# include <sys/mman.h>
# include <unistd.h>
static size_t os_getpagesize()
{
return getpagesize();
}
static void* os_mmap(void* hint, size_t size, int prot, int flags)
{
int map_prot = PROT_NONE;
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
uint64_t request_size, page_size;
void* addr;
page_size = (uint64_t)os_getpagesize();
request_size = (size + page_size - 1) & ~(page_size - 1);
if ((size_t)request_size < size)
/* integer overflow */
return NULL;
if (request_size > 16 * (uint64_t)UINT32_MAX)
/* At most 16 G is allowed */
return NULL;
if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;
if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
# if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
# ifndef __APPLE__
if (flags & MMAP_MAP_32BIT)
map_flags |= MAP_32BIT;
# endif
# endif
if (flags & MMAP_MAP_FIXED)
map_flags |= MAP_FIXED;
addr = mmap(hint, request_size, map_prot, map_flags, -1, 0);
if (addr == MAP_FAILED)
return NULL;
return addr;
}
static void* os_mmap_aligned(void* addr,
size_t requested_length,
int prot,
int flags,
size_t alignment,
size_t alignment_offset)
{
size_t padded_length = requested_length + alignment + alignment_offset;
uintptr_t unaligned = (uintptr_t)os_mmap(addr, padded_length, prot, flags);
if (!unaligned) {
return (void*)unaligned;
}
// Round up the next address that has addr % alignment = 0
const size_t alignment_corrected = alignment == 0 ? 1 : alignment;
uintptr_t aligned_nonoffset =
(unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1);
// Currently offset 0 is aligned according to alignment
// Alignment needs to be enforced at the given offset
uintptr_t aligned = 0;
if ((aligned_nonoffset - alignment_offset) >= unaligned) {
aligned = aligned_nonoffset - alignment_offset;
} else {
aligned = aligned_nonoffset - alignment_offset + alignment;
}
// Sanity check
if (aligned < unaligned ||
(aligned + (requested_length - 1)) > (unaligned + (padded_length - 1)) ||
(aligned + alignment_offset) % alignment_corrected != 0) {
os_munmap((void*)unaligned, padded_length);
return NULL;
}
{
size_t unused_front = aligned - unaligned;
if (unused_front != 0) {
os_munmap((void*)unaligned, unused_front);
}
}
{
size_t unused_back =
(unaligned + (padded_length - 1)) - (aligned + (requested_length - 1));
if (unused_back != 0) {
os_munmap((void*)(aligned + requested_length), unused_back);
}
}
return (void*)aligned;
}
static void os_munmap(void* addr, size_t size)
{
uint64_t page_size = (uint64_t)os_getpagesize();
uint64_t request_size = (size + page_size - 1) & ~(page_size - 1);
if (addr) {
if (munmap(addr, request_size)) {
printf("os_munmap error addr:%p, size:0x%" PRIx64 ", errno:%d\n",
addr,
request_size,
errno);
}
}
}
static int os_mmap_commit(void* addr, size_t size, int prot)
{
int map_prot = PROT_NONE;
uint64_t page_size = (uint64_t)os_getpagesize();
uint64_t request_size = (size + page_size - 1) & ~(page_size - 1);
if (!addr)
return 0;
if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;
if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
return mprotect(addr, request_size, map_prot);
}
#else
# error "Unknown OS"
#endif

View File

@ -0,0 +1,799 @@
/* A minimum wasi implementation supporting only stdin, stdout, stderr, argv
* (upto 1000 args), env (upto 1000 env), and clock functions. */
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
# include <windows.h>
#endif
#if defined(__APPLE__) && defined(__MACH__)
// Macs priors to OSX 10.12 don't have the clock functions. So we will use mac
// specific options
# include <mach/mach_time.h>
# include <sys/time.h>
#endif
#include "wasm-rt.h"
#include "wasm2c_rt_minwasi.h"
#ifndef WASM_RT_CORE_TYPES_DEFINED
# define WASM_RT_CORE_TYPES_DEFINED
typedef uint8_t u8;
typedef int8_t s8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef int32_t s32;
typedef uint64_t u64;
typedef int64_t s64;
typedef float f32;
typedef double f64;
#endif
#ifndef UNLIKELY
# if defined(__GNUC__)
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
# define LIKELY(x) __builtin_expect(!!(x), 1)
# else
# define UNLIKELY(x) (x)
# define LIKELY(x) (x)
# endif
#endif
#define TRAP(x) wasm_rt_trap(WASM_RT_TRAP_##x)
#define WASI_MEMACCESS(mem, a) ((void*)&(mem->data[a]))
#define WASI_MEMCHECK_SIZE(mem, a, sz) \
if (UNLIKELY(((u64)(a)) + sz > mem->size)) \
TRAP(OOB)
#define WASI_CHECK_COPY(mem, a, sz, src) \
do { \
WASI_MEMCHECK_SIZE(mem, a, sz); \
memcpy(WASI_MEMACCESS(mem, a), src, sz); \
} while (0)
#define WASI_MEMCHECK(mem, a, t) WASI_MEMCHECK_SIZE(mem, a, sizeof(t))
#define DEFINE_WASI_LOAD(name, t1, t2, t3) \
static inline t3 name(wasm_rt_memory_t* mem, u64 addr) \
{ \
WASI_MEMCHECK(mem, addr, t1); \
t1 result; \
memcpy(&result, WASI_MEMACCESS(mem, addr), sizeof(t1)); \
return (t3)(t2)result; \
}
#define DEFINE_WASI_STORE(name, t1, t2) \
static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) \
{ \
WASI_MEMCHECK(mem, addr, t1); \
t1 wrapped = (t1)value; \
memcpy(WASI_MEMACCESS(mem, addr), &wrapped, sizeof(t1)); \
}
DEFINE_WASI_LOAD(wasm_i32_load, u32, u32, u32);
DEFINE_WASI_STORE(wasm_i32_store, u32, u32);
DEFINE_WASI_STORE(wasm_i64_store, u64, u64);
static bool safe_add_u32(u32* ret, u32 a, u32 b)
{
if (UINT32_MAX - a < b) {
*ret = 0;
return false;
}
*ret = a + b;
return true;
}
// clang-format off
////////////// Supported WASI APIs
//
// Clock operations
// ----------------
// errno_t clock_res_get(void* ctx, clockid_t clock_id, timestamp_t* resolution);
// errno_t clock_time_get(void* ctx, clockid_t clock_id, timestamp_t precision, timestamp_t* time);
//
// File operations
// ----------------
// Only the default descriptors of STDIN, STDOUT, STDERR are allowed by the
// runtime.
//
// errno_t fd_prestat_get(void* ctx, fd_t fd, prestat_t* buf);
// errno_t fd_read(void* ctx, fd_t fd, const iovec_t* iovs, size_t iovs_len, size_t* nread);
// errno_t fd_write(void* ctx, fd_t fd, const ciovec_t* iovs, size_t iovs_len, size_t* nwritten);
////////////// Partially supported WASI APIs
//
// App environment operations
// --------------------------
// These APIs work but return an empty buffer
//
// errno_t args_get(void* ctx, char** argv, char* argv_buf);
// errno_t args_sizes_get(void* ctx, size_t* argc, size_t* argv_buf_size);
// errno_t environ_get(void* ctx, char** environment, char* environ_buf);
// errno_t environ_sizes_get(void* ctx, size_t* environ_count, size_t* environ_buf_size);
//
// Proc exit operation
// -------------------
// This is a no-op here in this runtime as the focus is on library
// sandboxing
//
// errno_t proc_exit(void* ctx, exitcode_t rval);
////////////// Unsupported WASI APIs
// errno_t fd_advise(void* ctx, fd_t fd, filesize_t offset, filesize_t len, advice_t advice);
// errno_t fd_allocate(void* ctx, fd_t fd, filesize_t offset, filesize_t len);
// errno_t fd_close(void* ctx, fd_t fd);
// errno_t fd_datasync(void* ctx, fd_t fd);
// errno_t fd_fdstat_get(void* ctx, fd_t fd, fdstat_t* buf);
// errno_t fd_fdstat_set_flags(void* ctx, fd_t fd, fdflags_t flags);
// errno_t fd_fdstat_set_rights(void* ctx, fd_t fd, rights_t fs_rights_base, rights_t fs_rights_inheriting);
// errno_t fd_filestat_get(void* ctx, fd_t fd, filestat_t* buf);
// errno_t fd_filestat_set_size(void* ctx, fd_t fd, filesize_t st_size);
// errno_t fd_filestat_set_times(void* ctx, fd_t fd, timestamp_t st_atim, timestamp_t st_mtim, fstflags_t fst_flags);
// errno_t fd_pread(void* ctx, fd_t fd, const iovec_t* iovs, size_t iovs_len, filesize_t offset, size_t* nread);
// errno_t fd_prestat_dir_name(void* ctx, fd_t fd, char* path, size_t path_len);
// errno_t fd_pwrite(void* ctx, fd_t fd, const ciovec_t* iovs, size_t iovs_len, filesize_t offset, size_t* nwritten);
// errno_t fd_readdir(void* ctx, fd_t fd, void* buf, size_t buf_len, dircookie_t cookie, size_t* bufused);
// errno_t fd_renumber(void* ctx, fd_t from, fd_t to);
// errno_t fd_seek(void* ctx, fd_t fd, filedelta_t offset, whence_t whence, filesize_t* newoffset);
// errno_t fd_sync(void* ctx, fd_t fd);
// errno_t fd_tell(void* ctx, fd_t fd, filesize_t* offset);
// errno_t path_create_directory(void* ctx, fd_t fd, const char* path, size_t path_len);
// errno_t path_filestat_get(void* ctx, fd_t fd, lookupflags_t flags, const char* path, size_t path_len, filestat_t* buf);
// errno_t path_filestat_set_times(void* ctx, fd_t fd, lookupflags_t flags, const char* path, size_t path_len, timestamp_t st_atim, timestamp_t st_mtim, fstflags_t fst_flags);
// errno_t path_link(void* ctx, fd_t old_fd, lookupflags_t old_flags, const char* old_path, size_t old_path_len, fd_t new_fd, const char* new_path, size_t new_path_len);
// errno_t path_open(void* ctx, fd_t dirfd, lookupflags_t dirflags, const char* path, size_t path_len, oflags_t o_flags, rights_t fs_rights_base, rights_t fs_rights_inheriting, fdflags_t fs_flags, fd_t* fd);
// errno_t path_readlink(void* ctx, fd_t fd, const char* path, size_t path_len, char* buf, size_t buf_len, size_t* bufused);
// errno_t path_remove_directory(void* ctx, fd_t fd, const char* path, size_t path_len);
// errno_t path_rename(void* ctx, fd_t old_fd, const char* old_path, size_t old_path_len, fd_t new_fd, const char* new_path, size_t new_path_len);
// errno_t path_symlink(void* ctx, const char* old_path, size_t old_path_len, fd_t fd, const char* new_path, size_t new_path_len);
// errno_t path_unlink_file(void* ctx, fd_t fd, const char* path, size_t path_len);
// errno_t poll_oneoff(void* ctx, const subscription_t* in, event_t* out, size_t nsubscriptions, size_t* nevents);
// errno_t proc_raise(void* ctx, signal_t sig);
// errno_t random_get(void* ctx, void* buf, size_t buf_len);
// errno_t sched_yield(t* uvwasi);
// errno_t sock_accept(void* ctx, fd_t sock, flags_t fdflags, fd* fd);
// errno_t sock_recv(void* ctx, fd_t sock, const iovec_t* ri_data, size_t ri_data_len, riflags_t ri_flags, size_t* ro_datalen, roflags_t* ro_flags);
// errno_t sock_send(void* ctx, fd_t sock, const ciovec_t* si_data, size_t si_data_len, siflags_t si_flags, size_t* so_datalen);
// errno_t sock_shutdown(void* ctx, fd_t sock, sdflags_t how);
// clang-format on
// Success
#define WASI_SUCCESS 0
// Bad file descriptor.
#define WASI_BADF_ERROR 8
// Invalid argument
#define WASI_INVAL_ERROR 28
// Operation not permitted.
#define WASI_PERM_ERROR 63
// Syscall not implemented
#define WASI_NOSYS_ERROR 53
#define WASI_RET_ERR_ON_FAIL(exp) \
if (!(exp)) { \
return WASI_INVAL_ERROR; \
}
/////////////////////////////////////////////////////////////
// Clock operations
/////////////////////////////////////////////////////////////
#if defined(_WIN32)
typedef struct
{
LARGE_INTEGER counts_per_sec; /* conversion factor */
} wasi_win_clock_info_t;
static wasi_win_clock_info_t g_wasi_win_clock_info;
static int g_os_data_initialized = 0;
static bool os_clock_init()
{
// From here:
// https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows/38212960#38212960
if (QueryPerformanceFrequency(&g_wasi_win_clock_info.counts_per_sec) == 0) {
return false;
}
g_os_data_initialized = 1;
return true;
}
static bool os_clock_init_instance(void** clock_data_pointer)
{
if (!g_os_data_initialized) {
os_clock_init();
}
wasi_win_clock_info_t* alloc =
(wasi_win_clock_info_t*)malloc(sizeof(wasi_win_clock_info_t));
if (!alloc) {
return false;
}
memcpy(alloc, &g_wasi_win_clock_info, sizeof(wasi_win_clock_info_t));
*clock_data_pointer = alloc;
return true;
}
static void os_clock_cleanup_instance(void** clock_data_pointer)
{
if (*clock_data_pointer == 0) {
free(*clock_data_pointer);
*clock_data_pointer = 0;
}
}
static int os_clock_gettime(void* clock_data,
int clock_id,
struct timespec* out_struct)
{
wasi_win_clock_info_t* alloc = (wasi_win_clock_info_t*)clock_data;
LARGE_INTEGER count;
(void)clock_id;
if (alloc->counts_per_sec.QuadPart <= 0 ||
QueryPerformanceCounter(&count) == 0) {
return -1;
}
# define BILLION 1000000000LL
out_struct->tv_sec = count.QuadPart / alloc->counts_per_sec.QuadPart;
out_struct->tv_nsec =
((count.QuadPart % alloc->counts_per_sec.QuadPart) * BILLION) /
alloc->counts_per_sec.QuadPart;
# undef BILLION
return 0;
}
static int os_clock_getres(void* clock_data,
int clock_id,
struct timespec* out_struct)
{
(void)clock_id;
out_struct->tv_sec = 0;
out_struct->tv_nsec = 1000;
return 0;
}
#elif defined(__APPLE__) && defined(__MACH__)
typedef struct
{
mach_timebase_info_data_t timebase; /* numer = 0, denom = 0 */
struct timespec inittime; /* nanoseconds since 1-Jan-1970 to init() */
uint64_t initclock; /* ticks since boot to init() */
} wasi_mac_clock_info_t;
static wasi_mac_clock_info_t g_wasi_mac_clock_info;
static int g_os_data_initialized = 0;
static bool os_clock_init()
{
// From here:
// https://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x/21352348#21352348
if (mach_timebase_info(&g_wasi_mac_clock_info.timebase) != 0) {
return false;
}
// microseconds since 1 Jan 1970
struct timeval micro;
if (gettimeofday(&micro, NULL) != 0) {
return false;
}
g_wasi_mac_clock_info.initclock = mach_absolute_time();
g_wasi_mac_clock_info.inittime.tv_sec = micro.tv_sec;
g_wasi_mac_clock_info.inittime.tv_nsec = micro.tv_usec * 1000;
g_os_data_initialized = 1;
return true;
}
static bool os_clock_init_instance(void** clock_data_pointer)
{
if (!g_os_data_initialized) {
os_clock_init();
}
wasi_mac_clock_info_t* alloc =
(wasi_mac_clock_info_t*)malloc(sizeof(wasi_mac_clock_info_t));
if (!alloc) {
return false;
}
memcpy(alloc, &g_wasi_mac_clock_info, sizeof(wasi_mac_clock_info_t));
*clock_data_pointer = alloc;
return true;
}
static void os_clock_cleanup_instance(void** clock_data_pointer)
{
if (*clock_data_pointer == 0) {
free(*clock_data_pointer);
*clock_data_pointer = 0;
}
}
static int os_clock_gettime(void* clock_data,
int clock_id,
struct timespec* out_struct)
{
int ret = 0;
wasi_mac_clock_info_t* alloc = (wasi_mac_clock_info_t*)clock_data;
// From here:
// https://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x/21352348#21352348
(void)clock_id;
// ticks since init
uint64_t clock = mach_absolute_time() - alloc->initclock;
// nanoseconds since init
uint64_t nano = clock * (uint64_t)(alloc->timebase.numer) /
(uint64_t)(alloc->timebase.denom);
*out_struct = alloc->inittime;
# define BILLION 1000000000L
out_struct->tv_sec += nano / BILLION;
out_struct->tv_nsec += nano % BILLION;
// normalize
out_struct->tv_sec += out_struct->tv_nsec / BILLION;
out_struct->tv_nsec = out_struct->tv_nsec % BILLION;
# undef BILLION
return ret;
}
static int os_clock_getres(void* clock_data,
int clock_id,
struct timespec* out_struct)
{
int ret = 0;
(void)clock_id;
out_struct->tv_sec = 0;
out_struct->tv_nsec = 1;
return ret;
}
#else
static bool os_clock_init()
{
return true;
}
static bool os_clock_init_instance(void** clock_data_pointer)
{
(void)clock_data_pointer;
return true;
}
static void os_clock_cleanup_instance(void** clock_data_pointer)
{
(void)clock_data_pointer;
}
static int os_clock_gettime(void* clock_data,
int clock_id,
struct timespec* out_struct)
{
(void)clock_data;
int ret = clock_gettime(clock_id, out_struct);
return ret;
}
static int os_clock_getres(void* clock_data,
int clock_id,
struct timespec* out_struct)
{
(void)clock_data;
int ret = clock_getres(clock_id, out_struct);
return ret;
}
#endif
#define WASM_CLOCK_REALTIME 0
#define WASM_CLOCK_MONOTONIC 1
#define WASM_CLOCK_PROCESS_CPUTIME 2
#define WASM_CLOCK_THREAD_CPUTIME_ID 3
static int check_clock(u32 clock_id)
{
return clock_id == WASM_CLOCK_REALTIME || clock_id == WASM_CLOCK_MONOTONIC ||
clock_id == WASM_CLOCK_PROCESS_CPUTIME ||
clock_id == WASM_CLOCK_THREAD_CPUTIME_ID;
}
// out is a pointer to a u64 timestamp in nanoseconds
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-timestamp-u64
u32 w2c_wasi__snapshot__preview1_clock_time_get(
w2c_wasi__snapshot__preview1* wasi_data,
u32 clock_id,
u64 precision,
u32 out)
{
if (!check_clock(clock_id)) {
return WASI_INVAL_ERROR;
}
struct timespec out_struct;
int ret = os_clock_gettime(wasi_data->clock_data, clock_id, &out_struct);
u64 result =
((u64)out_struct.tv_sec) * 1000 * 1000 * 1000 + ((u64)out_struct.tv_nsec);
wasm_i64_store(wasi_data->instance_memory, out, result);
return ret;
}
u32 w2c_wasi__snapshot__preview1_clock_res_get(
w2c_wasi__snapshot__preview1* wasi_data,
u32 clock_id,
u32 out)
{
if (!check_clock(clock_id)) {
return WASI_INVAL_ERROR;
}
struct timespec out_struct;
int ret = os_clock_getres(wasi_data->clock_data, clock_id, &out_struct);
u64 result =
((u64)out_struct.tv_sec) * 1000 * 1000 * 1000 + ((u64)out_struct.tv_nsec);
wasm_i64_store(wasi_data->instance_memory, out, result);
return ret;
}
/////////////////////////////////////////////////////////////
////////// File operations
/////////////////////////////////////////////////////////////
// Only allow stdin (0), stdout (1), stderr(2)
#define WASM_STDIN 0
#define WASM_STDOUT 1
#define WASM_STDERR 2
u32 w2c_wasi__snapshot__preview1_fd_prestat_get(
w2c_wasi__snapshot__preview1* wasi_data,
u32 fd,
u32 prestat)
{
if (fd == WASM_STDIN || fd == WASM_STDOUT || fd == WASM_STDERR) {
return WASI_PERM_ERROR;
}
return WASI_BADF_ERROR;
}
u32 w2c_wasi__snapshot__preview1_fd_write(
w2c_wasi__snapshot__preview1* wasi_data,
u32 fd,
u32 iov,
u32 iovcnt,
u32 pnum)
{
if (fd != WASM_STDOUT && fd != WASM_STDERR) {
return WASI_BADF_ERROR;
}
u32 num = 0;
for (u32 i = 0; i < iovcnt; i++) {
u32 ptr = wasm_i32_load(wasi_data->instance_memory, iov + i * 8);
u32 len = wasm_i32_load(wasi_data->instance_memory, iov + i * 8 + 4);
WASI_MEMCHECK_SIZE(wasi_data->instance_memory, ptr, len);
size_t result = fwrite(WASI_MEMACCESS(wasi_data->instance_memory, ptr),
1 /* size */,
len /* n */,
fd == WASM_STDOUT ? stdout : stderr);
// Guaranteed by fwrite
assert(result <= len);
WASI_RET_ERR_ON_FAIL(safe_add_u32(&num, num, (u32)result));
if (((u32)result) != len) {
wasm_i32_store(wasi_data->instance_memory, pnum, num);
return WASI_PERM_ERROR;
}
}
wasm_i32_store(wasi_data->instance_memory, pnum, num);
return WASI_SUCCESS;
}
u32 w2c_wasi__snapshot__preview1_fd_read(
w2c_wasi__snapshot__preview1* wasi_data,
u32 fd,
u32 iov,
u32 iovcnt,
u32 pnum)
{
if (fd != WASM_STDIN) {
return WASI_BADF_ERROR;
}
u32 num = 0;
for (u32 i = 0; i < iovcnt; i++) {
u32 ptr = wasm_i32_load(wasi_data->instance_memory, iov + i * 8);
u32 len = wasm_i32_load(wasi_data->instance_memory, iov + i * 8 + 4);
WASI_MEMCHECK_SIZE(wasi_data->instance_memory, ptr, len);
size_t result = fread(WASI_MEMACCESS(wasi_data->instance_memory, ptr),
1 /* size */,
len /* n */,
stdin);
// Guaranteed by fwrite
assert(result <= len);
WASI_RET_ERR_ON_FAIL(safe_add_u32(&num, num, (u32)result));
if (((u32)result) != len) {
break; // nothing more to read
}
}
wasm_i32_store(wasi_data->instance_memory, pnum, num);
return WASI_SUCCESS;
}
/////////////////////////////////////////////////////////////
// App environment operations
/////////////////////////////////////////////////////////////
#define ARGV_AND_ENV_LIMIT 1000
static u32 strings_sizes_get(wasm_rt_memory_t* instance_memory,
const char* name,
u32 p_str_count,
u32 p_str_buff_size,
u32 string_count,
const char** strings)
{
u32 chosen_count = string_count;
if (chosen_count > ARGV_AND_ENV_LIMIT) {
chosen_count = ARGV_AND_ENV_LIMIT;
printf("Truncated %s args to %d\n", name, ARGV_AND_ENV_LIMIT);
}
u32 curr_buf_size = 0;
for (u32 i = 0; i < chosen_count; i++) {
size_t original_len = strlen(strings[i]);
// len has to be at most u32 - 1
WASI_RET_ERR_ON_FAIL(original_len < (size_t)UINT32_MAX);
u32 len = (u32)original_len;
u32 len_plus_nullchar = len + 1;
WASI_RET_ERR_ON_FAIL(
safe_add_u32(&curr_buf_size, curr_buf_size, len_plus_nullchar));
}
wasm_i32_store(instance_memory, p_str_count, chosen_count);
wasm_i32_store(instance_memory, p_str_buff_size, curr_buf_size);
return WASI_SUCCESS;
}
static u32 strings_get(wasm_rt_memory_t* instance_memory,
const char* name,
u32 p_str_arr,
u32 p_str_buf,
u32 string_count,
const char** strings)
{
u32 chosen_count = string_count;
if (chosen_count > ARGV_AND_ENV_LIMIT) {
chosen_count = ARGV_AND_ENV_LIMIT;
// Warning is already printed in get_size
}
u32 curr_buf_loc = 0;
for (u32 i = 0; i < chosen_count; i++) {
// Implement: p_str_arr[i] = p_str_buf[curr_buf_loc]
u32 target_argv_i_ref;
WASI_RET_ERR_ON_FAIL(safe_add_u32(&target_argv_i_ref, p_str_arr, i * 4));
u32 target_buf_curr_ref;
WASI_RET_ERR_ON_FAIL(
safe_add_u32(&target_buf_curr_ref, p_str_buf, curr_buf_loc));
wasm_i32_store(instance_memory, target_argv_i_ref, target_buf_curr_ref);
// Implement: strcpy(p_str_buf[curr_buf_loc], strings[i]);
size_t original_len = strlen(strings[i]);
// len has to be at most u32 - 1
WASI_RET_ERR_ON_FAIL(original_len < (size_t)UINT32_MAX);
u32 len = (u32)original_len;
u32 len_plus_nullchar = len + 1;
WASI_CHECK_COPY(
instance_memory, target_buf_curr_ref, len_plus_nullchar, strings[i]);
// Implement: curr_buf_loc += strlen(p_str_buf[curr_buf_loc])
WASI_RET_ERR_ON_FAIL(
safe_add_u32(&curr_buf_loc, curr_buf_loc, len_plus_nullchar));
}
return WASI_SUCCESS;
}
u32 w2c_wasi__snapshot__preview1_args_sizes_get(
w2c_wasi__snapshot__preview1* wasi_data,
u32 p_argc,
u32 p_argv_buf_size)
{
return strings_sizes_get(wasi_data->instance_memory,
"main",
p_argc,
p_argv_buf_size,
wasi_data->main_argc,
wasi_data->main_argv);
}
u32 w2c_wasi__snapshot__preview1_args_get(
w2c_wasi__snapshot__preview1* wasi_data,
u32 p_argv,
u32 p_argv_buf)
{
return strings_get(wasi_data->instance_memory,
"main",
p_argv,
p_argv_buf,
wasi_data->main_argc,
wasi_data->main_argv);
}
u32 w2c_wasi__snapshot__preview1_environ_sizes_get(
w2c_wasi__snapshot__preview1* wasi_data,
u32 p_env_count,
u32 p_env_buf_size)
{
return strings_sizes_get(wasi_data->instance_memory,
"env",
p_env_count,
p_env_buf_size,
wasi_data->env_count,
wasi_data->env);
}
u32 w2c_wasi__snapshot__preview1_environ_get(
w2c_wasi__snapshot__preview1* wasi_data,
u32 p_env,
u32 p_env_buf)
{
return strings_get(wasi_data->instance_memory,
"env",
p_env,
p_env_buf,
wasi_data->env_count,
wasi_data->env);
}
/////////////////////////////////////////////////////////////
// Proc exit operation
/////////////////////////////////////////////////////////////
void w2c_wasi__snapshot__preview1_proc_exit(
w2c_wasi__snapshot__preview1* wasi_data,
u32 x)
{
#ifdef WASM2C_WASI_TRAP_ON_EXIT
TRAP(WASI);
#else
exit(x);
#endif
}
/////////////////////////////////////////////////////////////
////////////// Unsupported WASI APIs
/////////////////////////////////////////////////////////////
#define STUB_IMPORT_IMPL(ret, name, params) \
ret name params { return WASI_NOSYS_ERROR; }
// clang-format off
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_advise,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u64 b, u64 c, u32 d));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_allocate,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u64 b, u64 c));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_close,
(w2c_wasi__snapshot__preview1* wasi_data, u32 fd));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_datasync,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_fdstat_get,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_fdstat_set_flags,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_fdstat_set_rights,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u64 b, u64 c));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_filestat_get,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_filestat_set_size,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u64 b));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_filestat_set_times,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u64 b, u64 c, u32 d));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_pread,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u64 d, u32 e));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_prestat_dir_name,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_pwrite,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u64 d, u32 e));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_readdir,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u64 d, u32 e));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_renumber,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_seek,
(w2c_wasi__snapshot__preview1* wasi_data, u32 fd, u64 offset, u32 whence, u32 new_offset));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_sync,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_fd_tell,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_create_directory,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_filestat_get,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u32 e));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_filestat_set_times,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u64 e, u64 f, u32 g));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_link,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u32 e, u32 f, u32 g));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_open,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u32 e, u64 f, u64 g, u32 h, u32 i));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_readlink,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u32 e, u32 f));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_remove_directory,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_rename,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u32 e, u32 f));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_symlink,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u32 e));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_path_unlink_file,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_poll_oneoff,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_proc_raise,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_random_get,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_sched_yield,
(w2c_wasi__snapshot__preview1* wasi_data));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_sock_accept,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_sock_recv,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u32 e, u32 f));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_sock_send,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b, u32 c, u32 d, u32 e));
STUB_IMPORT_IMPL(u32, w2c_wasi__snapshot__preview1_sock_shutdown,
(w2c_wasi__snapshot__preview1* wasi_data, u32 a, u32 b));
// clang-format on
/////////////////////////////////////////////////////////////
////////// Misc
/////////////////////////////////////////////////////////////
bool minwasi_init()
{
return os_clock_init();
}
bool minwasi_init_instance(w2c_wasi__snapshot__preview1* wasi_data)
{
return os_clock_init_instance(&(wasi_data->clock_data));
}
void minwasi_cleanup_instance(w2c_wasi__snapshot__preview1* wasi_data)
{
os_clock_cleanup_instance(&(wasi_data->clock_data));
}

View File

@ -17,7 +17,7 @@
#ifndef WABT_APPLY_NAMES_H_
#define WABT_APPLY_NAMES_H_
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2017 WebAssembly Community Group participants
* Copyright 2021 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,25 +14,22 @@
* limitations under the License.
*/
#include "src/hash-util.h"
#ifndef WABT_BASE_TYPES_H_
#define WABT_BASE_TYPES_H_
#include "config.h"
#include <cstddef>
#include <cstdint>
namespace wabt {
// Hash combiner from:
// http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine
using Index = uint32_t; // An index into one of the many index spaces.
using Address = uint64_t; // An address or size in linear memory.
using Offset = size_t; // An offset into a host's file or memory buffer.
hash_code HashCombine(hash_code seed, hash_code y) {
#if SIZEOF_SIZE_T == 4
constexpr hash_code magic = 0x9e3779b9;
#elif SIZEOF_SIZE_T == 8
constexpr hash_code magic = 0x9e3779b97f4a7c16;
#else
#error "weird sizeof size_t"
#endif
seed ^= y + magic + (seed << 6) + (seed >> 2);
return seed;
}
constexpr Address kInvalidAddress = ~0;
constexpr Index kInvalidIndex = ~0;
constexpr Offset kInvalidOffset = ~0;
} // namespace wabt
#endif // WABT_BASE_TYPES_H_

View File

@ -17,8 +17,8 @@
#ifndef WABT_BINARY_READER_IR_H_
#define WABT_BINARY_READER_IR_H_
#include "src/common.h"
#include "src/error.h"
#include "wabt/common.h"
#include "wabt/error.h"
namespace wabt {

View File

@ -17,7 +17,7 @@
#ifndef WABT_BINARY_READER_LOGGING_H_
#define WABT_BINARY_READER_LOGGING_H_
#include "src/binary-reader.h"
#include "wabt/binary-reader.h"
namespace wabt {
@ -39,7 +39,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result BeginCustomSection(Index section_index,
Offset size,
string_view section_name) override;
std::string_view section_name) override;
Result EndCustomSection() override;
Result BeginTypeSection(Offset size) override;
@ -57,33 +57,33 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnImportCount(Index count) override;
Result OnImport(Index index,
ExternalKind kind,
string_view module_name,
string_view field_name) override;
std::string_view module_name,
std::string_view field_name) override;
Result OnImportFunc(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index func_index,
Index sig_index) override;
Result OnImportTable(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index table_index,
Type elem_type,
const Limits* elem_limits) override;
Result OnImportMemory(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index memory_index,
const Limits* page_limits) override;
Result OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index global_index,
Type type,
bool mutable_) override;
Result OnImportTag(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index tag_index,
Index sig_index) override;
Result EndImportSection() override;
@ -118,7 +118,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnExport(Index index,
ExternalKind kind,
Index item_index,
string_view name) override;
std::string_view name) override;
Result EndExportSection() override;
Result BeginStartSection(Offset size) override;
@ -140,6 +140,10 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnOpcodeUint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3) override;
Result OnOpcodeUint32Uint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3,
uint32_t value4) override;
Result OnOpcodeUint64(uint64_t value) override;
Result OnOpcodeF32(uint32_t value) override;
Result OnOpcodeF64(uint64_t value) override;
@ -147,15 +151,19 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnOpcodeBlockSig(Type sig_type) override;
Result OnOpcodeType(Type type) override;
Result OnAtomicLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicRmwExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicRmwCmpxchgExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnBinaryExpr(Opcode opcode) override;
@ -176,7 +184,6 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnDropExpr() override;
Result OnElseExpr() override;
Result OnEndExpr() override;
Result OnEndFunc() override;
Result OnF32ConstExpr(uint32_t value_bits) override;
Result OnF64ConstExpr(uint64_t value_bits) override;
Result OnV128ConstExpr(v128 value_bits) override;
@ -186,18 +193,19 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnI64ConstExpr(uint64_t value) override;
Result OnIfExpr(Type sig_type) override;
Result OnLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnLocalGetExpr(Index local_index) override;
Result OnLocalSetExpr(Index local_index) override;
Result OnLocalTeeExpr(Index local_index) override;
Result OnLoopExpr(Type sig_type) override;
Result OnMemoryCopyExpr() override;
Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override;
Result OnDataDropExpr(Index segment_index) override;
Result OnMemoryFillExpr() override;
Result OnMemoryGrowExpr() override;
Result OnMemoryInitExpr(Index segment_index) override;
Result OnMemorySizeExpr() override;
Result OnMemoryFillExpr(Index memidx) override;
Result OnMemoryGrowExpr(Index memidx) override;
Result OnMemoryInitExpr(Index segment_index, Index memidx) override;
Result OnMemorySizeExpr(Index memidx) override;
Result OnTableCopyExpr(Index dst_index, Index src_index) override;
Result OnElemDropExpr(Index segment_index) override;
Result OnTableInitExpr(Index segment_index, Index table_index) override;
@ -216,6 +224,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnReturnExpr() override;
Result OnSelectExpr(Index result_count, Type* result_types) override;
Result OnStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnThrowExpr(Index tag_index) override;
@ -224,28 +233,34 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnTernaryExpr(Opcode opcode) override;
Result OnUnreachableExpr() override;
Result OnAtomicWaitExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicFenceExpr(uint32_t consistency_model) override;
Result OnAtomicNotifyExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result EndFunctionBody(Index index) override;
Result EndCodeSection() override;
Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override;
Result OnSimdLoadLaneExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset,
uint64_t value) override;
Result OnSimdStoreLaneExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset,
uint64_t value) override;
Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) override;
Result OnLoadSplatExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnLoadZeroExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
@ -285,13 +300,13 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnModuleNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override;
Result OnModuleName(string_view name) override;
Result OnModuleName(std::string_view name) override;
Result OnFunctionNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override;
Result OnFunctionNamesCount(Index num_functions) override;
Result OnFunctionName(Index function_index,
string_view function_name) override;
std::string_view function_name) override;
Result OnLocalNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override;
@ -299,13 +314,13 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnLocalNameLocalCount(Index function_index, Index num_locals) override;
Result OnLocalName(Index function_index,
Index local_index,
string_view local_name) override;
std::string_view local_name) override;
Result OnNameSubsection(Index index,
NameSectionSubsection subsection_type,
Offset subsection_size) override;
Result OnNameEntry(NameSectionSubsection type,
Index index,
string_view name) override;
std::string_view name) override;
Result OnNameCount(Index num_names) override;
Result EndNamesSection() override;
@ -323,45 +338,58 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
uint32_t table_size,
uint32_t table_align) override;
Result OnDylinkNeededCount(Index count) override;
Result OnDylinkNeeded(string_view needed) override;
Result OnDylinkNeeded(std::string_view needed) override;
Result OnDylinkImportCount(Index count) override;
Result OnDylinkExportCount(Index count) override;
Result OnDylinkImport(std::string_view module,
std::string_view name,
uint32_t flags) override;
Result OnDylinkExport(std::string_view name, uint32_t flags) override;
Result EndDylinkSection() override;
Result BeginTargetFeaturesSection(Offset size) override;
Result OnFeatureCount(Index count) override;
Result OnFeature(uint8_t prefix, std::string_view name) override;
Result EndTargetFeaturesSection() override;
Result BeginLinkingSection(Offset size) override;
Result OnSymbolCount(Index count) override;
Result OnDataSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index segment,
uint32_t offset,
uint32_t size) override;
Result OnFunctionSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index func_index) override;
Result OnGlobalSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index global_index) override;
Result OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) override;
Result OnTagSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index tag_index) override;
Result OnTableSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index tag_index) override;
Result OnSegmentInfoCount(Index count) override;
Result OnSegmentInfo(Index index,
string_view name,
std::string_view name,
Address alignment,
uint32_t flags) override;
Result OnInitFunctionCount(Index count) override;
Result OnInitFunction(uint32_t priority, Index function_index) override;
Result OnComdatCount(Index count) override;
Result OnComdatBegin(string_view name, uint32_t flags, Index count) override;
Result OnComdatBegin(std::string_view name,
uint32_t flags,
Index count) override;
Result OnComdatEntry(ComdatType kind, Index index) override;
Result EndLinkingSection() override;
@ -370,14 +398,12 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnTagType(Index index, Index sig_index) override;
Result EndTagSection() override;
Result OnInitExprF32ConstExpr(Index index, uint32_t value) override;
Result OnInitExprF64ConstExpr(Index index, uint64_t value) override;
Result OnInitExprV128ConstExpr(Index index, v128 value) override;
Result OnInitExprGlobalGetExpr(Index index, Index global_index) override;
Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
Result OnInitExprRefNull(Index index, Type type) override;
Result OnInitExprRefFunc(Index index, Index func_index) override;
/* Code Metadata sections */
Result BeginCodeMetadataSection(std::string_view name, Offset size) override;
Result OnCodeMetadataFuncCount(Index count) override;
Result OnCodeMetadataCount(Index function_index, Index count) override;
Result OnCodeMetadata(Offset offset, const void* data, Address size) override;
Result EndCodeMetadataSection() override;
private:
void Indent();

View File

@ -17,7 +17,7 @@
#ifndef WABT_BINARY_READER_NOP_H_
#define WABT_BINARY_READER_NOP_H_
#include "src/binary-reader.h"
#include "wabt/binary-reader.h"
namespace wabt {
@ -38,7 +38,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
/* Custom section */
Result BeginCustomSection(Index section_index,
Offset size,
string_view section_name) override {
std::string_view section_name) override {
return Result::Ok;
}
Result EndCustomSection() override { return Result::Ok; }
@ -58,9 +58,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
TypeMut* fields) override {
return Result::Ok;
}
Result OnArrayType(Index index, TypeMut field) override {
return Result::Ok;
}
Result OnArrayType(Index index, TypeMut field) override { return Result::Ok; }
Result EndTypeSection() override { return Result::Ok; }
/* Import section */
@ -68,43 +66,43 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnImportCount(Index count) override { return Result::Ok; }
Result OnImport(Index index,
ExternalKind kind,
string_view module_name,
string_view field_name) override {
std::string_view module_name,
std::string_view field_name) override {
return Result::Ok;
}
Result OnImportFunc(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index func_index,
Index sig_index) override {
return Result::Ok;
}
Result OnImportTable(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index table_index,
Type elem_type,
const Limits* elem_limits) override {
return Result::Ok;
}
Result OnImportMemory(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index memory_index,
const Limits* page_limits) override {
return Result::Ok;
}
Result OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index global_index,
Type type,
bool mutable_) override {
return Result::Ok;
}
Result OnImportTag(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index tag_index,
Index sig_index) override {
return Result::Ok;
@ -154,7 +152,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnExport(Index index,
ExternalKind kind,
Index item_index,
string_view name) override {
std::string_view name) override {
return Result::Ok;
}
Result EndExportSection() override { return Result::Ok; }
@ -192,6 +190,12 @@ class BinaryReaderNop : public BinaryReaderDelegate {
uint32_t value3) override {
return Result::Ok;
}
Result OnOpcodeUint32Uint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3,
uint32_t value4) override {
return Result::Ok;
}
Result OnOpcodeUint64(uint64_t value) override { return Result::Ok; }
Result OnOpcodeF32(uint32_t value) override { return Result::Ok; }
Result OnOpcodeF64(uint64_t value) override { return Result::Ok; }
@ -199,32 +203,34 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnOpcodeBlockSig(Type sig_type) override { return Result::Ok; }
Result OnOpcodeType(Type type) override { return Result::Ok; }
Result OnAtomicLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnAtomicStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnAtomicRmwExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnAtomicRmwCmpxchgExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnAtomicWaitExpr(Opcode, Address, Address) override {
Result OnAtomicWaitExpr(Opcode, Index, Address, Address) override {
return Result::Ok;
}
Result OnAtomicFenceExpr(uint32_t) override {
return Result::Ok;
}
Result OnAtomicNotifyExpr(Opcode, Address, Address) override {
Result OnAtomicFenceExpr(uint32_t) override { return Result::Ok; }
Result OnAtomicNotifyExpr(Opcode, Index, Address, Address) override {
return Result::Ok;
}
Result OnBinaryExpr(Opcode opcode) override { return Result::Ok; }
@ -237,7 +243,9 @@ class BinaryReaderNop : public BinaryReaderDelegate {
return Result::Ok;
}
Result OnCallExpr(Index func_index) override { return Result::Ok; }
Result OnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; }
Result OnCallIndirectExpr(Index sig_index, Index table_index) override {
return Result::Ok;
}
Result OnCallRefExpr() override { return Result::Ok; }
Result OnCatchExpr(Index tag_index) override { return Result::Ok; }
Result OnCatchAllExpr() override { return Result::Ok; }
@ -247,7 +255,6 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnDropExpr() override { return Result::Ok; }
Result OnElseExpr() override { return Result::Ok; }
Result OnEndExpr() override { return Result::Ok; }
Result OnEndFunc() override { return Result::Ok; }
Result OnF32ConstExpr(uint32_t value_bits) override { return Result::Ok; }
Result OnF64ConstExpr(uint64_t value_bits) override { return Result::Ok; }
Result OnV128ConstExpr(v128 value_bits) override { return Result::Ok; }
@ -257,6 +264,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnI64ConstExpr(uint64_t value) override { return Result::Ok; }
Result OnIfExpr(Type sig_type) override { return Result::Ok; }
Result OnLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override {
return Result::Ok;
@ -265,12 +273,16 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnLocalSetExpr(Index local_index) override { return Result::Ok; }
Result OnLocalTeeExpr(Index local_index) override { return Result::Ok; }
Result OnLoopExpr(Type sig_type) override { return Result::Ok; }
Result OnMemoryCopyExpr() override { return Result::Ok; }
Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override {
return Result::Ok;
}
Result OnDataDropExpr(Index segment_index) override { return Result::Ok; }
Result OnMemoryFillExpr() override { return Result::Ok; }
Result OnMemoryGrowExpr() override { return Result::Ok; }
Result OnMemoryInitExpr(Index segment_index) override { return Result::Ok; }
Result OnMemorySizeExpr() override { return Result::Ok; }
Result OnMemoryFillExpr(Index memidx) override { return Result::Ok; }
Result OnMemoryGrowExpr(Index memidx) override { return Result::Ok; }
Result OnMemoryInitExpr(Index segment_index, Index memidx) override {
return Result::Ok;
}
Result OnMemorySizeExpr(Index memidx) override { return Result::Ok; }
Result OnTableCopyExpr(Index dst_index, Index src_index) override {
return Result::Ok;
}
@ -289,12 +301,15 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnNopExpr() override { return Result::Ok; }
Result OnRethrowExpr(Index depth) override { return Result::Ok; }
Result OnReturnCallExpr(Index sig_index) override { return Result::Ok; }
Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; }
Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override {
return Result::Ok;
}
Result OnReturnExpr() override { return Result::Ok; }
Result OnSelectExpr(Index result_count, Type* result_types) override {
return Result::Ok;
}
Result OnStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override {
return Result::Ok;
@ -310,12 +325,14 @@ class BinaryReaderNop : public BinaryReaderDelegate {
return Result::Ok;
}
Result OnSimdLoadLaneExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset,
uint64_t value) override {
return Result::Ok;
}
Result OnSimdStoreLaneExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset,
uint64_t value) override {
@ -325,11 +342,13 @@ class BinaryReaderNop : public BinaryReaderDelegate {
return Result::Ok;
}
Result OnLoadSplatExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnLoadZeroExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override {
return Result::Ok;
@ -392,7 +411,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Offset subsection_size) override {
return Result::Ok;
}
Result OnModuleName(string_view name) override { return Result::Ok; }
Result OnModuleName(std::string_view name) override { return Result::Ok; }
Result OnFunctionNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override {
@ -402,7 +421,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
return Result::Ok;
}
Result OnFunctionName(Index function_index,
string_view function_name) override {
std::string_view function_name) override {
return Result::Ok;
}
Result OnLocalNameSubsection(Index index,
@ -419,7 +438,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
}
Result OnLocalName(Index function_index,
Index local_index,
string_view local_name) override {
std::string_view local_name) override {
return Result::Ok;
}
Result EndNamesSection() override { return Result::Ok; }
@ -432,7 +451,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnNameCount(Index num_names) override { return Result::Ok; }
Result OnNameEntry(NameSectionSubsection type,
Index index,
string_view name) override {
std::string_view name) override {
return Result::Ok;
}
@ -455,6 +474,21 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnTagType(Index index, Index sig_index) override { return Result::Ok; }
Result EndTagSection() override { return Result::Ok; }
/* Code Metadata sections */
Result BeginCodeMetadataSection(std::string_view name, Offset size) override {
return Result::Ok;
}
Result OnCodeMetadataFuncCount(Index count) override { return Result::Ok; }
Result OnCodeMetadataCount(Index function_index, Index count) override {
return Result::Ok;
}
Result OnCodeMetadata(Offset offset,
const void* data,
Address size) override {
return Result::Ok;
}
Result EndCodeMetadataSection() override { return Result::Ok; }
/* Dylink section */
Result BeginDylinkSection(Offset size) override { return Result::Ok; }
Result OnDylinkInfo(uint32_t mem_size,
@ -464,15 +498,35 @@ class BinaryReaderNop : public BinaryReaderDelegate {
return Result::Ok;
}
Result OnDylinkNeededCount(Index count) override { return Result::Ok; }
Result OnDylinkNeeded(string_view so_name) override { return Result::Ok; }
Result OnDylinkNeeded(std::string_view so_name) override {
return Result::Ok;
}
Result OnDylinkImportCount(Index count) override { return Result::Ok; }
Result OnDylinkExportCount(Index count) override { return Result::Ok; }
Result OnDylinkImport(std::string_view module,
std::string_view name,
uint32_t flags) override {
return Result::Ok;
}
Result OnDylinkExport(std::string_view name, uint32_t flags) override {
return Result::Ok;
}
Result EndDylinkSection() override { return Result::Ok; }
/* target_features section */
Result BeginTargetFeaturesSection(Offset size) override { return Result::Ok; }
Result OnFeatureCount(Index count) override { return Result::Ok; }
Result OnFeature(uint8_t prefix, std::string_view name) override {
return Result::Ok;
}
Result EndTargetFeaturesSection() override { return Result::Ok; }
/* Linking section */
Result BeginLinkingSection(Offset size) override { return Result::Ok; }
Result OnSymbolCount(Index count) override { return Result::Ok; }
Result OnDataSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index segment,
uint32_t offset,
uint32_t size) override {
@ -480,13 +534,13 @@ class BinaryReaderNop : public BinaryReaderDelegate {
}
Result OnFunctionSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index func_index) override {
return Result::Ok;
}
Result OnGlobalSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index global_index) override {
return Result::Ok;
}
@ -497,19 +551,19 @@ class BinaryReaderNop : public BinaryReaderDelegate {
}
Result OnTagSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index tag_index) override {
return Result::Ok;
}
Result OnTableSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index table_index) override {
return Result::Ok;
}
Result OnSegmentInfoCount(Index count) override { return Result::Ok; }
Result OnSegmentInfo(Index index,
string_view name,
std::string_view name,
Address alignment,
uint32_t flags) override {
return Result::Ok;
@ -519,40 +573,15 @@ class BinaryReaderNop : public BinaryReaderDelegate {
return Result::Ok;
}
Result OnComdatCount(Index count) override { return Result::Ok; }
Result OnComdatBegin(string_view name, uint32_t flags, Index count) override {
Result OnComdatBegin(std::string_view name,
uint32_t flags,
Index count) override {
return Result::Ok;
}
Result OnComdatEntry(ComdatType kind, Index index) override {
return Result::Ok;
}
Result EndLinkingSection() override { return Result::Ok; }
/* InitExpr - used by elem, data and global sections; these functions are
* only called between calls to Begin*InitExpr and End*InitExpr */
Result OnInitExprF32ConstExpr(Index index, uint32_t value) override {
return Result::Ok;
}
Result OnInitExprF64ConstExpr(Index index, uint64_t value) override {
return Result::Ok;
}
Result OnInitExprV128ConstExpr(Index index, v128 value) override {
return Result::Ok;
}
Result OnInitExprGlobalGetExpr(Index index, Index global_index) override {
return Result::Ok;
}
Result OnInitExprI32ConstExpr(Index index, uint32_t value) override {
return Result::Ok;
}
Result OnInitExprI64ConstExpr(Index index, uint64_t value) override {
return Result::Ok;
}
Result OnInitExprRefNull(Index index, Type type) override {
return Result::Ok;
}
Result OnInitExprRefFunc(Index index, Index func_index) override {
return Result::Ok;
}
};
} // namespace wabt

View File

@ -20,9 +20,9 @@
#include <map>
#include <string>
#include "src/common.h"
#include "src/feature.h"
#include "src/stream.h"
#include "wabt/common.h"
#include "wabt/feature.h"
#include "wabt/stream.h"
namespace wabt {
@ -58,24 +58,34 @@ struct ObjdumpSymbol {
};
struct ObjdumpNames {
string_view Get(Index index) const;
void Set(Index index, string_view name);
std::string_view Get(Index index) const;
void Set(Index index, std::string_view name);
std::map<Index, std::string> names;
};
struct ObjdumpLocalNames {
std::string_view Get(Index function_index, Index local_index) const;
void Set(Index function_index, Index local_index, std::string_view name);
std::map<std::pair<Index, Index>, std::string> names;
};
// read_binary_objdump uses this state to store information from previous runs
// and use it to display more useful information.
struct ObjdumpState {
std::vector<Reloc> code_relocations;
std::vector<Reloc> data_relocations;
ObjdumpNames type_names;
ObjdumpNames function_names;
ObjdumpNames global_names;
ObjdumpNames section_names;
ObjdumpNames tag_names;
ObjdumpNames segment_names;
ObjdumpNames table_names;
ObjdumpLocalNames local_names;
std::vector<ObjdumpSymbol> symtab;
std::map<Index, Index> function_param_counts;
};
Result ReadBinaryObjdump(const uint8_t* data,

View File

@ -20,8 +20,8 @@
#include <map>
#include <vector>
#include "src/common.h"
#include "src/opcode.h"
#include "wabt/common.h"
#include "wabt/opcode.h"
namespace wabt {
@ -39,8 +39,11 @@ class OpcodeInfo {
Float32,
Float64,
Uint32Uint32,
Uint32Uint32Uint32,
Uint32Uint32Uint32Uint32,
BlockSig,
BrTable,
V128,
};
explicit OpcodeInfo(Opcode, Kind);
@ -81,7 +84,7 @@ bool operator<=(const OpcodeInfo&, const OpcodeInfo&);
bool operator>(const OpcodeInfo&, const OpcodeInfo&);
bool operator>=(const OpcodeInfo&, const OpcodeInfo&);
typedef std::map<OpcodeInfo, size_t> OpcodeInfoCounts;
using OpcodeInfoCounts = std::map<OpcodeInfo, size_t>;
Result ReadBinaryOpcnt(const void* data,
size_t size,

View File

@ -17,15 +17,15 @@
#ifndef WABT_BINARY_READER_H_
#define WABT_BINARY_READER_H_
#include <stddef.h>
#include <stdint.h>
#include <cstddef>
#include <cstdint>
#include <string_view>
#include "src/binary.h"
#include "src/common.h"
#include "src/error.h"
#include "src/feature.h"
#include "src/opcode.h"
#include "src/string-view.h"
#include "wabt/binary.h"
#include "wabt/common.h"
#include "wabt/error.h"
#include "wabt/feature.h"
#include "wabt/opcode.h"
namespace wabt {
@ -49,6 +49,7 @@ struct ReadBinaryOptions {
bool read_debug_names = false;
bool stop_on_first_error = true;
bool fail_on_custom_section_error = true;
bool skip_function_bodies = false;
};
// TODO: Move somewhere else?
@ -85,7 +86,7 @@ class BinaryReaderDelegate {
/* Custom section */
virtual Result BeginCustomSection(Index section_index,
Offset size,
string_view section_name) = 0;
std::string_view section_name) = 0;
virtual Result EndCustomSection() = 0;
/* Type section */
@ -107,33 +108,33 @@ class BinaryReaderDelegate {
virtual Result OnImportCount(Index count) = 0;
virtual Result OnImport(Index index,
ExternalKind kind,
string_view module_name,
string_view field_name) = 0;
std::string_view module_name,
std::string_view field_name) = 0;
virtual Result OnImportFunc(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index func_index,
Index sig_index) = 0;
virtual Result OnImportTable(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index table_index,
Type elem_type,
const Limits* elem_limits) = 0;
virtual Result OnImportMemory(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index memory_index,
const Limits* page_limits) = 0;
virtual Result OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index global_index,
Type type,
bool mutable_) = 0;
virtual Result OnImportTag(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index tag_index,
Index sig_index) = 0;
virtual Result EndImportSection() = 0;
@ -173,7 +174,7 @@ class BinaryReaderDelegate {
virtual Result OnExport(Index index,
ExternalKind kind,
Index item_index,
string_view name) = 0;
std::string_view name) = 0;
virtual Result EndExportSection() = 0;
/* Start section */
@ -199,6 +200,10 @@ class BinaryReaderDelegate {
virtual Result OnOpcodeUint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3) = 0;
virtual Result OnOpcodeUint32Uint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3,
uint32_t value4) = 0;
virtual Result OnOpcodeUint64(uint64_t value) = 0;
virtual Result OnOpcodeF32(uint32_t value) = 0;
virtual Result OnOpcodeF64(uint64_t value) = 0;
@ -206,22 +211,28 @@ class BinaryReaderDelegate {
virtual Result OnOpcodeBlockSig(Type sig_type) = 0;
virtual Result OnOpcodeType(Type type) = 0;
virtual Result OnAtomicLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicRmwExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicRmwCmpxchgExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicWaitExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicFenceExpr(uint32_t consistency_model) = 0;
virtual Result OnAtomicNotifyExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnBinaryExpr(Opcode opcode) = 0;
@ -242,7 +253,6 @@ class BinaryReaderDelegate {
virtual Result OnDropExpr() = 0;
virtual Result OnElseExpr() = 0;
virtual Result OnEndExpr() = 0;
virtual Result OnEndFunc() = 0;
virtual Result OnF32ConstExpr(uint32_t value_bits) = 0;
virtual Result OnF64ConstExpr(uint64_t value_bits) = 0;
virtual Result OnV128ConstExpr(v128 value_bits) = 0;
@ -252,18 +262,19 @@ class BinaryReaderDelegate {
virtual Result OnI64ConstExpr(uint64_t value) = 0;
virtual Result OnIfExpr(Type sig_type) = 0;
virtual Result OnLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnLocalGetExpr(Index local_index) = 0;
virtual Result OnLocalSetExpr(Index local_index) = 0;
virtual Result OnLocalTeeExpr(Index local_index) = 0;
virtual Result OnLoopExpr(Type sig_type) = 0;
virtual Result OnMemoryCopyExpr() = 0;
virtual Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) = 0;
virtual Result OnDataDropExpr(Index segment_index) = 0;
virtual Result OnMemoryFillExpr() = 0;
virtual Result OnMemoryGrowExpr() = 0;
virtual Result OnMemoryInitExpr(Index segment_index) = 0;
virtual Result OnMemorySizeExpr() = 0;
virtual Result OnMemoryFillExpr(Index memidx) = 0;
virtual Result OnMemoryGrowExpr(Index memidx) = 0;
virtual Result OnMemoryInitExpr(Index segment_index, Index memidx) = 0;
virtual Result OnMemorySizeExpr(Index memidx) = 0;
virtual Result OnTableCopyExpr(Index dst_index, Index src_index) = 0;
virtual Result OnElemDropExpr(Index segment_index) = 0;
virtual Result OnTableInitExpr(Index segment_index, Index table_index) = 0;
@ -283,6 +294,7 @@ class BinaryReaderDelegate {
Index table_index) = 0;
virtual Result OnSelectExpr(Index result_count, Type* result_types) = 0;
virtual Result OnStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnThrowExpr(Index tag_index) = 0;
@ -298,18 +310,22 @@ class BinaryReaderDelegate {
virtual Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) = 0;
virtual Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) = 0;
virtual Result OnSimdLoadLaneExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset,
uint64_t value) = 0;
virtual Result OnSimdStoreLaneExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset,
uint64_t value) = 0;
virtual Result OnLoadSplatExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
virtual Result OnLoadZeroExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) = 0;
@ -354,13 +370,13 @@ class BinaryReaderDelegate {
virtual Result OnModuleNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) = 0;
virtual Result OnModuleName(string_view name) = 0;
virtual Result OnModuleName(std::string_view name) = 0;
virtual Result OnFunctionNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) = 0;
virtual Result OnFunctionNamesCount(Index num_functions) = 0;
virtual Result OnFunctionName(Index function_index,
string_view function_name) = 0;
std::string_view function_name) = 0;
virtual Result OnLocalNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) = 0;
@ -369,20 +385,19 @@ class BinaryReaderDelegate {
Index num_locals) = 0;
virtual Result OnLocalName(Index function_index,
Index local_index,
string_view local_name) = 0;
std::string_view local_name) = 0;
virtual Result OnNameSubsection(Index index,
NameSectionSubsection subsection_type,
Offset subsection_size) = 0;
virtual Result OnNameCount(Index num_names) = 0;
virtual Result OnNameEntry(NameSectionSubsection type,
Index index,
string_view name) = 0;
std::string_view name) = 0;
virtual Result EndNamesSection() = 0;
/* Reloc section */
virtual Result BeginRelocSection(Offset size) = 0;
virtual Result OnRelocCount(Index count,
Index section_index) = 0;
virtual Result OnRelocCount(Index count, Index section_index) = 0;
virtual Result OnReloc(RelocType type,
Offset offset,
Index index,
@ -395,47 +410,59 @@ class BinaryReaderDelegate {
uint32_t mem_align_log2,
uint32_t table_size,
uint32_t table_align_log2) = 0;
virtual Result OnDylinkImportCount(Index count) = 0;
virtual Result OnDylinkExportCount(Index count) = 0;
virtual Result OnDylinkImport(std::string_view module,
std::string_view name,
uint32_t flags) = 0;
virtual Result OnDylinkExport(std::string_view name, uint32_t flags) = 0;
virtual Result OnDylinkNeededCount(Index count) = 0;
virtual Result OnDylinkNeeded(string_view so_name) = 0;
virtual Result OnDylinkNeeded(std::string_view so_name) = 0;
virtual Result EndDylinkSection() = 0;
/* target_features section */
virtual Result BeginTargetFeaturesSection(Offset size) = 0;
virtual Result OnFeatureCount(Index count) = 0;
virtual Result OnFeature(uint8_t prefix, std::string_view name) = 0;
virtual Result EndTargetFeaturesSection() = 0;
/* Linking section */
virtual Result BeginLinkingSection(Offset size) = 0;
virtual Result OnSymbolCount(Index count) = 0;
virtual Result OnDataSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index segment,
uint32_t offset,
uint32_t size) = 0;
virtual Result OnFunctionSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index function_index) = 0;
virtual Result OnGlobalSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index global_index) = 0;
virtual Result OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) = 0;
virtual Result OnTagSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index tag_index) = 0;
virtual Result OnTableSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index table_index) = 0;
virtual Result OnSegmentInfoCount(Index count) = 0;
virtual Result OnSegmentInfo(Index index,
string_view name,
std::string_view name,
Address alignment_log2,
uint32_t flags) = 0;
virtual Result OnInitFunctionCount(Index count) = 0;
virtual Result OnInitFunction(uint32_t priority, Index function_index) = 0;
virtual Result OnComdatCount(Index count) = 0;
virtual Result OnComdatBegin(string_view name,
virtual Result OnComdatBegin(std::string_view name,
uint32_t flags,
Index count) = 0;
virtual Result OnComdatEntry(ComdatType kind, Index index) = 0;
@ -447,16 +474,15 @@ class BinaryReaderDelegate {
virtual Result OnTagType(Index index, Index sig_index) = 0;
virtual Result EndTagSection() = 0;
/* InitExpr - used by elem, data and global sections; these functions are
* only called between calls to Begin*InitExpr and End*InitExpr */
virtual Result OnInitExprF32ConstExpr(Index index, uint32_t value) = 0;
virtual Result OnInitExprF64ConstExpr(Index index, uint64_t value) = 0;
virtual Result OnInitExprV128ConstExpr(Index index, v128 value) = 0;
virtual Result OnInitExprGlobalGetExpr(Index index, Index global_index) = 0;
virtual Result OnInitExprI32ConstExpr(Index index, uint32_t value) = 0;
virtual Result OnInitExprI64ConstExpr(Index index, uint64_t value) = 0;
virtual Result OnInitExprRefNull(Index index, Type type) = 0;
virtual Result OnInitExprRefFunc(Index index, Index func_index) = 0;
/* Code Metadata sections */
virtual Result BeginCodeMetadataSection(std::string_view name,
Offset size) = 0;
virtual Result OnCodeMetadataFuncCount(Index count) = 0;
virtual Result OnCodeMetadataCount(Index function_index, Index count) = 0;
virtual Result OnCodeMetadata(Offset offset,
const void* data,
Address size) = 0;
virtual Result EndCodeMetadataSection() = 0;
const State* state = nullptr;
};

View File

@ -21,36 +21,36 @@
#include <utility>
#include <vector>
#include "src/binary-writer.h"
#include "src/common.h"
#include "src/ir.h"
#include "wabt/binary-writer.h"
#include "wabt/common.h"
#include "wabt/ir.h"
namespace wabt {
struct FilenameMemoryStreamPair {
FilenameMemoryStreamPair(string_view filename,
FilenameMemoryStreamPair(std::string_view filename,
std::unique_ptr<MemoryStream> stream)
: filename(filename), stream(std::move(stream)) {}
std::string filename;
std::unique_ptr<MemoryStream> stream;
};
typedef std::function<Stream*(string_view filename)>
WriteBinarySpecStreamFactory;
using WriteBinarySpecStreamFactory =
std::function<Stream*(std::string_view filename)>;
Result WriteBinarySpecScript(Stream* json_stream,
WriteBinarySpecStreamFactory module_stream_factory,
Script*,
string_view source_filename,
string_view module_filename_noext,
std::string_view source_filename,
std::string_view module_filename_noext,
const WriteBinaryOptions&);
// Convenience function for producing MemoryStream outputs all modules.
Result WriteBinarySpecScript(
Stream* json_stream,
Script*,
string_view source_filename,
string_view module_filename_noext,
std::string_view source_filename,
std::string_view module_filename_noext,
const WriteBinaryOptions&,
std::vector<FilenameMemoryStreamPair>* out_module_streams,
Stream* log_stream = nullptr);

View File

@ -17,10 +17,10 @@
#ifndef WABT_BINARY_WRITER_H_
#define WABT_BINARY_WRITER_H_
#include "src/common.h"
#include "src/feature.h"
#include "src/opcode.h"
#include "src/stream.h"
#include "wabt/common.h"
#include "wabt/feature.h"
#include "wabt/opcode.h"
#include "wabt/stream.h"
namespace wabt {
@ -49,7 +49,7 @@ Result WriteBinaryModule(Stream*, const Module*, const WriteBinaryOptions&);
void WriteType(Stream* stream, Type type, const char* desc = nullptr);
void WriteStr(Stream* stream,
string_view s,
std::string_view s,
const char* desc,
PrintChars print_chars = PrintChars::No);

View File

@ -17,7 +17,7 @@
#ifndef WABT_BINARY_H_
#define WABT_BINARY_H_
#include "src/common.h"
#include "wabt/common.h"
#define WABT_BINARY_MAGIC 0x6d736100
#define WABT_BINARY_VERSION 1
@ -31,8 +31,10 @@
#define WABT_BINARY_SECTION_NAME "name"
#define WABT_BINARY_SECTION_RELOC "reloc"
#define WABT_BINARY_SECTION_LINKING "linking"
#define WABT_BINARY_SECTION_TARGET_FEATURES "target_features"
#define WABT_BINARY_SECTION_DYLINK "dylink"
#define WABT_BINARY_SECTION_DYLINK0 "dylink.0"
#define WABT_BINARY_SECTION_CODE_METADATA "metadata.code."
#define WABT_FOREACH_BINARY_SECTION(V) \
V(Custom, custom, 0) \
@ -63,7 +65,7 @@ enum class BinarySection {
Last = Tag,
};
/* clang-format on */
static const int kBinarySectionCount = WABT_ENUM_COUNT(BinarySection);
constexpr int kBinarySectionCount = WABT_ENUM_COUNT(BinarySection);
enum class BinarySectionOrder {
#define V(Name, name, code) Name,
@ -74,6 +76,8 @@ enum class BinarySectionOrder {
BinarySectionOrder GetSectionOrder(BinarySection);
const char* GetSectionName(BinarySection);
// See
// https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md
enum class NameSectionSubsection {
Module = 0,
Function = 1,
@ -85,7 +89,15 @@ enum class NameSectionSubsection {
Global = 7,
ElemSegment = 8,
DataSegment = 9,
Last = DataSegment,
// tag names are yet part of the extended-name-section proposal (because it
// only deals with naming things that are in the spec already). However, we
// include names for Tags in wabt using this enum value on the basis that tags
// can only exist when exceptions are enabled and that engines should ignore
// unknown name types.
Tag = 10,
First = Module,
Last = Tag,
};
const char* GetNameSectionSubsectionName(NameSectionSubsection subsec);

View File

@ -19,11 +19,11 @@
#include <functional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "src/common.h"
#include "src/string-view.h"
#include "wabt/common.h"
namespace wabt {
@ -42,8 +42,8 @@ struct Binding {
// object through a pointer to std::unordered_multimap.
class BindingHash : public std::unordered_multimap<std::string, Binding> {
public:
typedef std::function<void(const value_type&, const value_type&)>
DuplicateCallback;
using DuplicateCallback =
std::function<void(const value_type&, const value_type&)>;
void FindDuplicates(DuplicateCallback callback) const;
@ -54,12 +54,12 @@ class BindingHash : public std::unordered_multimap<std::string, Binding> {
return iter != end() ? iter->second.index : kInvalidIndex;
}
Index FindIndex(string_view name) const {
return FindIndex(name.to_string());
Index FindIndex(std::string_view name) const {
return FindIndex(std::string(name));
}
private:
typedef std::vector<const value_type*> ValueTypeVector;
using ValueTypeVector = std::vector<const value_type*>;
void CreateDuplicatesVector(ValueTypeVector* out_duplicates) const;
void SortDuplicatesVectorByLocation(ValueTypeVector* duplicates) const;

View File

@ -0,0 +1,56 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* 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 WABT_C_WRITER_H_
#define WABT_C_WRITER_H_
#include <functional>
#include "wabt/common.h"
#include "wabt/ir.h"
namespace wabt {
struct Module;
class Stream;
struct WriteCOptions {
std::string_view module_name;
/*
* name_to_output_file_index takes const iterators to begin and end of a list
* of all functions in the module, number of imported functions, and number of
* .c outputs as argument, returns a vector where vector[i] the index of the
* .c output that funcs_begin + i goes into. Only called when --num-outputs is
* used.
*/
std::function<std::vector<size_t>(
std::vector<Func*>::const_iterator funcs_begin,
std::vector<Func*>::const_iterator funcs_end,
size_t num_imported_functions,
size_t num_outputs)>
name_to_output_file_index;
};
Result WriteC(std::vector<Stream*>&& c_streams,
Stream* h_stream,
Stream* h_impl_stream,
const char* header_name,
const char* header_impl_name,
const Module*,
const WriteCOptions&);
} // namespace wabt
#endif /* WABT_C_WRITER_H_ */

View File

@ -20,7 +20,7 @@
#include <memory>
#include <type_traits>
#include "src/common.h"
#include "wabt/common.h"
// Modeled after LLVM's dynamic casts:
// http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates

View File

@ -29,11 +29,11 @@ namespace wabt {
template <class T, size_t kCapacity>
class CircularArray {
public:
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = size_t;
using difference_type = ptrdiff_t;
CircularArray() {
static_assert(kCapacity && ((kCapacity & (kCapacity - 1)) == 0),
@ -103,7 +103,7 @@ class CircularArray {
}
private:
static const size_type kMask = kCapacity - 1;
static constexpr size_type kMask = kCapacity - 1;
size_t position(size_t index) const { return (front_ + index) & kMask; }

View File

@ -27,54 +27,32 @@
#include <cstring>
#include <memory>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
#include "config.h"
#include "wabt/config.h"
#include "src/make-unique.h"
#include "src/result.h"
#include "src/string-view.h"
#include "src/type.h"
#include "wabt/base-types.h"
#include "wabt/result.h"
#include "wabt/string-format.h"
#include "wabt/type.h"
#define WABT_FATAL(...) fprintf(stderr, __VA_ARGS__), exit(1)
#define WABT_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define WABT_USE(x) static_cast<void>(x)
#define WABT_PAGE_SIZE 0x10000 /* 64k */
#define WABT_MAX_PAGES32 0x10000 /* # of pages that fit in 32-bit address \
space */
#define WABT_MAX_PAGES64 0x1000000000000 /* # of pages that fit in 64-bit \
address space */
// 64k
#define WABT_PAGE_SIZE 0x10000
// # of pages that fit in 32-bit address space
#define WABT_MAX_PAGES32 0x10000
// # of pages that fit in 64-bit address space
#define WABT_MAX_PAGES64 0x1000000000000
#define WABT_BYTES_TO_PAGES(x) ((x) >> 16)
#define WABT_ALIGN_UP_TO_PAGE(x) \
(((x) + WABT_PAGE_SIZE - 1) & ~(WABT_PAGE_SIZE - 1))
#define PRIstringview "%.*s"
#define WABT_PRINTF_STRING_VIEW_ARG(x) \
static_cast<int>((x).length()), (x).data()
#define PRItypecode "%s%#x"
#define WABT_PRINTF_TYPE_CODE(x) \
(static_cast<int32_t>(x) < 0 ? "-" : ""), std::abs(static_cast<int32_t>(x))
#define WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128
#define WABT_SNPRINTF_ALLOCA(buffer, len, format) \
va_list args; \
va_list args_copy; \
va_start(args, format); \
va_copy(args_copy, args); \
char fixed_buf[WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE]; \
char* buffer = fixed_buf; \
size_t len = wabt_vsnprintf(fixed_buf, sizeof(fixed_buf), format, args); \
va_end(args); \
if (len + 1 > sizeof(fixed_buf)) { \
buffer = static_cast<char*>(alloca(len + 1)); \
len = wabt_vsnprintf(buffer, len + 1, format, args_copy); \
} \
va_end(args_copy)
#define WABT_ENUM_COUNT(name) \
(static_cast<int>(name::Last) - static_cast<int>(name::First) + 1)
@ -104,20 +82,22 @@
#define PRIoffset PRIzx
namespace wabt {
inline void MemcpyEndianAware(void* dst,
const void* src,
size_t dsize,
size_t ssize,
size_t doff,
size_t soff,
size_t len) {
#if WABT_BIG_ENDIAN
inline void MemcpyEndianAware(void *dst, const void *src, size_t dsize, size_t ssize, size_t doff, size_t soff, size_t len) {
memcpy(static_cast<char*>(dst) + (dsize) - (len) - (doff),
static_cast<const char*>(src) + (ssize) - (len) - (soff),
(len));
}
memcpy(static_cast<char*>(dst) + (dsize) - (len) - (doff),
static_cast<const char*>(src) + (ssize) - (len) - (soff), (len));
#else
inline void MemcpyEndianAware(void *dst, const void *src, size_t dsize, size_t ssize, size_t doff, size_t soff, size_t len) {
memcpy(static_cast<char*>(dst) + (doff),
static_cast<const char*>(src) + (soff),
(len));
}
memcpy(static_cast<char*>(dst) + (doff),
static_cast<const char*>(src) + (soff), (len));
#endif
}
}
struct v128 {
v128() = default;
@ -158,7 +138,8 @@ struct v128 {
static_assert(sizeof(T) <= sizeof(v), "Invalid cast!");
assert((lane + 1) * sizeof(T) <= sizeof(v));
T result;
wabt::MemcpyEndianAware(&result, v, sizeof(result), sizeof(v), 0, lane * sizeof(T), sizeof(result));
wabt::MemcpyEndianAware(&result, v, sizeof(result), sizeof(v), 0,
lane * sizeof(T), sizeof(result));
return result;
}
@ -166,7 +147,8 @@ struct v128 {
void From(int lane, T data) {
static_assert(sizeof(T) <= sizeof(v), "Invalid cast!");
assert((lane + 1) * sizeof(T) <= sizeof(v));
wabt::MemcpyEndianAware(v, &data, sizeof(v), sizeof(data), lane * sizeof(T), 0, sizeof(data));
wabt::MemcpyEndianAware(v, &data, sizeof(v), sizeof(data), lane * sizeof(T),
0, sizeof(data));
}
uint8_t v[16];
@ -174,14 +156,6 @@ struct v128 {
namespace wabt {
typedef uint32_t Index; // An index into one of the many index spaces.
typedef uint64_t Address; // An address or size in linear memory.
typedef size_t Offset; // An offset into a host's file or memory buffer.
static const Address kInvalidAddress = ~0;
static const Index kInvalidIndex = ~0;
static const Offset kInvalidOffset = ~0;
template <typename Dst, typename Src>
Dst WABT_VECTORCALL Bitcast(Src&& value) {
static_assert(sizeof(Src) == sizeof(Dst), "Bitcast sizes must match.");
@ -208,22 +182,9 @@ void Destruct(T& placement) {
placement.~T();
}
inline std::string WABT_PRINTF_FORMAT(1, 2)
StringPrintf(const char* format, ...) {
va_list args;
va_list args_copy;
va_start(args, format);
va_copy(args_copy, args);
size_t len = wabt_vsnprintf(nullptr, 0, format, args) + 1; // For \0.
std::vector<char> buffer(len);
va_end(args);
wabt_vsnprintf(buffer.data(), len, format, args_copy);
va_end(args_copy);
return std::string(buffer.data(), len - 1);
}
enum class LabelType {
Func,
InitExpr,
Block,
Loop,
If,
@ -234,7 +195,7 @@ enum class LabelType {
First = Func,
Last = Catch,
};
static const int kLabelTypeCount = WABT_ENUM_COUNT(LabelType);
constexpr int kLabelTypeCount = WABT_ENUM_COUNT(LabelType);
struct Location {
enum class Type {
@ -243,14 +204,17 @@ struct Location {
};
Location() : line(0), first_column(0), last_column(0) {}
Location(string_view filename, int line, int first_column, int last_column)
Location(std::string_view filename,
int line,
int first_column,
int last_column)
: filename(filename),
line(line),
first_column(first_column),
last_column(last_column) {}
explicit Location(size_t offset) : offset(offset) {}
string_view filename;
std::string_view filename;
union {
// For text files.
struct {
@ -298,7 +262,7 @@ enum class RelocType {
MemoryAddressSLEB = 4, // e.g. Memory address in i32.const
MemoryAddressI32 = 5, // e.g. Memory address in DATA
TypeIndexLEB = 6, // e.g. Immediate type in call_indirect
GlobalIndexLEB = 7, // e.g. Immediate of get_global inst
GlobalIndexLEB = 7, // e.g. Immediate of global.get inst
FunctionOffsetI32 = 8, // e.g. Code offset in DWARF metadata
SectionOffsetI32 = 9, // e.g. Section offset in DWARF metadata
TagIndexLEB = 10, // Used in throw instructions
@ -318,7 +282,7 @@ enum class RelocType {
First = FuncIndexLEB,
Last = MemoryAddressTLSI32,
};
static const int kRelocTypeCount = WABT_ENUM_COUNT(RelocType);
constexpr int kRelocTypeCount = WABT_ENUM_COUNT(RelocType);
struct Reloc {
Reloc(RelocType, size_t offset, Index index, int32_t addend = 0);
@ -339,6 +303,8 @@ enum class LinkingEntryType {
enum class DylinkEntryType {
MemInfo = 1,
Needed = 2,
ExportInfo = 3,
ImportInfo = 4,
};
enum class SymbolType {
@ -390,7 +356,7 @@ enum class ExternalKind {
First = Func,
Last = Tag,
};
static const int kExternalKindCount = WABT_ENUM_COUNT(ExternalKind);
constexpr int kExternalKindCount = WABT_ENUM_COUNT(ExternalKind);
struct Limits {
Limits() = default;
@ -416,7 +382,7 @@ struct Limits {
enum { WABT_USE_NATURAL_ALIGNMENT = 0xFFFFFFFFFFFFFFFF };
Result ReadFile(string_view filename, std::vector<uint8_t>* out_data);
Result ReadFile(std::string_view filename, std::vector<uint8_t>* out_data);
void InitStdio();
@ -424,25 +390,25 @@ void InitStdio();
extern const char* g_kind_name[];
static WABT_INLINE const char* GetKindName(ExternalKind kind) {
static inline const char* GetKindName(ExternalKind kind) {
return static_cast<size_t>(kind) < kExternalKindCount
? g_kind_name[static_cast<size_t>(kind)]
: "<error_kind>";
? g_kind_name[static_cast<size_t>(kind)]
: "<error_kind>";
}
/* reloc */
extern const char* g_reloc_type_name[];
static WABT_INLINE const char* GetRelocTypeName(RelocType reloc) {
static inline const char* GetRelocTypeName(RelocType reloc) {
return static_cast<size_t>(reloc) < kRelocTypeCount
? g_reloc_type_name[static_cast<size_t>(reloc)]
: "<error_reloc_type>";
? g_reloc_type_name[static_cast<size_t>(reloc)]
: "<error_reloc_type>";
}
/* symbol */
static WABT_INLINE const char* GetSymbolTypeName(SymbolType type) {
static inline const char* GetSymbolTypeName(SymbolType type) {
switch (type) {
case SymbolType::Function:
return "func";
@ -478,10 +444,10 @@ inline void ConvertBackslashToSlash(std::string* s) {
ConvertBackslashToSlash(s->begin(), s->end());
}
inline void SwapBytesSized(void *addr, size_t size) {
inline void SwapBytesSized(void* addr, size_t size) {
auto bytes = static_cast<uint8_t*>(addr);
for (size_t i = 0; i < size / 2; i++) {
std::swap(bytes[i], bytes[size-1-i]);
std::swap(bytes[i], bytes[size - 1 - i]);
}
}

View File

@ -17,10 +17,10 @@
#ifndef WABT_DECOMPILER_AST_H_
#define WABT_DECOMPILER_AST_H_
#include "src/cast.h"
#include "src/generate-names.h"
#include "src/ir.h"
#include "src/ir-util.h"
#include "wabt/cast.h"
#include "wabt/generate-names.h"
#include "wabt/ir-util.h"
#include "wabt/ir.h"
#include <map>
@ -45,15 +45,16 @@ struct Node {
std::vector<Node> children;
// Node specific annotations.
union {
struct { Index var_start, var_count; }; // FlushedVar/FlushToVars
struct {
Index var_start, var_count; // FlushedVar/FlushToVars
};
const Var* var; // Decl/DeclInit.
LabelType lt; // br/br_if target.
LabelType lt; // br/br_if target.
} u;
Node() : ntype(NodeType::Uninitialized), etype(ExprType::Nop), e(nullptr) {
}
Node() : ntype(NodeType::Uninitialized), etype(ExprType::Nop), e(nullptr) {}
Node(NodeType ntype, ExprType etype, const Expr* e, const Var* v)
: ntype(ntype), etype(etype), e(e) {
: ntype(ntype), etype(etype), e(e) {
u.var = v;
}
@ -76,24 +77,26 @@ struct Node {
};
struct AST {
AST(ModuleContext& mc, const Func *f) : mc(mc), f(f) {
AST(ModuleContext& mc, const Func* f) : mc(mc), f(f) {
if (f) {
mc.BeginFunc(*f);
for (Index i = 0; i < f->GetNumParams(); i++) {
auto name = "$" + IndexToAlphaName(i);
vars_defined.insert({ name, { 0, false }});
vars_defined.insert({name, {0, false}});
}
}
}
~AST() {
if (f) mc.EndFunc();
if (f) {
mc.EndFunc();
}
}
// Create a new node, take nargs existing nodes on the exp stack as children.
Node& InsertNode(NodeType ntype, ExprType etype, const Expr* e, Index nargs) {
assert(exp_stack.size() >= nargs);
Node n { ntype, etype, e, nullptr };
Node n{ntype, etype, e, nullptr};
n.children.reserve(nargs);
std::move(exp_stack.end() - nargs, exp_stack.end(),
std::back_inserter(n.children));
@ -102,7 +105,8 @@ struct AST {
return exp_stack.back();
}
template<ExprType T> void PreDecl(const VarExpr<T>& ve) {
template <ExprType T>
void PreDecl(const VarExpr<T>& ve) {
// FIXME: this is slow, and would be better to avoid in callers.
// See https://github.com/WebAssembly/wabt/issues/1565
// And https://github.com/WebAssembly/wabt/issues/1665
@ -114,9 +118,10 @@ struct AST {
predecls.emplace_back(NodeType::Decl, ExprType::Nop, nullptr, &ve.var);
}
template<ExprType T> void Get(const VarExpr<T>& ve, bool local) {
template <ExprType T>
void Get(const VarExpr<T>& ve, bool local) {
if (local) {
auto ret = vars_defined.insert({ ve.var.name(), { cur_block_id, false }});
auto ret = vars_defined.insert({ve.var.name(), {cur_block_id, false}});
if (ret.second) {
// Use before def, may happen since locals are guaranteed 0.
PreDecl(ve);
@ -130,10 +135,11 @@ struct AST {
InsertNode(NodeType::Expr, T, &ve, 0);
}
template<ExprType T> void Set(const VarExpr<T>& ve, bool local) {
template <ExprType T>
void Set(const VarExpr<T>& ve, bool local) {
// Seen this var before?
if (local &&
vars_defined.insert({ ve.var.name(), { cur_block_id, false }}).second) {
vars_defined.insert({ve.var.name(), {cur_block_id, false}}).second) {
if (value_stack_depth == 1) {
// Top level, declare it here.
InsertNode(NodeType::DeclInit, ExprType::Nop, nullptr, 1).u.var =
@ -147,9 +153,11 @@ struct AST {
InsertNode(NodeType::Expr, T, &ve, 1);
}
template<ExprType T> void Block(const BlockExprBase<T>& be, LabelType label) {
template <ExprType T>
void Block(const BlockExprBase<T>& be, LabelType label) {
mc.BeginBlock(label, be.block);
Construct(be.block.exprs, be.block.decl.GetNumResults(), be.block.decl.GetNumParams(), false);
Construct(be.block.exprs, be.block.decl.GetNumResults(),
be.block.decl.GetNumParams(), false);
mc.EndBlock();
InsertNode(NodeType::Expr, T, &be, 1);
}
@ -177,7 +185,7 @@ struct AST {
auto& lt = *cast<LocalTeeExpr>(&e);
Set(lt, true);
if (value_stack_depth == 1) { // Tee is the only thing on there.
Get(lt, true); // Now Set + Get instead.
Get(lt, true); // Now Set + Get instead.
} else {
// Things are above us on the stack so the Tee can't be eliminated.
// The Set makes this work as a Tee when consumed by a parent.
@ -188,13 +196,16 @@ struct AST {
auto ife = cast<IfExpr>(&e);
value_stack_depth--; // Condition.
mc.BeginBlock(LabelType::Block, ife->true_);
Construct(ife->true_.exprs, ife->true_.decl.GetNumResults(), ife->true_.decl.GetNumParams(), false);
Construct(ife->true_.exprs, ife->true_.decl.GetNumResults(),
ife->true_.decl.GetNumParams(), false);
if (!ife->false_.empty()) {
Construct(ife->false_, ife->true_.decl.GetNumResults(), ife->true_.decl.GetNumParams(), false);
Construct(ife->false_, ife->true_.decl.GetNumResults(),
ife->true_.decl.GetNumParams(), false);
}
mc.EndBlock();
value_stack_depth++; // Put Condition back.
InsertNode(NodeType::Expr, ExprType::If, &e, ife->false_.empty() ? 2 : 3);
InsertNode(NodeType::Expr, ExprType::If, &e,
ife->false_.empty() ? 2 : 3);
return;
}
case ExprType::Block: {
@ -215,6 +226,11 @@ struct AST {
mc.GetLabel(cast<BrIfExpr>(&e)->var)->label_type;
return;
}
case ExprType::BrTable: {
InsertNode(NodeType::Expr, ExprType::BrTable, &e, 1).u.lt =
mc.GetLabel(cast<BrTableExpr>(&e)->default_target)->label_type;
return;
}
default: {
InsertNode(NodeType::Expr, e.type(), &e, arity.nargs);
return;
@ -222,7 +238,10 @@ struct AST {
}
}
void Construct(const ExprList& es, Index nresults, Index nparams, bool is_function_body) {
void Construct(const ExprList& es,
Index nresults,
Index nparams,
bool is_function_body) {
block_stack.push_back(cur_block_id);
cur_block_id = blocks_closed.size();
blocks_closed.push_back(false);
@ -234,8 +253,8 @@ struct AST {
Construct(e);
auto arity = mc.GetExprArity(e);
value_stack_depth -= arity.nargs;
value_stack_in_variables = std::min(value_stack_in_variables,
value_stack_depth);
value_stack_in_variables =
std::min(value_stack_in_variables, value_stack_depth);
unreachable = unreachable || arity.unreachable;
assert(unreachable || value_stack_depth >= value_stack_depth_start);
value_stack_depth += arity.nreturns;
@ -256,21 +275,20 @@ struct AST {
auto num_vars = value_stack_in_variables - value_stack_depth_start;
auto num_vals = value_stack_depth - value_stack_in_variables;
auto GenFlushVars = [&](int nargs) {
auto& ftv = InsertNode(NodeType::FlushToVars, ExprType::Nop, nullptr,
nargs);
auto& ftv =
InsertNode(NodeType::FlushToVars, ExprType::Nop, nullptr, nargs);
ftv.u.var_start = flushed_vars;
ftv.u.var_count = num_vals;
};
auto MoveStatementsBelowVars = [&](size_t amount) {
std::rotate(exp_stack.end() - num_vars - amount,
exp_stack.end() - amount,
exp_stack.end());
exp_stack.end() - amount, exp_stack.end());
};
auto GenFlushedVars = [&]() {
// Re-generate these values as vars.
for (int i = 0; i < num_vals; i++) {
auto& fv = InsertNode(NodeType::FlushedVar, ExprType::Nop, nullptr,
0);
auto& fv =
InsertNode(NodeType::FlushedVar, ExprType::Nop, nullptr, 0);
fv.u.var_start = flushed_vars++;
fv.u.var_count = 1;
}
@ -316,8 +334,8 @@ struct AST {
// Special optimisation: for constant instructions, we can mark these
// as if they were variables, so they can be re-ordered for free with
// the above code, without needing new variables!
// TODO: this would be nice to also do for get_local and maybe others,
// though that needs a way to ensure there's no set_local in between
// TODO: this would be nice to also do for local.get and maybe others,
// though that needs a way to ensure there's no local.set in between
// when they get lifted, so complicates matters a bit.
if (e.type() == ExprType::Const &&
value_stack_in_variables == value_stack_depth - 1) {
@ -325,9 +343,8 @@ struct AST {
}
}
}
assert(unreachable ||
value_stack_depth - value_stack_depth_start ==
static_cast<int>(nresults));
assert(unreachable || value_stack_depth - value_stack_depth_start ==
static_cast<int>(nresults));
// Undo any changes to value_stack_depth, since parent takes care of arity
// changes.
value_stack_depth = value_stack_depth_start;
@ -371,9 +388,12 @@ struct AST {
ModuleContext& mc;
std::vector<Node> exp_stack;
std::vector<Node> predecls;
const Func *f;
const Func* f;
int value_stack_depth = 0;
struct Variable { size_t block_id; bool defined; };
struct Variable {
size_t block_id;
bool defined;
};
std::map<std::string, Variable> vars_defined;
Index flushed_vars = 0;
size_t cur_block_id = 0;

View File

@ -17,14 +17,15 @@
#ifndef WABT_DECOMPILER_LS_H_
#define WABT_DECOMPILER_LS_H_
#include "src/decompiler-ast.h"
#include "wabt/decompiler-ast.h"
#include "wabt/string-util.h"
#include <map>
namespace wabt {
// Names starting with "u" are unsigned, the rest are "signed or doesn't matter"
inline const char *GetDecompTypeName(Type t) {
inline const char* GetDecompTypeName(Type t) {
switch (t) {
case Type::I8: return "byte";
case Type::I8U: return "ubyte";
@ -51,7 +52,7 @@ inline Type GetMemoryType(Type operand_type, Opcode opc) {
// from context, if not, we should probably represent that as a cast around
// the access, since it should not be part of the field type.
if (operand_type == Type::I32 || operand_type == Type::I64) {
auto name = string_view(opc.GetName());
auto name = std::string_view(opc.GetName());
// FIXME: change into a new column in opcode.def instead?
auto is_unsigned = name.substr(name.size() - 2) == "_u";
switch (opc.GetMemorySize()) {
@ -84,18 +85,20 @@ struct LoadStoreTracking {
};
void Track(const Node& n) {
for (auto& c : n.children) Track(c);
for (auto& c : n.children) {
Track(c);
}
switch (n.etype) {
case ExprType::Load: {
auto& le = *cast<LoadExpr>(n.e);
LoadStore(le.offset, le.opcode, le.opcode.GetResultType(),
le.align, n.children[0]);
LoadStore(le.offset, le.opcode, le.opcode.GetResultType(), le.align,
n.children[0]);
break;
}
case ExprType::Store: {
auto& se = *cast<StoreExpr>(n.e);
LoadStore(se.offset, se.opcode, se.opcode.GetParamType2(),
se.align, n.children[0]);
LoadStore(se.offset, se.opcode, se.opcode.GetParamType2(), se.align,
n.children[0]);
break;
}
default:
@ -117,7 +120,10 @@ struct LoadStoreTracking {
}
}
void LoadStore(uint64_t offset, Opcode opc, Type type, Address align,
void LoadStore(uint64_t offset,
Opcode opc,
Type type,
Address align,
const Node& addr_exp) {
auto byte_size = opc.GetMemorySize();
type = GetMemoryType(type, opc);
@ -131,10 +137,8 @@ struct LoadStoreTracking {
auto& access = var.accesses[offset];
// Check if previous access at this offset (if any) is of same size
// and type (see Checklayouts below).
if (access.byte_size &&
((access.byte_size != byte_size) ||
(access.type != type) ||
(access.align != align)))
if (access.byte_size && ((access.byte_size != byte_size) ||
(access.type != type) || (access.align != align)))
access.is_uniform = false;
// Also exclude weird alignment accesses from structs.
if (!opc.IsNaturallyAligned(align))
@ -202,9 +206,7 @@ struct LoadStoreTracking {
}
std::string GenAlign(Address align, Opcode opc) const {
return opc.IsNaturallyAligned(align)
? ""
: cat("@", std::to_string(align));
return opc.IsNaturallyAligned(align) ? "" : cat("@", std::to_string(align));
}
std::string GenTypeDecl(const std::string& name) const {
@ -215,7 +217,9 @@ struct LoadStoreTracking {
if (it->second.struct_layout) {
std::string s = "{ ";
for (auto& access : it->second.accesses) {
if (access.second.idx) s += ", ";
if (access.second.idx) {
s += ", ";
}
s += IdxToName(access.second.idx);
s += ':';
s += GetDecompTypeName(access.second.type);
@ -243,7 +247,7 @@ struct LoadStoreTracking {
}
if (it->second.struct_layout) {
auto ait = it->second.accesses.find(offset);
assert (ait != it->second.accesses.end());
assert(ait != it->second.accesses.end());
return IdxToName(ait->second.idx);
}
// Not a struct, see if it is a typed pointer.
@ -253,9 +257,7 @@ struct LoadStoreTracking {
return "";
}
void Clear() {
vars.clear();
}
void Clear() { vars.clear(); }
std::map<std::string, LSVar> vars;
};

View File

@ -17,15 +17,16 @@
#ifndef WABT_DECOMPILER_NAMING_H_
#define WABT_DECOMPILER_NAMING_H_
#include "src/decompiler-ast.h"
#include "wabt/decompiler-ast.h"
#include <set>
namespace wabt {
inline void RenameToIdentifier(std::string& name, Index i,
inline void RenameToIdentifier(std::string& name,
Index i,
BindingHash& bh,
const std::set<string_view>* filter) {
const std::set<std::string_view>* filter) {
// Filter out non-identifier characters, and try to reduce the size of
// gigantic C++ signature names.
std::string s;
@ -66,7 +67,8 @@ inline void RenameToIdentifier(std::string& name, Index i,
word_end--;
}
assert(word_end > word_start);
auto word = string_view(s.c_str() + word_start, word_end - word_start);
auto word =
std::string_view(s.c_str() + word_start, word_end - word_start);
if (filter->find(word) != filter->end()) {
s.resize(word_start);
}
@ -83,6 +85,9 @@ inline void RenameToIdentifier(std::string& name, Index i,
if (s.size() > max_identifier_length) {
s.resize(max_identifier_length);
}
if (s.empty()) {
s = "__empty";
}
// Remove original binding first, such that it doesn't match with our
// new name.
bh.erase(name);
@ -103,9 +108,10 @@ inline void RenameToIdentifier(std::string& name, Index i,
bh.emplace(s, Binding(i));
}
template<typename T>
void RenameToIdentifiers(std::vector<T*>& things, BindingHash& bh,
const std::set<string_view>* filter) {
template <typename T>
void RenameToIdentifiers(std::vector<T*>& things,
BindingHash& bh,
const std::set<std::string_view>* filter) {
Index i = 0;
for (auto thing : things) {
RenameToIdentifier(thing->name, i++, bh, filter);
@ -172,22 +178,10 @@ void RenameAll(Module& module) {
// We also filter common C++ keywords/STL idents that make for huge
// identifiers.
// FIXME: this can obviously give bad results if the input is not C++..
std::set<string_view> filter = {
{ "const" },
{ "std" },
{ "allocator" },
{ "char" },
{ "basic" },
{ "traits" },
{ "wchar" },
{ "t" },
{ "void" },
{ "int" },
{ "unsigned" },
{ "2" },
{ "cxxabiv1" },
{ "short" },
{ "4096ul" },
std::set<std::string_view> filter = {
{"const"}, {"std"}, {"allocator"}, {"char"}, {"basic"},
{"traits"}, {"wchar"}, {"t"}, {"void"}, {"int"},
{"unsigned"}, {"2"}, {"cxxabiv1"}, {"short"}, {"4096ul"},
};
RenameToIdentifiers(module.funcs, module.func_bindings, &filter);
// Also do this for some other kinds of names, but without the keyword

View File

@ -17,15 +17,14 @@
#ifndef WABT_DECOMPILER_H_
#define WABT_DECOMPILER_H_
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {
struct Module;
class Stream;
struct DecompileOptions {
};
struct DecompileOptions {};
void RenameAll(Module&);

View File

@ -18,12 +18,12 @@
#define WABT_ERROR_FORMATTER_H_
#include <cstdio>
#include <string>
#include <memory>
#include <string>
#include "src/color.h"
#include "src/error.h"
#include "src/lexer-source-line-finder.h"
#include "wabt/color.h"
#include "wabt/error.h"
#include "wabt/lexer-source-line-finder.h"
namespace wabt {

View File

@ -18,10 +18,10 @@
#define WABT_ERROR_H_
#include <string>
#include <string_view>
#include <vector>
#include "src/common.h"
#include "src/string-view.h"
#include "wabt/common.h"
namespace wabt {
@ -30,7 +30,7 @@ enum class ErrorLevel {
Error,
};
static WABT_INLINE const char* GetErrorLevelName(ErrorLevel error_level) {
static inline const char* GetErrorLevelName(ErrorLevel error_level) {
switch (error_level) {
case ErrorLevel::Warning:
return "warning";
@ -43,8 +43,8 @@ static WABT_INLINE const char* GetErrorLevelName(ErrorLevel error_level) {
class Error {
public:
Error() : error_level(ErrorLevel::Error) {}
Error(ErrorLevel error_level, Location loc, string_view message)
: error_level(error_level), loc(loc), message(message.to_string()) {}
Error(ErrorLevel error_level, Location loc, std::string_view message)
: error_level(error_level), loc(loc), message(message) {}
ErrorLevel error_level;
Location loc;

View File

@ -17,8 +17,8 @@
#ifndef WABT_EXPR_VISITOR_H_
#define WABT_EXPR_VISITOR_H_
#include "src/common.h"
#include "src/ir.h"
#include "wabt/common.h"
#include "wabt/ir.h"
namespace wabt {
@ -76,6 +76,7 @@ class ExprVisitor::Delegate {
virtual Result OnCallExpr(CallExpr*) = 0;
virtual Result OnCallIndirectExpr(CallIndirectExpr*) = 0;
virtual Result OnCallRefExpr(CallRefExpr*) = 0;
virtual Result OnCodeMetadataExpr(CodeMetadataExpr*) = 0;
virtual Result OnCompareExpr(CompareExpr*) = 0;
virtual Result OnConstExpr(ConstExpr*) = 0;
virtual Result OnConvertExpr(ConvertExpr*) = 0;
@ -149,6 +150,7 @@ class ExprVisitor::DelegateNop : public ExprVisitor::Delegate {
Result OnCallExpr(CallExpr*) override { return Result::Ok; }
Result OnCallIndirectExpr(CallIndirectExpr*) override { return Result::Ok; }
Result OnCallRefExpr(CallRefExpr*) override { return Result::Ok; }
Result OnCodeMetadataExpr(CodeMetadataExpr*) override { return Result::Ok; }
Result OnCompareExpr(CompareExpr*) override { return Result::Ok; }
Result OnConstExpr(ConstExpr*) override { return Result::Ok; }
Result OnConvertExpr(ConvertExpr*) override { return Result::Ok; }

View File

@ -26,13 +26,17 @@ WABT_FEATURE(exceptions, "exceptions", false, "Experimen
WABT_FEATURE(mutable_globals, "mutable-globals", true, "Import/export mutable globals")
WABT_FEATURE(sat_float_to_int, "saturating-float-to-int", true, "Saturating float-to-int operators")
WABT_FEATURE(sign_extension, "sign-extension", true, "Sign-extension operators")
WABT_FEATURE(simd, "simd", true, "SIMD support")
WABT_FEATURE(simd, "simd", true, "SIMD support")
WABT_FEATURE(threads, "threads", false, "Threading support")
WABT_FEATURE(function_references, "function-references", false, "Typed function references")
WABT_FEATURE(multi_value, "multi-value", true, "Multi-value")
WABT_FEATURE(tail_call, "tail-call", false, "Tail-call support")
WABT_FEATURE(bulk_memory, "bulk-memory", false, "Bulk-memory operations")
WABT_FEATURE(reference_types, "reference-types", false, "Reference types (externref)")
WABT_FEATURE(bulk_memory, "bulk-memory", true, "Bulk-memory operations")
WABT_FEATURE(reference_types, "reference-types", true, "Reference types (externref)")
WABT_FEATURE(annotations, "annotations", false, "Custom annotation syntax")
WABT_FEATURE(code_metadata, "code-metadata", false, "Code metadata")
WABT_FEATURE(gc, "gc", false, "Garbage collection")
WABT_FEATURE(memory64, "memory64", false, "64-bit memory")
WABT_FEATURE(multi_memory, "multi-memory", false, "Multi-memory")
WABT_FEATURE(extended_const, "extended-const", false, "Extended constant expressions")
WABT_FEATURE(relaxed_simd, "relaxed-simd", false, "Relaxed SIMD")

View File

@ -17,7 +17,7 @@
#ifndef WABT_FEATURE_H_
#define WABT_FEATURE_H_
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {
@ -29,7 +29,7 @@ class Features {
void EnableAll() {
#define WABT_FEATURE(variable, flag, default_, help) enable_##variable();
#include "src/feature.def"
#include "wabt/feature.def"
#undef WABT_FEATURE
}
@ -41,7 +41,7 @@ class Features {
variable##_enabled_ = value; \
UpdateDependencies(); \
}
#include "src/feature.def"
#include "wabt/feature.def"
#undef WABT_FEATURE
private:
@ -49,7 +49,7 @@ class Features {
#define WABT_FEATURE(variable, flag, default_, help) \
bool variable##_enabled_ = default_;
#include "src/feature.def"
#include "wabt/feature.def"
#undef WABT_FEATURE
};

View File

@ -17,7 +17,7 @@
#ifndef WABT_FILENAMES_H_
#define WABT_FILENAMES_H_
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {
@ -29,7 +29,7 @@ extern const char* kWatExtension;
// "foo.txt", => ".txt"
// "foo" => ""
// "/foo/bar/foo.wasm" => ".wasm"
string_view GetExtension(string_view filename);
std::string_view GetExtension(std::string_view filename);
// Strip extension, e.g.:
//
@ -37,14 +37,14 @@ string_view GetExtension(string_view filename);
// "foo.bar" => "foo"
// "/path/to/foo.bar" => "/path/to/foo"
// "\\path\\to\\foo.bar" => "\\path\\to\\foo"
string_view StripExtension(string_view s);
std::string_view StripExtension(std::string_view s);
// Strip everything up to and including the last slash, e.g.:
//
// "/foo/bar/baz", => "baz"
// "/usr/local/include/stdio.h", => "stdio.h"
// "foo.bar", => "foo.bar"
string_view GetBasename(string_view filename);
std::string_view GetBasename(std::string_view filename);
} // namespace wabt

View File

@ -17,7 +17,7 @@
#ifndef WABT_GENERATE_NAMES_H_
#define WABT_GENERATE_NAMES_H_
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {

View File

@ -21,8 +21,6 @@
#include <iterator>
#include <memory>
#include "src/make-unique.h"
// This uses a similar interface as std::list, but is missing the following
// features:
//
@ -53,15 +51,15 @@ template <typename T>
class intrusive_list {
public:
// types:
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
class iterator;
class const_iterator;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
// construct/copy/destroy:
intrusive_list();
@ -142,11 +140,11 @@ class intrusive_list {
template <typename T>
class intrusive_list<T>::iterator {
public:
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
using difference_type = std::ptrdiff_t;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using pointer = T*;
using reference = T&;
iterator(const intrusive_list<T>& list, T* node)
: list_(&list), node_(node) {}
@ -205,11 +203,11 @@ class intrusive_list<T>::iterator {
template <typename T>
class intrusive_list<T>::const_iterator {
public:
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef const T* pointer;
typedef const T& reference;
using difference_type = std::ptrdiff_t;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using pointer = const T*;
using reference = const T&;
const_iterator(const intrusive_list<T>& list, T* node)
: list_(&list), node_(node) {}
@ -320,8 +318,8 @@ inline typename intrusive_list<T>::iterator intrusive_list<T>::end() noexcept {
}
template <typename T>
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end() const
noexcept {
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end()
const noexcept {
return const_iterator(*this, nullptr);
}
@ -374,8 +372,8 @@ intrusive_list<T>::crend() const noexcept {
}
template <typename T>
inline typename intrusive_list<T>::size_type intrusive_list<T>::size() const
noexcept {
inline typename intrusive_list<T>::size_type intrusive_list<T>::size()
const noexcept {
return size_;
}
@ -413,13 +411,13 @@ inline typename intrusive_list<T>::const_reference intrusive_list<T>::back()
template <typename T>
template <class... Args>
inline void intrusive_list<T>::emplace_front(Args&&... args) {
push_front(MakeUnique<T>(std::forward<Args>(args)...));
push_front(std::make_unique<T>(std::forward<Args>(args)...));
}
template <typename T>
template <class... Args>
inline void intrusive_list<T>::emplace_back(Args&&... args) {
push_back(MakeUnique<T>(std::forward<Args>(args)...));
push_back(std::make_unique<T>(std::forward<Args>(args)...));
}
template <typename T>
@ -439,7 +437,7 @@ inline void intrusive_list<T>::push_front(std::unique_ptr<T> node) {
template <typename T>
inline void intrusive_list<T>::push_front(T&& node) {
push_front(MakeUnique<T>(std::move(node)));
push_front(std::make_unique<T>(std::move(node)));
}
template <typename T>
@ -459,7 +457,7 @@ inline void intrusive_list<T>::push_back(std::unique_ptr<T> node) {
template <typename T>
inline void intrusive_list<T>::push_back(T&& node) {
push_back(MakeUnique<T>(std::move(node)));
push_back(std::make_unique<T>(std::move(node)));
}
template <typename T>
@ -507,7 +505,7 @@ template <class... Args>
inline typename intrusive_list<T>::iterator intrusive_list<T>::emplace(
iterator pos,
Args&&... args) {
return insert(pos, MakeUnique<T>(std::forward<Args>(args)...));
return insert(pos, std::make_unique<T>(std::forward<Args>(args)...));
}
template <typename T>
@ -539,7 +537,7 @@ template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::insert(
iterator pos,
T&& node) {
return insert(pos, MakeUnique<T>(std::move(node)));
return insert(pos, std::make_unique<T>(std::move(node)));
}
template <typename T>

View File

@ -17,8 +17,8 @@
#ifndef WABT_IR_UTIL_H_
#define WABT_IR_UTIL_H_
#include "src/common.h"
#include "src/ir.h"
#include "wabt/common.h"
#include "wabt/ir.h"
namespace wabt {
@ -39,7 +39,7 @@ struct Label {
};
struct ModuleContext {
ModuleContext(const Module &module) : module(module) {}
ModuleContext(const Module& module) : module(module) {}
Index GetLabelStackSize() const { return label_stack_.size(); }
const Label* GetLabel(const Var& var) const;
@ -61,11 +61,12 @@ struct ModuleContext {
Index nreturns;
bool unreachable;
Arities(Index na, Index nr, bool ur = false)
: nargs(na), nreturns(nr), unreachable(ur) {}
: nargs(na), nreturns(nr), unreachable(ur) {}
};
Arities GetExprArity(const Expr& expr) const;
const Module &module;
const Module& module;
private:
const Func* current_func_ = nullptr;
std::vector<Label> label_stack_;

View File

@ -22,14 +22,14 @@
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
#include "src/binding-hash.h"
#include "src/common.h"
#include "src/intrusive-list.h"
#include "src/opcode.h"
#include "src/string-view.h"
#include "wabt/binding-hash.h"
#include "wabt/common.h"
#include "wabt/intrusive-list.h"
#include "wabt/opcode.h"
namespace wabt {
@ -41,8 +41,9 @@ enum class VarType {
};
struct Var {
explicit Var(Index index = kInvalidIndex, const Location& loc = Location());
explicit Var(string_view name, const Location& loc = Location());
explicit Var();
explicit Var(Index index, const Location& loc);
explicit Var(std::string_view name, const Location& loc);
Var(Var&&);
Var(const Var&);
Var& operator=(const Var&);
@ -53,12 +54,18 @@ struct Var {
bool is_index() const { return type_ == VarType::Index; }
bool is_name() const { return type_ == VarType::Name; }
Index index() const { assert(is_index()); return index_; }
const std::string& name() const { assert(is_name()); return name_; }
Index index() const {
assert(is_index());
return index_;
}
const std::string& name() const {
assert(is_name());
return name_;
}
void set_index(Index);
void set_name(std::string&&);
void set_name(string_view);
void set_name(std::string_view);
Location loc;
@ -71,7 +78,7 @@ struct Var {
std::string name_;
};
};
typedef std::vector<Var> VarVector;
using VarVector = std::vector<Var>;
struct Const {
static constexpr uintptr_t kRefNullBits = ~uintptr_t(0);
@ -95,7 +102,10 @@ struct Const {
}
Type type() const { return type_; }
Type lane_type() const { assert(type_ == Type::V128); return lane_type_; }
Type lane_type() const {
assert(type_ == Type::V128);
return lane_type_;
}
int lane_count() const {
switch (lane_type()) {
@ -117,7 +127,9 @@ struct Const {
v128 vec128() const { return data_; }
template <typename T>
T v128_lane(int lane) const { return data_.To<T>(lane); }
T v128_lane(int lane) const {
return data_.To<T>(lane);
}
void set_u32(uint32_t x) { From(Type::I32, x); }
void set_u64(uint64_t x) { From(Type::I64, x); }
@ -132,11 +144,17 @@ struct Const {
void set_v128_f64(int lane, uint64_t x) { set_v128_lane(lane, Type::F64, x); }
// Only used for expectations. (e.g. wast assertions)
void set_f32(ExpectedNan nan) { set_f32(0); set_expected_nan(0, nan); }
void set_f64(ExpectedNan nan) { set_f64(0); set_expected_nan(0, nan); }
void set_funcref() { From<uintptr_t>(Type::FuncRef, 0); }
void set_f32(ExpectedNan nan) {
set_f32(0);
set_expected_nan(0, nan);
}
void set_f64(ExpectedNan nan) {
set_f64(0);
set_expected_nan(0, nan);
}
void set_funcref() { From<uintptr_t>(Type::FuncRef, 0); }
void set_externref(uintptr_t x) { From(Type::ExternRef, x); }
void set_null(Type type) { From<uintptr_t>(type, kRefNullBits); }
void set_null(Type type) { From<uintptr_t>(type, kRefNullBits); }
bool is_expected_nan(int lane = 0) const {
return expected_nan(lane) != ExpectedNan::None;
@ -178,16 +196,71 @@ struct Const {
}
Type type_;
Type lane_type_; // Only valid if type_ == Type::V128.
Type lane_type_; // Only valid if type_ == Type::V128.
v128 data_;
ExpectedNan nan_[4];
};
typedef std::vector<Const> ConstVector;
using ConstVector = std::vector<Const>;
enum class ExpectationType {
Values,
Either,
};
class Expectation {
public:
Expectation() = delete;
virtual ~Expectation() = default;
ExpectationType type() const { return type_; }
Location loc;
ConstVector expected;
protected:
explicit Expectation(ExpectationType type, const Location& loc = Location())
: loc(loc), type_(type) {}
private:
ExpectationType type_;
};
template <ExpectationType TypeEnum>
class ExpectationMixin : public Expectation {
public:
static bool classof(const Expectation* expectation) {
return expectation->type() == TypeEnum;
}
explicit ExpectationMixin(const Location& loc = Location())
: Expectation(TypeEnum, loc) {}
};
class ValueExpectation : public ExpectationMixin<ExpectationType::Values> {
public:
explicit ValueExpectation(const Location& loc = Location())
: ExpectationMixin<ExpectationType::Values>(loc) {}
};
struct EitherExpectation : public ExpectationMixin<ExpectationType::Either> {
public:
explicit EitherExpectation(const Location& loc = Location())
: ExpectationMixin<ExpectationType::Either>(loc) {}
};
typedef std::unique_ptr<Expectation> ExpectationPtr;
struct FuncSignature {
TypeVector param_types;
TypeVector result_types;
// Some types can have names, for example (ref $foo) has type $foo.
// So to use this type we need to translate its name into
// a proper index from the module type section.
// This is the mapping from parameter/result index to its name.
std::unordered_map<uint32_t, std::string> param_type_names;
std::unordered_map<uint32_t, std::string> result_type_names;
Index GetNumParams() const { return param_types.size(); }
Index GetNumResults() const { return result_types.size(); }
Type GetParamType(Index index) const { return param_types[index]; }
@ -215,9 +288,9 @@ class TypeEntry {
protected:
explicit TypeEntry(TypeEntryKind kind,
string_view name = string_view(),
std::string_view name = std::string_view(),
const Location& loc = Location())
: loc(loc), name(name.to_string()), kind_(kind) {}
: loc(loc), name(name), kind_(kind) {}
TypeEntryKind kind_;
};
@ -228,7 +301,7 @@ class FuncType : public TypeEntry {
return entry->kind() == TypeEntryKind::Func;
}
explicit FuncType(string_view name = string_view())
explicit FuncType(std::string_view name = std::string_view())
: TypeEntry(TypeEntryKind::Func, name) {}
Index GetNumParams() const { return sig.GetNumParams(); }
@ -251,7 +324,7 @@ class StructType : public TypeEntry {
return entry->kind() == TypeEntryKind::Struct;
}
explicit StructType(string_view name = string_view())
explicit StructType(std::string_view name = std::string_view())
: TypeEntry(TypeEntryKind::Struct) {}
std::vector<Field> fields;
@ -263,7 +336,7 @@ class ArrayType : public TypeEntry {
return entry->kind() == TypeEntryKind::Array;
}
explicit ArrayType(string_view name = string_view())
explicit ArrayType(std::string_view name = std::string_view())
: TypeEntry(TypeEntryKind::Array) {}
Field field;
@ -296,6 +369,7 @@ enum class ExprType {
Call,
CallIndirect,
CallRef,
CodeMetadata,
Compare,
Const,
Convert,
@ -351,9 +425,9 @@ enum class ExprType {
const char* GetExprTypeName(ExprType type);
class Expr;
typedef intrusive_list<Expr> ExprList;
using ExprList = intrusive_list<Expr>;
typedef FuncDeclaration BlockDeclaration;
using BlockDeclaration = FuncDeclaration;
struct Block {
Block() = default;
@ -376,13 +450,9 @@ struct Catch {
return var.is_index() && var.index() == kInvalidIndex;
}
};
typedef std::vector<Catch> CatchVector;
using CatchVector = std::vector<Catch>;
enum class TryKind {
Plain,
Catch,
Delegate
};
enum class TryKind { Plain, Catch, Delegate };
class Expr : public intrusive_list_base<Expr> {
public:
@ -411,14 +481,39 @@ class ExprMixin : public Expr {
explicit ExprMixin(const Location& loc = Location()) : Expr(TypeEnum, loc) {}
};
typedef ExprMixin<ExprType::Drop> DropExpr;
typedef ExprMixin<ExprType::MemoryGrow> MemoryGrowExpr;
typedef ExprMixin<ExprType::MemorySize> MemorySizeExpr;
typedef ExprMixin<ExprType::MemoryCopy> MemoryCopyExpr;
typedef ExprMixin<ExprType::MemoryFill> MemoryFillExpr;
typedef ExprMixin<ExprType::Nop> NopExpr;
typedef ExprMixin<ExprType::Return> ReturnExpr;
typedef ExprMixin<ExprType::Unreachable> UnreachableExpr;
template <ExprType TypeEnum>
class MemoryExpr : public ExprMixin<TypeEnum> {
public:
MemoryExpr(Var memidx, const Location& loc = Location())
: ExprMixin<TypeEnum>(loc), memidx(memidx) {}
Var memidx;
};
template <ExprType TypeEnum>
class MemoryBinaryExpr : public ExprMixin<TypeEnum> {
public:
MemoryBinaryExpr(Var srcmemidx,
Var destmemidx,
const Location& loc = Location())
: ExprMixin<TypeEnum>(loc),
srcmemidx(srcmemidx),
destmemidx(destmemidx) {}
Var srcmemidx;
Var destmemidx;
};
using DropExpr = ExprMixin<ExprType::Drop>;
using NopExpr = ExprMixin<ExprType::Nop>;
using ReturnExpr = ExprMixin<ExprType::Return>;
using UnreachableExpr = ExprMixin<ExprType::Unreachable>;
using MemoryGrowExpr = MemoryExpr<ExprType::MemoryGrow>;
using MemorySizeExpr = MemoryExpr<ExprType::MemorySize>;
using MemoryFillExpr = MemoryExpr<ExprType::MemoryFill>;
using MemoryCopyExpr = MemoryBinaryExpr<ExprType::MemoryCopy>;
template <ExprType TypeEnum>
class RefTypeExpr : public ExprMixin<TypeEnum> {
@ -429,8 +524,8 @@ class RefTypeExpr : public ExprMixin<TypeEnum> {
Type type;
};
typedef RefTypeExpr<ExprType::RefNull> RefNullExpr;
typedef ExprMixin<ExprType::RefIsNull> RefIsNullExpr;
using RefNullExpr = RefTypeExpr<ExprType::RefNull>;
using RefIsNullExpr = ExprMixin<ExprType::RefIsNull>;
template <ExprType TypeEnum>
class OpcodeExpr : public ExprMixin<TypeEnum> {
@ -441,11 +536,11 @@ class OpcodeExpr : public ExprMixin<TypeEnum> {
Opcode opcode;
};
typedef OpcodeExpr<ExprType::Binary> BinaryExpr;
typedef OpcodeExpr<ExprType::Compare> CompareExpr;
typedef OpcodeExpr<ExprType::Convert> ConvertExpr;
typedef OpcodeExpr<ExprType::Unary> UnaryExpr;
typedef OpcodeExpr<ExprType::Ternary> TernaryExpr;
using BinaryExpr = OpcodeExpr<ExprType::Binary>;
using CompareExpr = OpcodeExpr<ExprType::Compare>;
using ConvertExpr = OpcodeExpr<ExprType::Convert>;
using UnaryExpr = OpcodeExpr<ExprType::Unary>;
using TernaryExpr = OpcodeExpr<ExprType::Ternary>;
class SimdLaneOpExpr : public ExprMixin<ExprType::SimdLaneOp> {
public:
@ -456,35 +551,41 @@ class SimdLaneOpExpr : public ExprMixin<ExprType::SimdLaneOp> {
uint64_t val;
};
class SimdLoadLaneExpr : public OpcodeExpr<ExprType::SimdLoadLane> {
class SimdLoadLaneExpr : public MemoryExpr<ExprType::SimdLoadLane> {
public:
SimdLoadLaneExpr(Opcode opcode,
Var memidx,
Address align,
Address offset,
uint64_t val,
const Location& loc = Location())
: OpcodeExpr<ExprType::SimdLoadLane>(opcode, loc),
: MemoryExpr<ExprType::SimdLoadLane>(memidx, loc),
opcode(opcode),
align(align),
offset(offset),
val(val) {}
Opcode opcode;
Address align;
Address offset;
uint64_t val;
};
class SimdStoreLaneExpr : public OpcodeExpr<ExprType::SimdStoreLane> {
class SimdStoreLaneExpr : public MemoryExpr<ExprType::SimdStoreLane> {
public:
SimdStoreLaneExpr(Opcode opcode,
Var memidx,
Address align,
Address offset,
uint64_t val,
const Location& loc = Location())
: OpcodeExpr<ExprType::SimdStoreLane>(opcode, loc),
: MemoryExpr<ExprType::SimdStoreLane>(memidx, loc),
opcode(opcode),
align(align),
offset(offset),
val(val) {}
Opcode opcode;
Address align;
Address offset;
uint64_t val;
@ -508,27 +609,37 @@ class VarExpr : public ExprMixin<TypeEnum> {
Var var;
};
typedef VarExpr<ExprType::Br> BrExpr;
typedef VarExpr<ExprType::BrIf> BrIfExpr;
typedef VarExpr<ExprType::Call> CallExpr;
typedef VarExpr<ExprType::RefFunc> RefFuncExpr;
typedef VarExpr<ExprType::GlobalGet> GlobalGetExpr;
typedef VarExpr<ExprType::GlobalSet> GlobalSetExpr;
typedef VarExpr<ExprType::LocalGet> LocalGetExpr;
typedef VarExpr<ExprType::LocalSet> LocalSetExpr;
typedef VarExpr<ExprType::LocalTee> LocalTeeExpr;
typedef VarExpr<ExprType::ReturnCall> ReturnCallExpr;
typedef VarExpr<ExprType::Throw> ThrowExpr;
typedef VarExpr<ExprType::Rethrow> RethrowExpr;
template <ExprType TypeEnum>
class MemoryVarExpr : public MemoryExpr<TypeEnum> {
public:
MemoryVarExpr(const Var& var, Var memidx, const Location& loc = Location())
: MemoryExpr<TypeEnum>(memidx, loc), var(var) {}
typedef VarExpr<ExprType::MemoryInit> MemoryInitExpr;
typedef VarExpr<ExprType::DataDrop> DataDropExpr;
typedef VarExpr<ExprType::ElemDrop> ElemDropExpr;
typedef VarExpr<ExprType::TableGet> TableGetExpr;
typedef VarExpr<ExprType::TableSet> TableSetExpr;
typedef VarExpr<ExprType::TableGrow> TableGrowExpr;
typedef VarExpr<ExprType::TableSize> TableSizeExpr;
typedef VarExpr<ExprType::TableFill> TableFillExpr;
Var var;
};
using BrExpr = VarExpr<ExprType::Br>;
using BrIfExpr = VarExpr<ExprType::BrIf>;
using CallExpr = VarExpr<ExprType::Call>;
using RefFuncExpr = VarExpr<ExprType::RefFunc>;
using GlobalGetExpr = VarExpr<ExprType::GlobalGet>;
using GlobalSetExpr = VarExpr<ExprType::GlobalSet>;
using LocalGetExpr = VarExpr<ExprType::LocalGet>;
using LocalSetExpr = VarExpr<ExprType::LocalSet>;
using LocalTeeExpr = VarExpr<ExprType::LocalTee>;
using ReturnCallExpr = VarExpr<ExprType::ReturnCall>;
using ThrowExpr = VarExpr<ExprType::Throw>;
using RethrowExpr = VarExpr<ExprType::Rethrow>;
using DataDropExpr = VarExpr<ExprType::DataDrop>;
using ElemDropExpr = VarExpr<ExprType::ElemDrop>;
using TableGetExpr = VarExpr<ExprType::TableGet>;
using TableSetExpr = VarExpr<ExprType::TableSet>;
using TableGrowExpr = VarExpr<ExprType::TableGrow>;
using TableSizeExpr = VarExpr<ExprType::TableSize>;
using TableFillExpr = VarExpr<ExprType::TableFill>;
using MemoryInitExpr = MemoryVarExpr<ExprType::MemoryInit>;
class SelectExpr : public ExprMixin<ExprType::Select> {
public:
@ -570,9 +681,22 @@ class CallIndirectExpr : public ExprMixin<ExprType::CallIndirect> {
Var table;
};
class CodeMetadataExpr : public ExprMixin<ExprType::CodeMetadata> {
public:
explicit CodeMetadataExpr(std::string_view name,
std::vector<uint8_t> data,
const Location& loc = Location())
: ExprMixin<ExprType::CodeMetadata>(loc),
name(std::move(name)),
data(std::move(data)) {}
std::string_view name;
std::vector<uint8_t> data;
};
class ReturnCallIndirectExpr : public ExprMixin<ExprType::ReturnCallIndirect> {
public:
explicit ReturnCallIndirectExpr(const Location &loc = Location())
explicit ReturnCallIndirectExpr(const Location& loc = Location())
: ExprMixin<ExprType::ReturnCallIndirect>(loc) {}
FuncDeclaration decl;
@ -581,7 +705,7 @@ class ReturnCallIndirectExpr : public ExprMixin<ExprType::ReturnCallIndirect> {
class CallRefExpr : public ExprMixin<ExprType::CallRef> {
public:
explicit CallRefExpr(const Location &loc = Location())
explicit CallRefExpr(const Location& loc = Location())
: ExprMixin<ExprType::CallRef>(loc) {}
// This field is setup only during Validate phase,
@ -598,8 +722,8 @@ class BlockExprBase : public ExprMixin<TypeEnum> {
Block block;
};
typedef BlockExprBase<ExprType::Block> BlockExpr;
typedef BlockExprBase<ExprType::Loop> LoopExpr;
using BlockExpr = BlockExprBase<ExprType::Block>;
using LoopExpr = BlockExprBase<ExprType::Loop>;
class IfExpr : public ExprMixin<ExprType::If> {
public:
@ -641,13 +765,14 @@ class ConstExpr : public ExprMixin<ExprType::Const> {
// TODO(binji): Rename this, it is used for more than loads/stores now.
template <ExprType TypeEnum>
class LoadStoreExpr : public ExprMixin<TypeEnum> {
class LoadStoreExpr : public MemoryExpr<TypeEnum> {
public:
LoadStoreExpr(Opcode opcode,
Var memidx,
Address align,
Address offset,
const Location& loc = Location())
: ExprMixin<TypeEnum>(loc),
: MemoryExpr<TypeEnum>(memidx, loc),
opcode(opcode),
align(align),
offset(offset) {}
@ -657,16 +782,17 @@ class LoadStoreExpr : public ExprMixin<TypeEnum> {
Address offset;
};
typedef LoadStoreExpr<ExprType::Load> LoadExpr;
typedef LoadStoreExpr<ExprType::Store> StoreExpr;
typedef LoadStoreExpr<ExprType::AtomicLoad> AtomicLoadExpr;
typedef LoadStoreExpr<ExprType::AtomicStore> AtomicStoreExpr;
typedef LoadStoreExpr<ExprType::AtomicRmw> AtomicRmwExpr;
typedef LoadStoreExpr<ExprType::AtomicRmwCmpxchg> AtomicRmwCmpxchgExpr;
typedef LoadStoreExpr<ExprType::AtomicWait> AtomicWaitExpr;
typedef LoadStoreExpr<ExprType::AtomicNotify> AtomicNotifyExpr;
typedef LoadStoreExpr<ExprType::LoadSplat> LoadSplatExpr;
typedef LoadStoreExpr<ExprType::LoadZero> LoadZeroExpr;
using LoadExpr = LoadStoreExpr<ExprType::Load>;
using StoreExpr = LoadStoreExpr<ExprType::Store>;
using AtomicLoadExpr = LoadStoreExpr<ExprType::AtomicLoad>;
using AtomicStoreExpr = LoadStoreExpr<ExprType::AtomicStore>;
using AtomicRmwExpr = LoadStoreExpr<ExprType::AtomicRmw>;
using AtomicRmwCmpxchgExpr = LoadStoreExpr<ExprType::AtomicRmwCmpxchg>;
using AtomicWaitExpr = LoadStoreExpr<ExprType::AtomicWait>;
using AtomicNotifyExpr = LoadStoreExpr<ExprType::AtomicNotify>;
using LoadSplatExpr = LoadStoreExpr<ExprType::LoadSplat>;
using LoadZeroExpr = LoadStoreExpr<ExprType::LoadZero>;
class AtomicFenceExpr : public ExprMixin<ExprType::AtomicFence> {
public:
@ -679,7 +805,7 @@ class AtomicFenceExpr : public ExprMixin<ExprType::AtomicFence> {
};
struct Tag {
explicit Tag(string_view name) : name(name.to_string()) {}
explicit Tag(std::string_view name) : name(name) {}
std::string name;
FuncDeclaration decl;
@ -687,8 +813,8 @@ struct Tag {
class LocalTypes {
public:
typedef std::pair<Type, Index> Decl;
typedef std::vector<Decl> Decls;
using Decl = std::pair<Type, Index>;
using Decls = std::vector<Decl>;
struct const_iterator {
const_iterator(Decls::const_iterator decl, Index index)
@ -747,7 +873,7 @@ inline bool operator!=(const LocalTypes::const_iterator& lhs,
}
struct Func {
explicit Func(string_view name) : name(name.to_string()) {}
explicit Func(std::string_view name) : name(name) {}
Type GetParamType(Index index) const { return decl.GetParamType(index); }
Type GetResultType(Index index) const { return decl.GetResultType(index); }
@ -766,10 +892,11 @@ struct Func {
LocalTypes local_types;
BindingHash bindings;
ExprList exprs;
Location loc;
};
struct Global {
explicit Global(string_view name) : name(name.to_string()) {}
explicit Global(std::string_view name) : name(name) {}
std::string name;
Type type = Type::Void;
@ -778,33 +905,18 @@ struct Global {
};
struct Table {
explicit Table(string_view name)
: name(name.to_string()), elem_type(Type::FuncRef) {}
explicit Table(std::string_view name)
: name(name), elem_type(Type::FuncRef) {}
std::string name;
Limits elem_limits;
Type elem_type;
};
enum class ElemExprKind {
RefNull,
RefFunc,
};
struct ElemExpr {
ElemExpr() : kind(ElemExprKind::RefNull), type(Type::FuncRef) {}
explicit ElemExpr(Var var) : kind(ElemExprKind::RefFunc), var(var) {}
explicit ElemExpr(Type type) : kind(ElemExprKind::RefNull), type(type) {}
ElemExprKind kind;
Var var; // Only used when kind == RefFunc.
Type type; // Only used when kind == RefNull
};
typedef std::vector<ElemExpr> ElemExprVector;
using ExprListVector = std::vector<ExprList>;
struct ElemSegment {
explicit ElemSegment(string_view name) : name(name.to_string()) {}
explicit ElemSegment(std::string_view name) : name(name) {}
uint8_t GetFlags(const Module*) const;
SegmentKind kind = SegmentKind::Active;
@ -812,18 +924,18 @@ struct ElemSegment {
Var table_var;
Type elem_type;
ExprList offset;
ElemExprVector elem_exprs;
ExprListVector elem_exprs;
};
struct Memory {
explicit Memory(string_view name) : name(name.to_string()) {}
explicit Memory(std::string_view name) : name(name) {}
std::string name;
Limits page_limits;
};
struct DataSegment {
explicit DataSegment(string_view name) : name(name.to_string()) {}
explicit DataSegment(std::string_view name) : name(name) {}
uint8_t GetFlags(const Module*) const;
SegmentKind kind = SegmentKind::Active;
@ -862,7 +974,7 @@ class ImportMixin : public Import {
class FuncImport : public ImportMixin<ExternalKind::Func> {
public:
explicit FuncImport(string_view name = string_view())
explicit FuncImport(std::string_view name = std::string_view())
: ImportMixin<ExternalKind::Func>(), func(name) {}
Func func;
@ -870,7 +982,7 @@ class FuncImport : public ImportMixin<ExternalKind::Func> {
class TableImport : public ImportMixin<ExternalKind::Table> {
public:
explicit TableImport(string_view name = string_view())
explicit TableImport(std::string_view name = std::string_view())
: ImportMixin<ExternalKind::Table>(), table(name) {}
Table table;
@ -878,7 +990,7 @@ class TableImport : public ImportMixin<ExternalKind::Table> {
class MemoryImport : public ImportMixin<ExternalKind::Memory> {
public:
explicit MemoryImport(string_view name = string_view())
explicit MemoryImport(std::string_view name = std::string_view())
: ImportMixin<ExternalKind::Memory>(), memory(name) {}
Memory memory;
@ -886,7 +998,7 @@ class MemoryImport : public ImportMixin<ExternalKind::Memory> {
class GlobalImport : public ImportMixin<ExternalKind::Global> {
public:
explicit GlobalImport(string_view name = string_view())
explicit GlobalImport(std::string_view name = std::string_view())
: ImportMixin<ExternalKind::Global>(), global(name) {}
Global global;
@ -894,7 +1006,7 @@ class GlobalImport : public ImportMixin<ExternalKind::Global> {
class TagImport : public ImportMixin<ExternalKind::Tag> {
public:
explicit TagImport(string_view name = string_view())
explicit TagImport(std::string_view name = std::string_view())
: ImportMixin<ExternalKind::Tag>(), tag(name) {}
Tag tag;
@ -937,7 +1049,7 @@ class ModuleField : public intrusive_list_base<ModuleField> {
ModuleFieldType type_;
};
typedef intrusive_list<ModuleField> ModuleFieldList;
using ModuleFieldList = intrusive_list<ModuleField>;
template <ModuleFieldType TypeEnum>
class ModuleFieldMixin : public ModuleField {
@ -952,7 +1064,7 @@ class ModuleFieldMixin : public ModuleField {
class FuncModuleField : public ModuleFieldMixin<ModuleFieldType::Func> {
public:
explicit FuncModuleField(const Location& loc = Location(),
string_view name = string_view())
std::string_view name = std::string_view())
: ModuleFieldMixin<ModuleFieldType::Func>(loc), func(name) {}
Func func;
@ -961,7 +1073,7 @@ class FuncModuleField : public ModuleFieldMixin<ModuleFieldType::Func> {
class GlobalModuleField : public ModuleFieldMixin<ModuleFieldType::Global> {
public:
explicit GlobalModuleField(const Location& loc = Location(),
string_view name = string_view())
std::string_view name = std::string_view())
: ModuleFieldMixin<ModuleFieldType::Global>(loc), global(name) {}
Global global;
@ -998,7 +1110,7 @@ class TypeModuleField : public ModuleFieldMixin<ModuleFieldType::Type> {
class TableModuleField : public ModuleFieldMixin<ModuleFieldType::Table> {
public:
explicit TableModuleField(const Location& loc = Location(),
string_view name = string_view())
std::string_view name = std::string_view())
: ModuleFieldMixin<ModuleFieldType::Table>(loc), table(name) {}
Table table;
@ -1008,7 +1120,7 @@ class ElemSegmentModuleField
: public ModuleFieldMixin<ModuleFieldType::ElemSegment> {
public:
explicit ElemSegmentModuleField(const Location& loc = Location(),
string_view name = string_view())
std::string_view name = std::string_view())
: ModuleFieldMixin<ModuleFieldType::ElemSegment>(loc),
elem_segment(name) {}
@ -1018,7 +1130,7 @@ class ElemSegmentModuleField
class MemoryModuleField : public ModuleFieldMixin<ModuleFieldType::Memory> {
public:
explicit MemoryModuleField(const Location& loc = Location(),
string_view name = string_view())
std::string_view name = std::string_view())
: ModuleFieldMixin<ModuleFieldType::Memory>(loc), memory(name) {}
Memory memory;
@ -1028,7 +1140,7 @@ class DataSegmentModuleField
: public ModuleFieldMixin<ModuleFieldType::DataSegment> {
public:
explicit DataSegmentModuleField(const Location& loc = Location(),
string_view name = string_view())
std::string_view name = std::string_view())
: ModuleFieldMixin<ModuleFieldType::DataSegment>(loc),
data_segment(name) {}
@ -1038,7 +1150,7 @@ class DataSegmentModuleField
class TagModuleField : public ModuleFieldMixin<ModuleFieldType::Tag> {
public:
explicit TagModuleField(const Location& loc = Location(),
string_view name = string_view())
std::string_view name = std::string_view())
: ModuleFieldMixin<ModuleFieldType::Tag>(loc), tag(name) {}
Tag tag;
@ -1070,7 +1182,7 @@ struct Module {
Index GetGlobalIndex(const Var&) const;
const Global* GetGlobal(const Var&) const;
Global* GetGlobal(const Var&);
const Export* GetExport(string_view) const;
const Export* GetExport(std::string_view) const;
Tag* GetTag(const Var&) const;
Index GetTagIndex(const Var&) const;
const DataSegment* GetDataSegment(const Var&) const;
@ -1185,8 +1297,8 @@ class DataScriptModule : public ScriptModuleMixin<TypeEnum> {
std::vector<uint8_t> data;
};
typedef DataScriptModule<ScriptModuleType::Binary> BinaryScriptModule;
typedef DataScriptModule<ScriptModuleType::Quoted> QuotedScriptModule;
using BinaryScriptModule = DataScriptModule<ScriptModuleType::Binary>;
using QuotedScriptModule = DataScriptModule<ScriptModuleType::Quoted>;
enum class ActionType {
Invoke,
@ -1212,7 +1324,7 @@ class Action {
ActionType type_;
};
typedef std::unique_ptr<Action> ActionPtr;
using ActionPtr = std::unique_ptr<Action>;
template <ActionType TypeEnum>
class ActionMixin : public Action {
@ -1241,6 +1353,7 @@ class InvokeAction : public ActionMixin<ActionType::Invoke> {
enum class CommandType {
Module,
ScriptModule,
Action,
Register,
AssertMalformed,
@ -1250,11 +1363,12 @@ enum class CommandType {
AssertReturn,
AssertTrap,
AssertExhaustion,
AssertException,
First = Module,
Last = AssertExhaustion,
Last = AssertException,
};
static const int kCommandTypeCount = WABT_ENUM_COUNT(CommandType);
constexpr int kCommandTypeCount = WABT_ENUM_COUNT(CommandType);
class Command {
public:
@ -1280,17 +1394,26 @@ class ModuleCommand : public CommandMixin<CommandType::Module> {
Module module;
};
class ScriptModuleCommand : public CommandMixin<CommandType::ScriptModule> {
public:
// Both the module and the script_module need to be stored since the module
// has the parsed information about the module, but the script_module has the
// original contents (binary or quoted).
Module module;
std::unique_ptr<ScriptModule> script_module;
};
template <CommandType TypeEnum>
class ActionCommandBase : public CommandMixin<TypeEnum> {
public:
ActionPtr action;
};
typedef ActionCommandBase<CommandType::Action> ActionCommand;
using ActionCommand = ActionCommandBase<CommandType::Action>;
class RegisterCommand : public CommandMixin<CommandType::Register> {
public:
RegisterCommand(string_view module_name, const Var& var)
RegisterCommand(std::string_view module_name, const Var& var)
: module_name(module_name), var(var) {}
std::string module_name;
@ -1300,7 +1423,7 @@ class RegisterCommand : public CommandMixin<CommandType::Register> {
class AssertReturnCommand : public CommandMixin<CommandType::AssertReturn> {
public:
ActionPtr action;
ConstVector expected;
ExpectationPtr expected;
};
template <CommandType TypeEnum>
@ -1310,9 +1433,9 @@ class AssertTrapCommandBase : public CommandMixin<TypeEnum> {
std::string text;
};
typedef AssertTrapCommandBase<CommandType::AssertTrap> AssertTrapCommand;
typedef AssertTrapCommandBase<CommandType::AssertExhaustion>
AssertExhaustionCommand;
using AssertTrapCommand = AssertTrapCommandBase<CommandType::AssertTrap>;
using AssertExhaustionCommand =
AssertTrapCommandBase<CommandType::AssertExhaustion>;
template <CommandType TypeEnum>
class AssertModuleCommand : public CommandMixin<TypeEnum> {
@ -1321,16 +1444,22 @@ class AssertModuleCommand : public CommandMixin<TypeEnum> {
std::string text;
};
typedef AssertModuleCommand<CommandType::AssertMalformed>
AssertMalformedCommand;
typedef AssertModuleCommand<CommandType::AssertInvalid> AssertInvalidCommand;
typedef AssertModuleCommand<CommandType::AssertUnlinkable>
AssertUnlinkableCommand;
typedef AssertModuleCommand<CommandType::AssertUninstantiable>
AssertUninstantiableCommand;
using AssertMalformedCommand =
AssertModuleCommand<CommandType::AssertMalformed>;
using AssertInvalidCommand = AssertModuleCommand<CommandType::AssertInvalid>;
using AssertUnlinkableCommand =
AssertModuleCommand<CommandType::AssertUnlinkable>;
using AssertUninstantiableCommand =
AssertModuleCommand<CommandType::AssertUninstantiable>;
typedef std::unique_ptr<Command> CommandPtr;
typedef std::vector<CommandPtr> CommandPtrVector;
class AssertExceptionCommand
: public CommandMixin<CommandType::AssertException> {
public:
ActionPtr action;
};
using CommandPtr = std::unique_ptr<Command>;
using CommandPtrVector = std::vector<CommandPtr>;
struct Script {
WABT_DISALLOW_COPY_AND_ASSIGN(Script);

View File

@ -19,7 +19,7 @@
#include <cstdint>
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {

View File

@ -21,9 +21,9 @@
#include <string>
#include <vector>
#include "src/common.h"
#include "src/lexer-source.h"
#include "src/range.h"
#include "wabt/common.h"
#include "wabt/lexer-source.h"
#include "wabt/range.h"
namespace wabt {

View File

@ -22,8 +22,8 @@
#include <string>
#include <vector>
#include "src/common.h"
#include "src/range.h"
#include "wabt/common.h"
#include "wabt/range.h"
namespace wabt {

View File

@ -19,7 +19,7 @@
#include <cstdint>
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {
@ -75,6 +75,51 @@ Result ParseDouble(LiteralType literal_type,
const char* end,
uint64_t* out_bits);
// Same as above but taking a string_view
inline Result ParseInt8(std::string_view v,
uint8_t* out,
ParseIntType parse_type) {
return ParseInt8(v.data(), v.data() + v.size(), out, parse_type);
}
inline Result ParseInt16(std::string_view v,
uint16_t* out,
ParseIntType parse_type) {
return ParseInt16(v.data(), v.data() + v.size(), out, parse_type);
}
inline Result ParseInt32(std::string_view v,
uint32_t* out,
ParseIntType parse_type) {
return ParseInt32(v.data(), v.data() + v.size(), out, parse_type);
}
inline Result ParseInt64(std::string_view v,
uint64_t* out,
ParseIntType parse_type) {
return ParseInt64(v.data(), v.data() + v.size(), out, parse_type);
}
inline Result ParseUint64(std::string_view v, uint64_t* out) {
return ParseUint64(v.data(), v.data() + v.size(), out);
}
inline Result ParseUint128(std::string_view v, v128* out) {
return ParseUint128(v.data(), v.data() + v.size(), out);
}
inline Result ParseFloat(LiteralType literal_type,
std::string_view v,
uint32_t* out_bits) {
return ParseFloat(literal_type, v.data(), v.data() + v.size(), out_bits);
}
inline Result ParseDouble(LiteralType literal_type,
std::string_view v,
uint64_t* out_bits) {
return ParseDouble(literal_type, v.data(), v.data() + v.size(), out_bits);
}
void WriteFloatHex(char* buffer, size_t size, uint32_t bits);
void WriteDoubleHex(char* buffer, size_t size, uint64_t bits);
void WriteUint128(char* buffer, size_t size, v128 bits);

View File

@ -17,14 +17,19 @@
#ifndef WABT_OPCODE_CODE_TABLE_H_
#define WABT_OPCODE_CODE_TABLE_H_
#include <stdlib.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#define WABT_OPCODE_CODE_TABLE_SIZE 65536
#define WABT_OPCODE_CODE_TABLE_SIZE 131072
/*
* Number of bits required to store an opcode
*/
#define MAX_OPCODE_BITS 9
/* This structure is defined in C because C++ doesn't (yet) allow you to use
* designated array initializers, i.e. [10] = {foo}.

View File

@ -231,6 +231,8 @@ WABT_OPCODE(___, I32, ___, ___, 0, 0, 0xe1, InterpBrUnless, "br_unless",
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe2, InterpCallImport, "call_import", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe3, InterpData, "data", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe4, InterpDropKeep, "drop_keep", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe5, InterpCatchDrop, "catch_drop", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe6, InterpAdjustFrameForReturnCall, "adjust_frame_for_return_call", "")
/* Saturating float-to-int opcodes (--enable-saturating-float-to-int) */
WABT_OPCODE(I32, F32, ___, ___, 0, 0xfc, 0x00, I32TruncSatF32S, "i32.trunc_sat_f32_s", "")
@ -242,7 +244,7 @@ WABT_OPCODE(I64, F32, ___, ___, 0, 0xfc, 0x05, I64TruncSatF32U, "i64.trunc_
WABT_OPCODE(I64, F64, ___, ___, 0, 0xfc, 0x06, I64TruncSatF64S, "i64.trunc_sat_f64_s", "")
WABT_OPCODE(I64, F64, ___, ___, 0, 0xfc, 0x07, I64TruncSatF64U, "i64.trunc_sat_f64_u", "")
/* Bulk-memory (--enable-bulk-memory) */
/* Bulk-memory */
WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x08, MemoryInit, "memory.init", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0xfc, 0x09, DataDrop, "data.drop", "")
WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x0a, MemoryCopy,"memory.copy", "")
@ -251,7 +253,7 @@ WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x0c, TableInit, "table.init", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0xfc, 0x0d, ElemDrop, "elem.drop", "")
WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x0e, TableCopy, "table.copy", "")
/* Reference types (--enable-reference-types) */
/* Reference types */
WABT_OPCODE(___, I32, ___, ___, 0, 0, 0x25, TableGet, "table.get", "")
WABT_OPCODE(___, I32, ___, ___, 0, 0, 0x26, TableSet, "table.set", "")
WABT_OPCODE(___, ___, I32, ___, 0, 0xfc, 0x0f, TableGrow, "table.grow", "")
@ -499,6 +501,28 @@ WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xfd, I32X4TruncSatF64X2UZero, "i3
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xfe, F64X2ConvertLowI32X4S, "f64x2.convert_low_i32x4_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xff, F64X2ConvertLowI32X4U, "f64x2.convert_low_i32x4_u", "")
/* Relaxed-SIMD opcodes */
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x100, I8X16RelaxedSwizzle, "i8x16.relaxed_swizzle", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x101, I32X4RelaxedTruncF32X4S, "i32x4.relaxed_trunc_f32x4_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x102, I32X4RelaxedTruncF32X4U, "i32x4.relaxed_trunc_f32x4_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x103, I32X4RelaxedTruncF64X2SZero, "i32x4.relaxed_trunc_f64x2_s_zero", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x104, I32X4RelaxedTruncF64X2UZero, "i32x4.relaxed_trunc_f64x2_u_zero", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x105, F32X4RelaxedMadd, "f32x4.relaxed_madd", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x106, F32X4RelaxedNmadd, "f32x4.relaxed_nmadd", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x107, F64X2RelaxedMadd, "f64x2.relaxed_madd", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x108, F64X2RelaxedNmadd, "f64x2.relaxed_nmadd", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x109, I8X16RelaxedLaneSelect, "i8x16.relaxed_laneselect", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x10a, I16X8RelaxedLaneSelect, "i16x8.relaxed_laneselect", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x10b, I32X4RelaxedLaneSelect, "i32x4.relaxed_laneselect", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x10c, I64X2RelaxedLaneSelect, "i64x2.relaxed_laneselect", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x10d, F32X4RelaxedMin, "f32x4.relaxed_min", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x10e, F32X4RelaxedMax, "f32x4.relaxed_max", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x10f, F64X2RelaxedMin, "f64x2.relaxed_min", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x110, F64X2RelaxedMax, "f64x2.relaxed_max", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x111, I16X8RelaxedQ15mulrS, "i16x8.relaxed_q15mulr_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x112, I16X8DotI8X16I7X16S, "i16x8.dot_i8x16_i7x16_s", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x113, I32X4DotI8X16I7X16AddS, "i32x4.dot_i8x16_i7x16_add_s", "")
/* Thread opcodes (--enable-threads) */
WABT_OPCODE(I32, I32, I32, ___, 4, 0xfe, 0x00, MemoryAtomicNotify, "memory.atomic.notify", "")
WABT_OPCODE(I32, I32, I32, I64, 4, 0xfe, 0x01, MemoryAtomicWait32, "memory.atomic.wait32", "")

View File

@ -19,9 +19,9 @@
#include <vector>
#include "src/common.h"
#include "src/opcode-code-table.h"
#include "src/leb128.h"
#include "wabt/common.h"
#include "wabt/leb128.h"
#include "wabt/opcode-code-table.h"
namespace wabt {
@ -36,7 +36,7 @@ struct Opcode {
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
Name,
#include "src/opcode.def"
#include "wabt/opcode.def"
#undef WABT_OPCODE
Invalid,
};
@ -45,7 +45,7 @@ struct Opcode {
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
static Opcode Name##_Opcode;
#include "src/opcode.def"
#include "wabt/opcode.def"
#undef WABT_OPCODE
Opcode() = default; // Provided so Opcode can be member of a union.
@ -69,14 +69,6 @@ struct Opcode {
Type GetParamType(int n) const { return GetInfo().param_types[n - 1]; }
Address GetMemorySize() const { return GetInfo().memory_size; }
// If this is a load/store op, the type depends on the memory used.
Type GetMemoryParam(Type param,
const Limits* limits,
bool has_address_operands) {
return limits && limits->is_64 && has_address_operands ? Type(Type::I64)
: param;
}
// Get the byte sequence for this opcode, including prefix.
std::vector<uint8_t> GetBytes() const;
@ -99,9 +91,9 @@ struct Opcode {
bool IsInvalid() const { return enum_ >= Invalid; }
private:
static const uint32_t kMathPrefix = 0xfc;
static const uint32_t kThreadsPrefix = 0xfe;
static const uint32_t kSimdPrefix = 0xfd;
static constexpr uint32_t kMathPrefix = 0xfc;
static constexpr uint32_t kThreadsPrefix = 0xfe;
static constexpr uint32_t kSimdPrefix = 0xfd;
struct Info {
const char* name;
@ -115,12 +107,11 @@ struct Opcode {
};
static uint32_t PrefixCode(uint8_t prefix, uint32_t code) {
// For now, 8 bits is enough for all codes.
if (code >= 0x100) {
// Clamp to 0xff, since we know that it is an invalid code.
code = 0xff;
if (code >= (1 << MAX_OPCODE_BITS)) {
// Clamp to (2^bits - 1), since we know that it is an invalid code.
code = (1 << MAX_OPCODE_BITS) - 1;
}
return (prefix << 8) | code;
return (prefix << MAX_OPCODE_BITS) | code;
}
// The Opcode struct only stores an enumeration (Opcode::Enum) of all valid
@ -145,7 +136,7 @@ struct Opcode {
uint8_t* out_prefix,
uint32_t* out_code) {
uint32_t prefix_code = ~static_cast<uint32_t>(e) + 1;
*out_prefix = prefix_code >> 8;
*out_prefix = prefix_code >> MAX_OPCODE_BITS;
*out_code = prefix_code & 0xff;
}
@ -176,7 +167,6 @@ inline Opcode Opcode::FromCode(uint8_t prefix, uint32_t code) {
return Opcode(EncodeInvalidOpcode(prefix_code));
}
} // namespace wabt
#endif // WABT_OPCODE_H_

View File

@ -21,7 +21,7 @@
#include <string>
#include <vector>
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {
@ -31,8 +31,8 @@ class OptionParser {
enum class ArgumentCount { One, OneOrMore, ZeroOrMore };
struct Option;
typedef std::function<void(const char*)> Callback;
typedef std::function<void()> NullCallback;
using Callback = std::function<void(const char*)>;
using NullCallback = std::function<void()>;
struct Option {
Option(char short_name,

View File

@ -29,8 +29,8 @@ struct Range {
T size() const { return end - start; }
};
typedef Range<Offset> OffsetRange;
typedef Range<int> ColumnRange;
using OffsetRange = Range<Offset>;
using ColumnRange = Range<int>;
} // namespace wabt

View File

@ -17,8 +17,8 @@
#ifndef WABT_RESOLVE_NAMES_H_
#define WABT_RESOLVE_NAMES_H_
#include "src/common.h"
#include "src/error.h"
#include "wabt/common.h"
#include "wabt/error.h"
namespace wabt {

View File

@ -14,28 +14,18 @@
* limitations under the License.
*/
#ifndef WABT_C_WRITER_H_
#define WABT_C_WRITER_H_
#ifndef WABT_SHA256_H_
#define WABT_SHA256_H_
#include "src/common.h"
#include "wabt/config.h"
#include <string>
#include <string_view>
namespace wabt {
struct Module;
class Stream;
struct WriteCOptions {
std::string mod_name;
};
Result WriteC(Stream* c_stream,
Stream* h_stream,
const char* header_name,
const Module*,
const WriteCOptions&);
void sha256(std::string_view input, std::string& digest);
} // namespace wabt
#endif /* WABT_C_WRITER_H_ */
#endif // WABT_SHA256_H_

View File

@ -22,14 +22,14 @@
#include <string>
#include <vector>
#include "src/common.h"
#include "src/error.h"
#include "src/feature.h"
#include "src/ir.h"
#include "src/opcode.h"
#include "src/type-checker.h"
#include "wabt/common.h"
#include "wabt/error.h"
#include "wabt/feature.h"
#include "wabt/ir.h"
#include "wabt/opcode.h"
#include "wabt/type-checker.h"
#include "src/binary-reader.h" // For TypeMut.
#include "wabt/binary-reader.h" // For TypeMut.
namespace wabt {
@ -51,6 +51,9 @@ class SharedValidator {
Result GetLabel(Index depth, Label** out_label) {
return typechecker_.GetLabel(depth, out_label);
}
Result GetCatchCount(Index depth, Index* out_count) {
return typechecker_.GetCatchCount(depth, out_count);
}
Result WABT_PRINTF_FORMAT(3, 4)
PrintError(const Location& loc, const char* fmt, ...);
@ -65,7 +68,8 @@ class SharedValidator {
Index param_count,
const Type* param_types,
Index result_count,
const Type* result_types);
const Type* result_types,
Index type_index);
Result OnStructType(const Location&, Index field_count, TypeMut* fields);
Result OnArrayType(const Location&, TypeMut field);
@ -74,47 +78,38 @@ class SharedValidator {
Result OnMemory(const Location&, const Limits&);
Result OnGlobalImport(const Location&, Type type, bool mutable_);
Result OnGlobal(const Location&, Type type, bool mutable_);
Result OnGlobalInitExpr_Const(const Location&, Type);
Result OnGlobalInitExpr_GlobalGet(const Location&, Var global_var);
Result OnGlobalInitExpr_RefNull(const Location&, Type type);
Result OnGlobalInitExpr_RefFunc(const Location&, Var func_var);
Result OnGlobalInitExpr_Other(const Location&);
Result OnTag(const Location&, Var sig_var);
Result OnExport(const Location&,
ExternalKind,
Var item_var,
string_view name);
std::string_view name);
Result OnStart(const Location&, Var func_var);
Result OnElemSegment(const Location&, Var table_var, SegmentKind);
void OnElemSegmentElemType(Type elem_type);
Result OnElemSegmentInitExpr_Const(const Location&, Type);
Result OnElemSegmentInitExpr_GlobalGet(const Location&, Var global_var);
Result OnElemSegmentInitExpr_Other(const Location&);
Result OnElemSegmentElemType(const Location&, Type elem_type);
Result OnElemSegmentElemExpr_RefNull(const Location&, Type type);
Result OnElemSegmentElemExpr_RefFunc(const Location&, Var func_var);
Result OnElemSegmentElemExpr_Other(const Location&);
void OnDataCount(Index count);
Result OnDataSegment(const Location&, Var memory_var, SegmentKind);
Result OnDataSegmentInitExpr_Const(const Location&, Type);
Result OnDataSegmentInitExpr_GlobalGet(const Location&, Var global_var);
Result OnDataSegmentInitExpr_Other(const Location&);
Result BeginInitExpr(const Location&, Type type);
Result EndInitExpr();
Result BeginFunctionBody(const Location&, Index func_index);
Result EndFunctionBody(const Location&);
Result OnLocalDecl(const Location&, Index count, Type type);
Result OnAtomicFence(const Location&, uint32_t consistency_model);
Result OnAtomicLoad(const Location&, Opcode, Address align);
Result OnAtomicNotify(const Location&, Opcode, Address align);
Result OnAtomicRmwCmpxchg(const Location&, Opcode, Address align);
Result OnAtomicRmw(const Location&, Opcode, Address align);
Result OnAtomicStore(const Location&, Opcode, Address align);
Result OnAtomicWait(const Location&, Opcode, Address align);
Result OnAtomicLoad(const Location&, Opcode, Var memidx, Address align);
Result OnAtomicNotify(const Location&, Opcode, Var memidx, Address align);
Result OnAtomicRmwCmpxchg(const Location&, Opcode, Var memidx, Address align);
Result OnAtomicRmw(const Location&, Opcode, Var memidx, Address align);
Result OnAtomicStore(const Location&, Opcode, Var memidx, Address align);
Result OnAtomicWait(const Location&, Opcode, Var memidx, Address align);
Result OnBinary(const Location&, Opcode);
Result OnBlock(const Location&, Type sig_type);
Result OnBr(const Location&, Var depth);
@ -138,18 +133,18 @@ class SharedValidator {
Result OnGlobalGet(const Location&, Var);
Result OnGlobalSet(const Location&, Var);
Result OnIf(const Location&, Type sig_type);
Result OnLoad(const Location&, Opcode, Address align);
Result OnLoadSplat(const Location&, Opcode, Address align);
Result OnLoadZero(const Location&, Opcode, Address align);
Result OnLoad(const Location&, Opcode, Var memidx, Address align);
Result OnLoadSplat(const Location&, Opcode, Var memidx, Address align);
Result OnLoadZero(const Location&, Opcode, Var memidx, Address align);
Result OnLocalGet(const Location&, Var);
Result OnLocalSet(const Location&, Var);
Result OnLocalTee(const Location&, Var);
Result OnLoop(const Location&, Type sig_type);
Result OnMemoryCopy(const Location&);
Result OnMemoryFill(const Location&);
Result OnMemoryGrow(const Location&);
Result OnMemoryInit(const Location&, Var segment_var);
Result OnMemorySize(const Location&);
Result OnMemoryCopy(const Location&, Var srcmemidx, Var destmemidx);
Result OnMemoryFill(const Location&, Var memidx);
Result OnMemoryGrow(const Location&, Var memidx);
Result OnMemoryInit(const Location&, Var segment_var, Var memidx);
Result OnMemorySize(const Location&, Var memidx);
Result OnNop(const Location&);
Result OnRefFunc(const Location&, Var func_var);
Result OnRefIsNull(const Location&);
@ -160,10 +155,18 @@ class SharedValidator {
Result OnReturn(const Location&);
Result OnSelect(const Location&, Index result_count, Type* result_types);
Result OnSimdLaneOp(const Location&, Opcode, uint64_t lane_idx);
Result OnSimdLoadLane(const Location&, Opcode, Address align, uint64_t lane_idx);
Result OnSimdStoreLane(const Location&, Opcode, Address align, uint64_t lane_idx);
Result OnSimdLoadLane(const Location&,
Opcode,
Var memidx,
Address align,
uint64_t lane_idx);
Result OnSimdStoreLane(const Location&,
Opcode,
Var memidx,
Address align,
uint64_t lane_idx);
Result OnSimdShuffleOp(const Location&, Opcode, v128 lane_idx);
Result OnStore(const Location&, Opcode, Address align);
Result OnStore(const Location&, Opcode, Var memidx, Address align);
Result OnTableCopy(const Location&, Var dst_var, Var src_var);
Result OnTableFill(const Location&, Var table_var);
Result OnTableGet(const Location&, Var table_var);
@ -180,11 +183,14 @@ class SharedValidator {
private:
struct FuncType {
FuncType() = default;
FuncType(const TypeVector& params, const TypeVector& results)
: params(params), results(results) {}
FuncType(const TypeVector& params,
const TypeVector& results,
Index type_index)
: params(params), results(results), type_index(type_index) {}
TypeVector params;
TypeVector results;
Index type_index;
};
struct StructType {
@ -230,9 +236,12 @@ class SharedValidator {
struct ElemType {
ElemType() = default;
ElemType(Type element) : element(element) {}
ElemType(Type element, bool is_active, Type table_type)
: element(element), is_active(is_active), table_type(table_type) {}
Type element;
bool is_active;
Type table_type;
};
struct LocalDecl {
@ -240,6 +249,8 @@ class SharedValidator {
Index end;
};
bool ValidInitOpcode(Opcode opcode) const;
Result CheckInstr(Opcode opcode, const Location& loc);
Result CheckType(const Location&,
Type actual,
Type expected,
@ -269,7 +280,9 @@ class SharedValidator {
Result CheckDataSegmentIndex(Var data_segment_var);
Result CheckAlign(const Location&, Address align, Address natural_align);
Result CheckAtomicAlign(const Location&, Address align, Address natural_align);
Result CheckAtomicAlign(const Location&,
Address align,
Address natural_align);
Result CheckBlockSignature(const Location&,
Opcode,
@ -277,13 +290,16 @@ class SharedValidator {
TypeVector* out_param_types,
TypeVector* out_result_types);
Index GetFunctionTypeIndex(Index func_index) const;
TypeVector ToTypeVector(Index count, const Type* types);
ValidateOptions options_;
Errors* errors_;
TypeChecker typechecker_; // TODO: Move into SharedValidator.
// Cached for access by OnTypecheckerError.
const Location* expr_loc_ = nullptr;
Location expr_loc_ = Location(kInvalidOffset);
bool in_init_expr_ = false;
Index num_types_ = 0;
std::map<Index, FuncType> func_types_;
@ -306,7 +322,7 @@ class SharedValidator {
std::set<std::string> export_names_; // Used to check for duplicates.
std::set<Index> declared_funcs_; // TODO: optimize?
std::vector<Var> init_expr_funcs_;
std::vector<Var> check_declared_funcs_;
};
} // namespace wabt

View File

@ -21,7 +21,7 @@
#include <memory>
#include <vector>
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {
@ -158,7 +158,8 @@ class Stream {
};
struct OutputBuffer {
Result WriteToFile(string_view filename) const;
Result WriteToFile(std::string_view filename) const;
Result WriteToStdout() const;
void clear() { data.clear(); }
size_t size() const { return data.size(); }
@ -169,6 +170,7 @@ struct OutputBuffer {
class MemoryStream : public Stream {
public:
WABT_DISALLOW_COPY_AND_ASSIGN(MemoryStream);
MemoryStream(MemoryStream&&) = default;
explicit MemoryStream(Stream* log_stream = nullptr);
explicit MemoryStream(std::unique_ptr<OutputBuffer>&&,
Stream* log_stream = nullptr);
@ -178,7 +180,7 @@ class MemoryStream : public Stream {
void Clear();
Result WriteToFile(string_view filename) {
Result WriteToFile(std::string_view filename) {
return buf_->WriteToFile(filename);
}
@ -196,7 +198,7 @@ class MemoryStream : public Stream {
class FileStream : public Stream {
public:
WABT_DISALLOW_COPY_AND_ASSIGN(FileStream);
explicit FileStream(string_view filename, Stream* log_stream = nullptr);
explicit FileStream(std::string_view filename, Stream* log_stream = nullptr);
explicit FileStream(FILE*, Stream* log_stream = nullptr);
FileStream(FileStream&&);
FileStream& operator=(FileStream&&);

View File

@ -0,0 +1,68 @@
/*
* Copyright 2021 WebAssembly Community Group participants
*
* 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 WABT_STRING_FORMAT_H_
#define WABT_STRING_FORMAT_H_
#include <cstdarg>
#include <string>
#include <vector>
#include "wabt/config.h"
#define PRIstringview "%.*s"
#define WABT_PRINTF_STRING_VIEW_ARG(x) \
static_cast<int>((x).length()), (x).data()
#define PRItypecode "%s%#x"
#define WABT_PRINTF_TYPE_CODE(x) \
(static_cast<int32_t>(x) < 0 ? "-" : ""), std::abs(static_cast<int32_t>(x))
#define WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128
#define WABT_SNPRINTF_ALLOCA(buffer, len, format) \
va_list args; \
va_list args_copy; \
va_start(args, format); \
va_copy(args_copy, args); \
char fixed_buf[WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE]; \
char* buffer = fixed_buf; \
size_t len = wabt_vsnprintf(fixed_buf, sizeof(fixed_buf), format, args); \
va_end(args); \
if (len + 1 > sizeof(fixed_buf)) { \
buffer = static_cast<char*>(alloca(len + 1)); \
len = wabt_vsnprintf(buffer, len + 1, format, args_copy); \
} \
va_end(args_copy)
namespace wabt {
inline std::string WABT_PRINTF_FORMAT(1, 2)
StringPrintf(const char* format, ...) {
va_list args;
va_list args_copy;
va_start(args, format);
va_copy(args_copy, args);
size_t len = wabt_vsnprintf(nullptr, 0, format, args) + 1; // For \0.
std::vector<char> buffer(len);
va_end(args);
wabt_vsnprintf(buffer.data(), len, format, args_copy);
va_end(args_copy);
return std::string(buffer.data(), len - 1);
}
} // namespace wabt
#endif // WABT_STRING_FORMAT_H_

View File

@ -0,0 +1,82 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* 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 WABT_STRING_UTIL_H_
#define WABT_STRING_UTIL_H_
#include <string>
#include <string_view>
namespace wabt {
inline std::string& operator+=(std::string& x, std::string_view y) {
x.append(y.data(), y.size());
return x;
}
inline std::string operator+(std::string_view x, std::string_view y) {
std::string s;
s.reserve(x.size() + y.size());
s.append(x.data(), x.size());
s.append(y.data(), y.size());
return s;
}
inline std::string operator+(const std::string& x, std::string_view y) {
return std::string_view(x) + y;
}
inline std::string operator+(std::string_view x, const std::string& y) {
return x + std::string_view(y);
}
inline std::string operator+(const char* x, std::string_view y) {
return std::string_view(x) + y;
}
inline std::string operator+(std::string_view x, const char* y) {
return x + std::string_view(y);
}
inline void cat_concatenate(std::string&) {}
template <typename T, typename... Ts>
void cat_concatenate(std::string& s, const T& t, const Ts&... args) {
s += t;
cat_concatenate(s, args...);
}
inline size_t cat_compute_size() {
return 0;
}
template <typename T, typename... Ts>
size_t cat_compute_size(const T& t, const Ts&... args) {
return std::string_view(t).size() + cat_compute_size(args...);
}
// Is able to concatenate any combination of string/string_view/char*
template <typename... Ts>
std::string cat(const Ts&... args) {
std::string s;
s.reserve(cat_compute_size(args...));
cat_concatenate(s, args...);
return s;
}
} // namespace wabt
#endif // WABT_STRING_UTIL_H_

View File

@ -21,6 +21,7 @@
/* Tokens with no additional data (i.e. bare). */
WABT_TOKEN(Invalid, "Invalid")
WABT_TOKEN(Array, "array")
WABT_TOKEN(AssertException, "assert_exception")
WABT_TOKEN(AssertExhaustion, "assert_exhaustion")
WABT_TOKEN(AssertInvalid, "assert_invalid")
WABT_TOKEN(AssertMalformed, "assert_malformed")
@ -33,6 +34,7 @@ WABT_TOKEN(Data, "data")
WABT_TOKEN(Declare, "declare")
WABT_TOKEN(Delegate, "delegate")
WABT_TOKEN(Do, "do")
WABT_TOKEN(Either, "either")
WABT_TOKEN(Elem, "elem")
WABT_TOKEN(Eof, "EOF")
WABT_TOKEN(Tag, "tag")
@ -53,6 +55,7 @@ WABT_TOKEN(NanCanonical, "nan:canonical")
WABT_TOKEN(Offset, "offset")
WABT_TOKEN(Output, "output")
WABT_TOKEN(Param, "param")
WABT_TOKEN(Ref, "ref")
WABT_TOKEN(Quote, "quote")
WABT_TOKEN(Register, "register")
WABT_TOKEN(Result, "result")

View File

@ -17,25 +17,26 @@
#ifndef WABT_TOKEN_H_
#define WABT_TOKEN_H_
#include "src/literal.h"
#include "src/opcode.h"
#include "src/string-view.h"
#include <string_view>
#include "wabt/literal.h"
#include "wabt/opcode.h"
namespace wabt {
struct Literal {
Literal() = default;
Literal(LiteralType type, string_view text) : type(type), text(text) {}
Literal(LiteralType type, std::string_view text) : type(type), text(text) {}
LiteralType type;
string_view text;
std::string_view text;
};
enum class TokenType {
#define WABT_TOKEN(name, string) name,
#define WABT_TOKEN_FIRST(group, first) First_##group = first,
#define WABT_TOKEN_LAST(group, last) Last_##group = last,
#include "token.def"
#include "wabt/token.def"
#undef WABT_TOKEN
#undef WABT_TOKEN_FIRST
#undef WABT_TOKEN_LAST
@ -79,7 +80,7 @@ struct Token {
Token() : token_type_(TokenType::Invalid) {}
Token(Location, TokenType);
Token(Location, TokenType, Type);
Token(Location, TokenType, string_view);
Token(Location, TokenType, std::string_view);
Token(Location, TokenType, Opcode);
Token(Location, TokenType, const Literal&);
@ -94,7 +95,7 @@ struct Token {
bool HasOpcode() const { return IsTokenTypeOpcode(token_type_); }
bool HasLiteral() const { return IsTokenTypeLiteral(token_type_); }
string_view text() const {
std::string_view text() const {
assert(HasText());
return text_;
}
@ -121,7 +122,7 @@ struct Token {
TokenType token_type_;
union {
string_view text_;
std::string_view text_;
Type type_;
Opcode opcode_;
Literal literal_;

View File

@ -29,7 +29,7 @@
#define WABT_TRACING 0
#endif
#include "src/common.h"
#include "wabt/common.h"
namespace wabt {

View File

@ -20,15 +20,15 @@
#include <functional>
#include <vector>
#include "src/common.h"
#include "src/feature.h"
#include "src/opcode.h"
#include "wabt/common.h"
#include "wabt/feature.h"
#include "wabt/opcode.h"
namespace wabt {
class TypeChecker {
public:
typedef std::function<void(const char* msg)> ErrorCallback;
using ErrorCallback = std::function<void(const char* msg)>;
struct Label {
Label(LabelType,
@ -58,6 +58,7 @@ class TypeChecker {
bool IsUnreachable();
Result GetLabel(Index depth, Label** out_label);
Result GetRethrowLabel(Index depth, Label** out_label);
Result GetCatchCount(Index depth, Index* out_depth);
Result BeginFunction(const TypeVector& sig);
Result OnAtomicFence(uint32_t consistency_model);
@ -77,9 +78,11 @@ class TypeChecker {
Result OnCall(const TypeVector& param_types, const TypeVector& result_types);
Result OnCallIndirect(const TypeVector& param_types,
const TypeVector& result_types);
Result OnFuncRef(Index* out_index);
Result OnReturnCall(const TypeVector& param_types, const TypeVector& result_types);
Result OnReturnCallIndirect(const TypeVector& param_types, const TypeVector& result_types);
Result OnIndexedFuncRef(Index* out_index);
Result OnReturnCall(const TypeVector& param_types,
const TypeVector& result_types);
Result OnReturnCallIndirect(const TypeVector& param_types,
const TypeVector& result_types);
Result OnCatch(const TypeVector& sig);
Result OnCompare(Opcode);
Result OnConst(Type);
@ -96,7 +99,7 @@ class TypeChecker {
Result OnLocalSet(Type);
Result OnLocalTee(Type);
Result OnLoop(const TypeVector& param_types, const TypeVector& result_types);
Result OnMemoryCopy(const Limits& limits);
Result OnMemoryCopy(const Limits& srclimits, const Limits& dstlimits);
Result OnDataDrop(Index);
Result OnMemoryFill(const Limits& limits);
Result OnMemoryGrow(const Limits& limits);
@ -110,7 +113,7 @@ class TypeChecker {
Result OnTableGrow(Type elem_type);
Result OnTableSize();
Result OnTableFill(Type elem_type);
Result OnRefFuncExpr(Index func_index);
Result OnRefFuncExpr(Index func_type);
Result OnRefNullExpr(Type type);
Result OnRefIsNullExpr();
Result OnRethrow(Index depth);
@ -128,6 +131,9 @@ class TypeChecker {
Result OnUnreachable();
Result EndFunction();
Result BeginInitExpr(Type type);
Result EndInitExpr();
static Result CheckType(Type actual, Type expected);
private:
@ -140,17 +146,21 @@ class TypeChecker {
const TypeVector& result_types);
Result PopLabel();
Result CheckLabelType(Label* label, LabelType label_type);
Result Check2LabelTypes(Label* label, LabelType label_type1, LabelType label_type2);
Result GetThisFunctionLabel(Label **label);
Result Check2LabelTypes(Label* label,
LabelType label_type1,
LabelType label_type2);
Result GetThisFunctionLabel(Label** label);
Result PeekType(Index depth, Type* out_type);
Result PeekAndCheckType(Index depth, Type expected);
Result DropTypes(size_t drop_count);
void PushType(Type type);
void PushTypes(const TypeVector& types);
Result CheckTypeStackEnd(const char* desc);
Result CheckTypes(const TypeVector &actual, const TypeVector &expected);
Result CheckTypes(const TypeVector& actual, const TypeVector& expected);
Result CheckSignature(const TypeVector& sig, const char* desc);
Result CheckReturnSignature(const TypeVector& sig, const TypeVector &expected,const char *desc);
Result CheckReturnSignature(const TypeVector& sig,
const TypeVector& expected,
const char* desc);
Result PopAndCheckSignature(const TypeVector& sig, const char* desc);
Result PopAndCheckCall(const TypeVector& param_types,
const TypeVector& result_types,
@ -161,9 +171,7 @@ class TypeChecker {
Type expected2,
Type expected3,
const char* desc);
Result CheckOpcode1(Opcode opcode,
const Limits* limits = nullptr,
bool has_address_operands = false);
Result CheckOpcode1(Opcode opcode, const Limits* limits = nullptr);
Result CheckOpcode2(Opcode opcode, const Limits* limits = nullptr);
Result CheckOpcode3(Opcode opcode,
const Limits* limits1 = nullptr,
@ -176,11 +184,14 @@ class TypeChecker {
// Minor optimization, check result before constructing the vector to pass
// to the other overload of PrintStackIfFailed.
if (Failed(result)) {
PrintStackIfFailed(result, desc, {args...});
PrintStackIfFailedV(result, desc, {args...}, /*is_end=*/false);
}
}
void PrintStackIfFailed(Result, const char* desc, const TypeVector&);
void PrintStackIfFailedV(Result,
const char* desc,
const TypeVector&,
bool is_end);
ErrorCallback error_callback_;
TypeVector type_stack_;

View File

@ -21,13 +21,14 @@
#include <cstdint>
#include <vector>
#include "config.h"
#include "wabt/config.h"
#include "wabt/base-types.h"
#include "wabt/string-format.h"
namespace wabt {
class Type;
using Index = uint32_t;
using TypeVector = std::vector<Type>;
class Type {
@ -43,33 +44,41 @@ class Type {
I16 = -0x07, // 0x79 : packed-type only, used in gc and as v128 lane
FuncRef = -0x10, // 0x70
ExternRef = -0x11, // 0x6f
Reference = -0x15, // 0x6b
Func = -0x20, // 0x60
Struct = -0x21, // 0x5f
Array = -0x22, // 0x5e
Void = -0x40, // 0x40
___ = Void, // Convenient for the opcode table in opcode.h
Any = 0, // Not actually specified, but useful for type-checking
Any = 0, // Not actually specified, but useful for type-checking
I8U = 4, // Not actually specified, but used internally with load/store
I16U = 6, // Not actually specified, but used internally with load/store
I32U = 7, // Not actually specified, but used internally with load/store
};
Type() = default; // Provided so Type can be member of a union.
Type(int32_t code) : enum_(static_cast<Enum>(code)) {}
Type(Enum e) : enum_(e) {}
operator Enum() const { return enum_; }
Type(int32_t code)
: enum_(static_cast<Enum>(code)), type_index_(kInvalidIndex) {}
Type(Enum e) : enum_(e), type_index_(kInvalidIndex) {}
Type(Enum e, Index type_index) : enum_(e), type_index_(type_index) {
assert(e == Enum::Reference);
}
constexpr operator Enum() const { return enum_; }
bool IsRef() const {
return enum_ == Type::ExternRef || enum_ == Type::FuncRef;
return enum_ == Type::ExternRef || enum_ == Type::FuncRef ||
enum_ == Type::Reference;
}
bool IsReferenceWithIndex() const { return enum_ == Type::Reference; }
bool IsNullableRef() const {
// Currently all reftypes are nullable
return IsRef();
}
const char* GetName() const {
std::string GetName() const {
switch (enum_) {
case Type::I32: return "i32";
case Type::I64: return "i64";
@ -83,7 +92,10 @@ class Type {
case Type::Void: return "void";
case Type::Any: return "any";
case Type::ExternRef: return "externref";
default: return "<type_index>";
case Type::Reference:
return StringPrintf("(ref %d)", type_index_);
default:
return StringPrintf("<type_index[%d]>", enum_);
}
}
@ -108,7 +120,7 @@ class Type {
// (type $T (func (result i32 i64)))
// ...
// (block (type $T) ...)
//
//
bool IsIndex() const { return static_cast<int32_t>(enum_) >= 0; }
Index GetIndex() const {
@ -116,6 +128,11 @@ class Type {
return static_cast<Index>(enum_);
}
Index GetReferenceIndex() const {
assert(enum_ == Enum::Reference);
return type_index_;
}
TypeVector GetInlineVector() const {
assert(!IsIndex());
switch (enum_) {
@ -129,6 +146,7 @@ class Type {
case Type::V128:
case Type::FuncRef:
case Type::ExternRef:
case Type::Reference:
return TypeVector(this, this + 1);
default:
@ -138,6 +156,7 @@ class Type {
private:
Enum enum_;
Index type_index_; // Only used for for Type::Reference
};
} // namespace wabt

View File

@ -17,7 +17,7 @@
#ifndef WABT_UTF8_H_
#define WABT_UTF8_H_
#include <stdlib.h>
#include <cstddef>
namespace wabt {

View File

@ -17,9 +17,9 @@
#ifndef WABT_VALIDATOR_H_
#define WABT_VALIDATOR_H_
#include "src/error.h"
#include "src/feature.h"
#include "src/shared-validator.h"
#include "wabt/error.h"
#include "wabt/feature.h"
#include "wabt/shared-validator.h"
namespace wabt {
@ -33,4 +33,4 @@ Result ValidateModule(const Module*, Errors*, const ValidateOptions&);
} // namespace wabt
#endif // WABT_VALIDATOR_H_
#endif // WABT_VALIDATOR_H_

View File

@ -21,43 +21,45 @@
#include <cstdio>
#include <memory>
#include "src/common.h"
#include "src/lexer-source-line-finder.h"
#include "src/literal.h"
#include "src/make-unique.h"
#include "src/opcode.h"
#include "src/token.h"
#include "wabt/common.h"
#include "wabt/error.h"
#include "wabt/lexer-source-line-finder.h"
#include "wabt/literal.h"
#include "wabt/opcode.h"
#include "wabt/token.h"
namespace wabt {
class ErrorHandler;
class LexerSource;
class WastParser;
class WastLexer {
public:
WABT_DISALLOW_COPY_AND_ASSIGN(WastLexer);
WastLexer(std::unique_ptr<LexerSource> source, string_view filename);
WastLexer(std::unique_ptr<LexerSource> source,
std::string_view filename,
Errors*);
// Convenience functions.
static std::unique_ptr<WastLexer> CreateBufferLexer(string_view filename,
static std::unique_ptr<WastLexer> CreateBufferLexer(std::string_view filename,
const void* data,
size_t size);
size_t size,
Errors*);
Token GetToken(WastParser* parser);
Token GetToken();
// TODO(binji): Move this out of the lexer.
std::unique_ptr<LexerSourceLineFinder> MakeLineFinder() {
return MakeUnique<LexerSourceLineFinder>(source_->Clone());
return std::make_unique<LexerSourceLineFinder>(source_->Clone());
}
private:
static const int kEof = -1;
enum class CharClass { Reserved = 1, Keyword = 2, HexDigit = 4, Digit = 8 };
static constexpr int kEof = -1;
enum class CharClass { IdChar = 1, Keyword = 2, HexDigit = 4, Digit = 8 };
Location GetLocation();
string_view GetText(size_t offset = 0);
std::string_view GetText(size_t offset = 0);
Token BareToken(TokenType);
Token LiteralToken(TokenType, LiteralType);
@ -66,9 +68,9 @@ class WastLexer {
int PeekChar();
int ReadChar();
bool MatchChar(char);
bool MatchString(string_view);
bool MatchString(std::string_view);
void Newline();
bool ReadBlockComment(WastParser*); // Returns false if EOF.
bool ReadBlockComment(); // Returns false if EOF.
bool ReadLineComment(); // Returns false if EOF.
void ReadWhitespace();
@ -76,20 +78,24 @@ class WastLexer {
static bool IsDigit(int c) { return IsCharClass(c, CharClass::Digit); }
static bool IsHexDigit(int c) { return IsCharClass(c, CharClass::HexDigit); }
static bool IsKeyword(int c) { return IsCharClass(c, CharClass::Keyword); }
static bool IsReserved(int c) { return IsCharClass(c, CharClass::Reserved); }
static bool IsIdChar(int c) { return IsCharClass(c, CharClass::IdChar); }
bool ReadNum();
bool ReadHexNum();
int ReadReservedChars();
bool NoTrailingReservedChars() { return ReadReservedChars() == 0; }
enum class ReservedChars { None, Some, Id };
ReservedChars ReadReservedChars();
bool NoTrailingReservedChars() {
return ReadReservedChars() == ReservedChars::None;
}
void ReadSign();
Token GetStringToken(WastParser*);
Token GetStringToken();
Token GetNumberToken(TokenType);
Token GetHexNumberToken(TokenType);
Token GetInfToken();
Token GetNanToken();
Token GetNameEqNumToken(string_view name, TokenType);
Token GetIdToken();
Token GetNameEqNumToken(std::string_view name, TokenType);
Token GetIdChars();
Token GetKeywordToken();
Token GetReservedToken();
@ -101,6 +107,9 @@ class WastLexer {
const char* line_start_;
const char* token_start_;
const char* cursor_;
Errors* errors_;
void WABT_PRINTF_FORMAT(3, 4) Error(Location, const char* format, ...);
};
} // namespace wabt

View File

@ -18,13 +18,15 @@
#define WABT_WAST_PARSER_H_
#include <array>
#include <memory>
#include <unordered_map>
#include "src/circular-array.h"
#include "src/error.h"
#include "src/feature.h"
#include "src/intrusive-list.h"
#include "src/ir.h"
#include "src/wast-lexer.h"
#include "wabt/circular-array.h"
#include "wabt/error.h"
#include "wabt/feature.h"
#include "wabt/intrusive-list.h"
#include "wabt/ir.h"
#include "wabt/wast-lexer.h"
namespace wabt {
@ -35,7 +37,7 @@ struct WastParseOptions {
bool debug_parsing = false;
};
typedef std::array<TokenType, 2> TokenTypePair;
using TokenTypePair = std::array<TokenType, 2>;
class WastParser {
public:
@ -81,7 +83,7 @@ class WastParser {
TokenTypePair PeekPair();
// Returns true if the next token's type is equal to the parameter.
bool PeekMatch(TokenType);
bool PeekMatch(TokenType, size_t n = 0);
// Returns true if the next token's type is '(' and the following token is
// equal to the parameter.
@ -91,6 +93,9 @@ class WastParser {
// folded expressions, plain instructions and block instructions.
bool PeekMatchExpr();
// Returns true if the next two tokens are form reference type - (ref $t)
bool PeekMatchRefType();
// Returns true if the next token's type is equal to the parameter. If so,
// then the token is consumed.
bool Match(TokenType);
@ -110,7 +115,7 @@ class WastParser {
// token (used for printing better error messages).
void ConsumeIfLpar() { Match(TokenType::Lpar); }
typedef bool SynchronizeFunc(TokenTypePair pair);
using SynchronizeFunc = bool(*)(TokenTypePair pair);
// Attempt to synchronize the token stream by dropping tokens until the
// SynchronizeFunc returns true, or until a token limit is reached. This
@ -126,17 +131,20 @@ class WastParser {
Result ParseTextList(std::vector<uint8_t>* out_data);
bool ParseTextListOpt(std::vector<uint8_t>* out_data);
Result ParseVarList(VarVector* out_var_list);
bool ParseElemExprOpt(ElemExpr* out_elem_expr);
bool ParseElemExprListOpt(ElemExprVector* out_list);
bool ParseElemExprVarListOpt(ElemExprVector* out_list);
Result ParseValueType(Type* out_type);
Result ParseValueTypeList(TypeVector* out_type_list);
bool ParseElemExprOpt(ExprList* out_elem_expr);
bool ParseElemExprListOpt(ExprListVector* out_list);
bool ParseElemExprVarListOpt(ExprListVector* out_list);
Result ParseValueType(Var* out_type);
Result ParseValueTypeList(
TypeVector* out_type_list,
std::unordered_map<uint32_t, std::string>* type_names);
Result ParseRefKind(Type* out_type);
Result ParseRefType(Type* out_type);
bool ParseRefTypeOpt(Type* out_type);
Result ParseQuotedText(std::string* text);
Result ParseQuotedText(std::string* text, bool check_utf8 = true);
bool ParseOffsetOpt(Address* offset);
bool ParseAlignOpt(Address* align);
Result ParseMemidx(Location loc, Var* memidx);
Result ParseLimitsIndex(Limits*);
Result ParseLimits(Limits*);
Result ParseNat(uint64_t*, bool is_64);
@ -164,16 +172,23 @@ class WastParser {
Result ParseBoundValueTypeList(TokenType,
TypeVector*,
BindingHash*,
std::unordered_map<uint32_t, std::string>*,
Index binding_index_offset = 0);
Result ParseUnboundValueTypeList(TokenType, TypeVector*);
Result ParseResultList(TypeVector*);
Result ParseUnboundValueTypeList(TokenType,
TypeVector*,
std::unordered_map<uint32_t, std::string>*);
Result ParseResultList(TypeVector*,
std::unordered_map<uint32_t, std::string>*);
Result ParseInstrList(ExprList*);
Result ParseTerminatingInstrList(ExprList*);
Result ParseInstr(ExprList*);
Result ParseCodeMetadataAnnotation(ExprList*);
Result ParsePlainInstr(std::unique_ptr<Expr>*);
Result ParseF32(Const*, ConstType type);
Result ParseF64(Const*, ConstType type);
Result ParseConst(Const*, ConstType type);
Result ParseExpectedValues(ExpectationPtr*);
Result ParseEither(ConstVector*);
Result ParseExternref(Const*);
Result ParseExpectedNan(ExpectedNan* expected);
Result ParseConstList(ConstVector*, ConstType type);
@ -193,11 +208,22 @@ class WastParser {
template <typename T>
Result ParsePlainInstrVar(Location, std::unique_ptr<Expr>*);
template <typename T>
Result ParsePlainLoadStoreInstr(Location, Token, std::unique_ptr<Expr>*);
Result ParseMemoryInstrVar(Location, std::unique_ptr<Expr>*);
template <typename T>
Result ParseLoadStoreInstr(Location, Token, std::unique_ptr<Expr>*);
template <typename T>
Result ParseSIMDLoadStoreInstr(Location loc,
Token token,
std::unique_ptr<Expr>* out_expr);
template <typename T>
Result ParseMemoryExpr(Location, std::unique_ptr<Expr>*);
template <typename T>
Result ParseMemoryBinaryExpr(Location, std::unique_ptr<Expr>*);
Result ParseSimdLane(Location, uint64_t*);
Result ParseCommandList(Script*, CommandPtrVector*);
Result ParseCommand(Script*, CommandPtr*);
Result ParseAssertExceptionCommand(CommandPtr*);
Result ParseAssertExhaustionCommand(CommandPtr*);
Result ParseAssertInvalidCommand(CommandPtr*);
Result ParseAssertMalformedCommand(CommandPtr*);

View File

@ -17,7 +17,8 @@
#ifndef WABT_WAT_WRITER_H_
#define WABT_WAT_WRITER_H_
#include "src/common.h"
#include "wabt/common.h"
#include "wabt/feature.h"
namespace wabt {
@ -25,6 +26,9 @@ struct Module;
class Stream;
struct WriteWatOptions {
WriteWatOptions() = default;
WriteWatOptions(const Features& features) : features(features) {}
Features features;
bool fold_exprs = false; // Write folded expressions.
bool inline_export = false;
bool inline_import = false;

View File

@ -14,15 +14,16 @@
* limitations under the License.
*/
#include "src/apply-names.h"
#include "wabt/apply-names.h"
#include <cassert>
#include <cstdio>
#include <string_view>
#include <vector>
#include "src/expr-visitor.h"
#include "src/ir.h"
#include "src/string-view.h"
#include "wabt/cast.h"
#include "wabt/expr-visitor.h"
#include "wabt/ir.h"
namespace wabt {
@ -49,13 +50,18 @@ class NameApplier : public ExprVisitor::DelegateNop {
Result OnGlobalSetExpr(GlobalSetExpr*) override;
Result BeginIfExpr(IfExpr*) override;
Result EndIfExpr(IfExpr*) override;
Result OnLoadExpr(LoadExpr*) override;
Result OnLocalGetExpr(LocalGetExpr*) override;
Result OnLocalSetExpr(LocalSetExpr*) override;
Result OnLocalTeeExpr(LocalTeeExpr*) override;
Result BeginLoopExpr(LoopExpr*) override;
Result EndLoopExpr(LoopExpr*) override;
Result OnMemoryCopyExpr(MemoryCopyExpr*) override;
Result OnDataDropExpr(DataDropExpr*) override;
Result OnMemoryFillExpr(MemoryFillExpr*) override;
Result OnMemoryGrowExpr(MemoryGrowExpr*) override;
Result OnMemoryInitExpr(MemoryInitExpr*) override;
Result OnMemorySizeExpr(MemorySizeExpr*) override;
Result OnElemDropExpr(ElemDropExpr*) override;
Result OnTableCopyExpr(TableCopyExpr*) override;
Result OnTableInitExpr(TableInitExpr*) override;
@ -64,18 +70,21 @@ class NameApplier : public ExprVisitor::DelegateNop {
Result OnTableGrowExpr(TableGrowExpr*) override;
Result OnTableSizeExpr(TableSizeExpr*) override;
Result OnTableFillExpr(TableFillExpr*) override;
Result OnStoreExpr(StoreExpr*) override;
Result BeginTryExpr(TryExpr*) override;
Result EndTryExpr(TryExpr*) override;
Result OnCatchExpr(TryExpr*, Catch*) override;
Result OnDelegateExpr(TryExpr*) override;
Result OnThrowExpr(ThrowExpr*) override;
Result OnRethrowExpr(RethrowExpr*) override;
Result OnSimdLoadLaneExpr(SimdLoadLaneExpr*) override;
Result OnSimdStoreLaneExpr(SimdStoreLaneExpr*) override;
private:
void PushLabel(const std::string& label);
void PopLabel();
string_view FindLabelByVar(Var* var);
void UseNameForVar(string_view name, Var* var);
std::string_view FindLabelByVar(Var* var);
void UseNameForVar(std::string_view name, Var* var);
Result UseNameForFuncTypeVar(Var* var);
Result UseNameForFuncVar(Var* var);
Result UseNameForGlobalVar(Var* var);
@ -110,7 +119,7 @@ void NameApplier::PopLabel() {
labels_.pop_back();
}
string_view NameApplier::FindLabelByVar(Var* var) {
std::string_view NameApplier::FindLabelByVar(Var* var) {
if (var->is_name()) {
for (int i = labels_.size() - 1; i >= 0; --i) {
const std::string& label = labels_[i];
@ -118,16 +127,16 @@ string_view NameApplier::FindLabelByVar(Var* var) {
return label;
}
}
return string_view();
return std::string_view();
} else {
if (var->index() >= labels_.size()) {
return string_view();
return std::string_view();
}
return labels_[labels_.size() - 1 - var->index()];
}
}
void NameApplier::UseNameForVar(string_view name, Var* var) {
void NameApplier::UseNameForVar(std::string_view name, Var* var) {
if (var->is_name()) {
assert(name == var->name());
return;
@ -253,12 +262,34 @@ Result NameApplier::OnDataDropExpr(DataDropExpr* expr) {
return Result::Ok;
}
Result NameApplier::OnMemoryInitExpr(MemoryInitExpr* expr) {
CHECK_RESULT(UseNameForDataSegmentVar(&expr->var));
Result NameApplier::OnMemoryCopyExpr(MemoryCopyExpr* expr) {
CHECK_RESULT(UseNameForMemoryVar(&expr->srcmemidx));
CHECK_RESULT(UseNameForMemoryVar(&expr->destmemidx));
return Result::Ok;
}
Result NameApplier::OnElemDropExpr(ElemDropExpr* expr) {
Result NameApplier::OnMemoryFillExpr(MemoryFillExpr* expr) {
CHECK_RESULT(UseNameForMemoryVar(&expr->memidx));
return Result::Ok;
}
Result NameApplier::OnMemoryGrowExpr(MemoryGrowExpr* expr) {
CHECK_RESULT(UseNameForMemoryVar(&expr->memidx));
return Result::Ok;
}
Result NameApplier::OnMemoryInitExpr(MemoryInitExpr* expr) {
CHECK_RESULT(UseNameForDataSegmentVar(&expr->var));
CHECK_RESULT(UseNameForMemoryVar(&expr->memidx));
return Result::Ok;
}
Result NameApplier::OnMemorySizeExpr(MemorySizeExpr* expr) {
CHECK_RESULT(UseNameForMemoryVar(&expr->memidx));
return Result::Ok;
}
Result NameApplier::OnElemDropExpr(ElemDropExpr* expr) {
CHECK_RESULT(UseNameForElemSegmentVar(&expr->var));
return Result::Ok;
}
@ -269,56 +300,61 @@ Result NameApplier::OnTableCopyExpr(TableCopyExpr* expr) {
return Result::Ok;
}
Result NameApplier::OnTableInitExpr(TableInitExpr* expr) {
Result NameApplier::OnTableInitExpr(TableInitExpr* expr) {
CHECK_RESULT(UseNameForElemSegmentVar(&expr->segment_index));
CHECK_RESULT(UseNameForTableVar(&expr->table_index));
return Result::Ok;
}
Result NameApplier::OnTableGetExpr(TableGetExpr* expr) {
Result NameApplier::OnTableGetExpr(TableGetExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableSetExpr(TableSetExpr* expr) {
Result NameApplier::OnTableSetExpr(TableSetExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableGrowExpr(TableGrowExpr* expr) {
Result NameApplier::OnTableGrowExpr(TableGrowExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableSizeExpr(TableSizeExpr* expr) {
Result NameApplier::OnTableSizeExpr(TableSizeExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableFillExpr(TableFillExpr* expr) {
Result NameApplier::OnTableFillExpr(TableFillExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnStoreExpr(StoreExpr* expr) {
CHECK_RESULT(UseNameForMemoryVar(&expr->memidx));
return Result::Ok;
}
Result NameApplier::OnBrExpr(BrExpr* expr) {
string_view label = FindLabelByVar(&expr->var);
std::string_view label = FindLabelByVar(&expr->var);
UseNameForVar(label, &expr->var);
return Result::Ok;
}
Result NameApplier::OnBrIfExpr(BrIfExpr* expr) {
string_view label = FindLabelByVar(&expr->var);
std::string_view label = FindLabelByVar(&expr->var);
UseNameForVar(label, &expr->var);
return Result::Ok;
}
Result NameApplier::OnBrTableExpr(BrTableExpr* expr) {
for (Var& target : expr->targets) {
string_view label = FindLabelByVar(&target);
std::string_view label = FindLabelByVar(&target);
UseNameForVar(label, &target);
}
string_view label = FindLabelByVar(&expr->default_target);
std::string_view label = FindLabelByVar(&expr->default_target);
UseNameForVar(label, &expr->default_target);
return Result::Ok;
}
@ -341,7 +377,8 @@ Result NameApplier::OnCatchExpr(TryExpr*, Catch* expr) {
}
Result NameApplier::OnDelegateExpr(TryExpr* expr) {
string_view label = FindLabelByVar(&expr->delegate_target);
PopLabel();
std::string_view label = FindLabelByVar(&expr->delegate_target);
UseNameForVar(label, &expr->delegate_target);
return Result::Ok;
}
@ -352,7 +389,7 @@ Result NameApplier::OnThrowExpr(ThrowExpr* expr) {
}
Result NameApplier::OnRethrowExpr(RethrowExpr* expr) {
string_view label = FindLabelByVar(&expr->var);
std::string_view label = FindLabelByVar(&expr->var);
UseNameForVar(label, &expr->var);
return Result::Ok;
}
@ -408,6 +445,11 @@ Result NameApplier::EndIfExpr(IfExpr* expr) {
return Result::Ok;
}
Result NameApplier::OnLoadExpr(LoadExpr* expr) {
CHECK_RESULT(UseNameForMemoryVar(&expr->memidx));
return Result::Ok;
}
Result NameApplier::OnGlobalSetExpr(GlobalSetExpr* expr) {
CHECK_RESULT(UseNameForGlobalVar(&expr->var));
return Result::Ok;
@ -423,6 +465,16 @@ Result NameApplier::OnLocalTeeExpr(LocalTeeExpr* expr) {
return Result::Ok;
}
Result NameApplier::OnSimdLoadLaneExpr(SimdLoadLaneExpr* expr) {
CHECK_RESULT(UseNameForMemoryVar(&expr->memidx));
return Result::Ok;
}
Result NameApplier::OnSimdStoreLaneExpr(SimdStoreLaneExpr* expr) {
CHECK_RESULT(UseNameForMemoryVar(&expr->memidx));
return Result::Ok;
}
Result NameApplier::VisitFunc(Index func_index, Func* func) {
current_func_ = func;
if (func->decl.has_func_type) {
@ -450,8 +502,26 @@ Result NameApplier::VisitTag(Tag* tag) {
}
Result NameApplier::VisitExport(Index export_index, Export* export_) {
if (export_->kind == ExternalKind::Func) {
UseNameForFuncVar(&export_->var);
switch (export_->kind) {
case ExternalKind::Func:
UseNameForFuncVar(&export_->var);
break;
case ExternalKind::Table:
UseNameForTableVar(&export_->var);
break;
case ExternalKind::Memory:
UseNameForMemoryVar(&export_->var);
break;
case ExternalKind::Global:
UseNameForGlobalVar(&export_->var);
break;
case ExternalKind::Tag:
UseNameForTagVar(&export_->var);
break;
}
return Result::Ok;
}
@ -460,9 +530,10 @@ Result NameApplier::VisitElemSegment(Index elem_segment_index,
ElemSegment* segment) {
CHECK_RESULT(UseNameForTableVar(&segment->table_var));
CHECK_RESULT(visitor_.VisitExprList(segment->offset));
for (ElemExpr& elem_expr : segment->elem_exprs) {
if (elem_expr.kind == ElemExprKind::RefFunc) {
CHECK_RESULT(UseNameForFuncVar(&elem_expr.var));
for (ExprList& elem_expr : segment->elem_exprs) {
Expr* expr = &elem_expr.front();
if (expr->type() == ExprType::RefFunc) {
CHECK_RESULT(UseNameForFuncVar(&cast<RefFuncExpr>(expr)->var));
}
}
return Result::Ok;

File diff suppressed because it is too large Load Diff

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
#include "src/binary-reader-logging.h"
#include "wabt/binary-reader-logging.h"
#include <cinttypes>
#include "src/stream.h"
#include "wabt/stream.h"
namespace wabt {
@ -80,7 +80,7 @@ void BinaryReaderLogging::LogType(Type type) {
if (type.IsIndex()) {
LOGF_NOINDENT("typeidx[%d]", type.GetIndex());
} else {
LOGF_NOINDENT("%s", type.GetName());
LOGF_NOINDENT("%s", type.GetName().c_str());
}
}
@ -132,7 +132,7 @@ Result BinaryReaderLogging::BeginSection(Index section_index,
Result BinaryReaderLogging::BeginCustomSection(Index section_index,
Offset size,
string_view section_name) {
std::string_view section_name) {
LOGF("BeginCustomSection('" PRIstringview "', size: %" PRIzd ")\n",
WABT_PRINTF_STRING_VIEW_ARG(section_name), size);
Indent();
@ -177,8 +177,8 @@ Result BinaryReaderLogging::OnArrayType(Index index, TypeMut field) {
Result BinaryReaderLogging::OnImport(Index index,
ExternalKind kind,
string_view module_name,
string_view field_name) {
std::string_view module_name,
std::string_view field_name) {
LOGF("OnImport(index: %" PRIindex ", kind: %s, module: \"" PRIstringview
"\", field: \"" PRIstringview "\")\n",
index, GetKindName(kind), WABT_PRINTF_STRING_VIEW_ARG(module_name),
@ -187,8 +187,8 @@ Result BinaryReaderLogging::OnImport(Index index,
}
Result BinaryReaderLogging::OnImportFunc(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index func_index,
Index sig_index) {
LOGF("OnImportFunc(import_index: %" PRIindex ", func_index: %" PRIindex
@ -199,8 +199,8 @@ Result BinaryReaderLogging::OnImportFunc(Index import_index,
}
Result BinaryReaderLogging::OnImportTable(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index table_index,
Type elem_type,
const Limits* elem_limits) {
@ -208,14 +208,14 @@ Result BinaryReaderLogging::OnImportTable(Index import_index,
SPrintLimits(buf, sizeof(buf), elem_limits);
LOGF("OnImportTable(import_index: %" PRIindex ", table_index: %" PRIindex
", elem_type: %s, %s)\n",
import_index, table_index, elem_type.GetName(), buf);
import_index, table_index, elem_type.GetName().c_str(), buf);
return reader_->OnImportTable(import_index, module_name, field_name,
table_index, elem_type, elem_limits);
}
Result BinaryReaderLogging::OnImportMemory(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index memory_index,
const Limits* page_limits) {
char buf[100];
@ -228,22 +228,23 @@ Result BinaryReaderLogging::OnImportMemory(Index import_index,
}
Result BinaryReaderLogging::OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index global_index,
Type type,
bool mutable_) {
LOGF("OnImportGlobal(import_index: %" PRIindex ", global_index: %" PRIindex
", type: %s, mutable: "
"%s)\n",
import_index, global_index, type.GetName(), mutable_ ? "true" : "false");
import_index, global_index, type.GetName().c_str(),
mutable_ ? "true" : "false");
return reader_->OnImportGlobal(import_index, module_name, field_name,
global_index, type, mutable_);
}
Result BinaryReaderLogging::OnImportTag(Index import_index,
string_view module_name,
string_view field_name,
std::string_view module_name,
std::string_view field_name,
Index tag_index,
Index sig_index) {
LOGF("OnImportTag(import_index: %" PRIindex ", tag_index: %" PRIindex
@ -259,7 +260,7 @@ Result BinaryReaderLogging::OnTable(Index index,
char buf[100];
SPrintLimits(buf, sizeof(buf), elem_limits);
LOGF("OnTable(index: %" PRIindex ", elem_type: %s, %s)\n", index,
elem_type.GetName(), buf);
elem_type.GetName().c_str(), buf);
return reader_->OnTable(index, elem_type, elem_limits);
}
@ -272,14 +273,14 @@ Result BinaryReaderLogging::OnMemory(Index index, const Limits* page_limits) {
Result BinaryReaderLogging::BeginGlobal(Index index, Type type, bool mutable_) {
LOGF("BeginGlobal(index: %" PRIindex ", type: %s, mutable: %s)\n", index,
type.GetName(), mutable_ ? "true" : "false");
type.GetName().c_str(), mutable_ ? "true" : "false");
return reader_->BeginGlobal(index, type, mutable_);
}
Result BinaryReaderLogging::OnExport(Index index,
ExternalKind kind,
Index item_index,
string_view name) {
std::string_view name) {
LOGF("OnExport(index: %" PRIindex ", kind: %s, item_index: %" PRIindex
", name: \"" PRIstringview "\")\n",
index, GetKindName(kind), item_index, WABT_PRINTF_STRING_VIEW_ARG(name));
@ -295,7 +296,7 @@ Result BinaryReaderLogging::OnLocalDecl(Index decl_index,
Index count,
Type type) {
LOGF("OnLocalDecl(index: %" PRIindex ", count: %" PRIindex ", type: %s)\n",
decl_index, count, type.GetName());
decl_index, count, type.GetName().c_str());
return reader_->OnLocalDecl(decl_index, count, type);
}
@ -412,7 +413,7 @@ Result BinaryReaderLogging::BeginElemSegment(Index index,
Result BinaryReaderLogging::OnElemSegmentElemType(Index index, Type elem_type) {
LOGF("OnElemSegmentElemType(index: %" PRIindex ", type: %s)\n", index,
elem_type.GetName());
elem_type.GetName().c_str());
return reader_->OnElemSegmentElemType(index, elem_type);
}
@ -433,7 +434,7 @@ Result BinaryReaderLogging::OnModuleNameSubsection(Index index,
return reader_->OnModuleNameSubsection(index, name_type, subsection_size);
}
Result BinaryReaderLogging::OnModuleName(string_view name) {
Result BinaryReaderLogging::OnModuleName(std::string_view name) {
LOGF("OnModuleName(name: \"" PRIstringview "\")\n",
WABT_PRINTF_STRING_VIEW_ARG(name));
return reader_->OnModuleName(name);
@ -448,7 +449,7 @@ Result BinaryReaderLogging::OnFunctionNameSubsection(Index index,
return reader_->OnFunctionNameSubsection(index, name_type, subsection_size);
}
Result BinaryReaderLogging::OnFunctionName(Index index, string_view name) {
Result BinaryReaderLogging::OnFunctionName(Index index, std::string_view name) {
LOGF("OnFunctionName(index: %" PRIindex ", name: \"" PRIstringview "\")\n",
index, WABT_PRINTF_STRING_VIEW_ARG(name));
return reader_->OnFunctionName(index, name);
@ -465,7 +466,7 @@ Result BinaryReaderLogging::OnLocalNameSubsection(Index index,
Result BinaryReaderLogging::OnLocalName(Index func_index,
Index local_index,
string_view name) {
std::string_view name) {
LOGF("OnLocalName(func_index: %" PRIindex ", local_index: %" PRIindex
", name: \"" PRIstringview "\")\n",
func_index, local_index, WABT_PRINTF_STRING_VIEW_ARG(name));
@ -483,7 +484,7 @@ Result BinaryReaderLogging::OnNameSubsection(
Result BinaryReaderLogging::OnNameEntry(NameSectionSubsection type,
Index index,
string_view name) {
std::string_view name) {
LOGF("OnNameEntry(type: %s, index: %" PRIindex ", name: \"" PRIstringview
"\")\n",
GetNameSectionSubsectionName(type), index,
@ -491,48 +492,6 @@ Result BinaryReaderLogging::OnNameEntry(NameSectionSubsection type,
return reader_->OnNameEntry(type, index, name);
}
Result BinaryReaderLogging::OnInitExprF32ConstExpr(Index index,
uint32_t value_bits) {
float value;
memcpy(&value, &value_bits, sizeof(value));
LOGF("OnInitExprF32ConstExpr(index: %" PRIindex ", value: %g (0x04%x))\n",
index, value, value_bits);
return reader_->OnInitExprF32ConstExpr(index, value_bits);
}
Result BinaryReaderLogging::OnInitExprF64ConstExpr(Index index,
uint64_t value_bits) {
double value;
memcpy(&value, &value_bits, sizeof(value));
LOGF("OnInitExprF64ConstExpr(index: %" PRIindex " value: %g (0x08%" PRIx64
"))\n",
index, value, value_bits);
return reader_->OnInitExprF64ConstExpr(index, value_bits);
}
Result BinaryReaderLogging::OnInitExprV128ConstExpr(Index index,
v128 value_bits) {
LOGF("OnInitExprV128ConstExpr(index: %" PRIindex
" value: ( 0x%08x 0x%08x 0x%08x 0x%08x))\n",
index, value_bits.u32(0), value_bits.u32(1), value_bits.u32(2),
value_bits.u32(3));
return reader_->OnInitExprV128ConstExpr(index, value_bits);
}
Result BinaryReaderLogging::OnInitExprI32ConstExpr(Index index,
uint32_t value) {
LOGF("OnInitExprI32ConstExpr(index: %" PRIindex ", value: %u)\n", index,
value);
return reader_->OnInitExprI32ConstExpr(index, value);
}
Result BinaryReaderLogging::OnInitExprI64ConstExpr(Index index,
uint64_t value) {
LOGF("OnInitExprI64ConstExpr(index: %" PRIindex ", value: %" PRIu64 ")\n",
index, value);
return reader_->OnInitExprI64ConstExpr(index, value);
}
Result BinaryReaderLogging::OnDylinkInfo(uint32_t mem_size,
uint32_t mem_align,
uint32_t table_size,
@ -544,14 +503,30 @@ Result BinaryReaderLogging::OnDylinkInfo(uint32_t mem_size,
return reader_->OnDylinkInfo(mem_size, mem_align, table_size, table_align);
}
Result BinaryReaderLogging::OnDylinkNeeded(string_view so_name) {
Result BinaryReaderLogging::OnDylinkNeeded(std::string_view so_name) {
LOGF("OnDylinkNeeded(name: " PRIstringview ")\n",
WABT_PRINTF_STRING_VIEW_ARG(so_name));
return reader_->OnDylinkNeeded(so_name);
}
Result BinaryReaderLogging::OnRelocCount(Index count,
Index section_index) {
Result BinaryReaderLogging::OnDylinkExport(std::string_view name,
uint32_t flags) {
LOGF("OnDylinkExport(name: " PRIstringview ", flags: 0x%x)\n",
WABT_PRINTF_STRING_VIEW_ARG(name), flags);
return reader_->OnDylinkExport(name, flags);
}
Result BinaryReaderLogging::OnDylinkImport(std::string_view module,
std::string_view name,
uint32_t flags) {
LOGF("OnDylinkImport(module: " PRIstringview ", name: " PRIstringview
", flags: 0x%x)\n",
WABT_PRINTF_STRING_VIEW_ARG(module), WABT_PRINTF_STRING_VIEW_ARG(name),
flags);
return reader_->OnDylinkImport(module, name, flags);
}
Result BinaryReaderLogging::OnRelocCount(Index count, Index section_index) {
LOGF("OnRelocCount(count: %" PRIindex ", section: %" PRIindex ")\n", count,
section_index);
return reader_->OnRelocCount(count, section_index);
@ -568,9 +543,15 @@ Result BinaryReaderLogging::OnReloc(RelocType type,
return reader_->OnReloc(type, offset, index, addend);
}
Result BinaryReaderLogging::OnFeature(uint8_t prefix, std::string_view name) {
LOGF("OnFeature(prefix: '%c', name: '" PRIstringview "')\n", prefix,
WABT_PRINTF_STRING_VIEW_ARG(name));
return reader_->OnFeature(prefix, name);
}
Result BinaryReaderLogging::OnDataSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index segment,
uint32_t offset,
uint32_t size) {
@ -581,7 +562,7 @@ Result BinaryReaderLogging::OnDataSymbol(Index index,
Result BinaryReaderLogging::OnFunctionSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index func_index) {
LOGF("OnFunctionSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
")\n",
@ -591,7 +572,7 @@ Result BinaryReaderLogging::OnFunctionSymbol(Index index,
Result BinaryReaderLogging::OnGlobalSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index global_index) {
LOGF("OnGlobalSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
")\n",
@ -609,7 +590,7 @@ Result BinaryReaderLogging::OnSectionSymbol(Index index,
Result BinaryReaderLogging::OnTagSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index tag_index) {
LOGF("OnTagSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
")\n",
@ -619,16 +600,16 @@ Result BinaryReaderLogging::OnTagSymbol(Index index,
Result BinaryReaderLogging::OnTableSymbol(Index index,
uint32_t flags,
string_view name,
std::string_view name,
Index table_index) {
LOGF("OnTableSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
")\n",
")\n",
WABT_PRINTF_STRING_VIEW_ARG(name), flags, table_index);
return reader_->OnTableSymbol(index, flags, name, table_index);
}
Result BinaryReaderLogging::OnSegmentInfo(Index index,
string_view name,
std::string_view name,
Address alignment,
uint32_t flags) {
LOGF("OnSegmentInfo(%d name: " PRIstringview ", alignment: %" PRIaddress
@ -643,7 +624,7 @@ Result BinaryReaderLogging::OnInitFunction(uint32_t priority,
return reader_->OnInitFunction(priority, func_index);
}
Result BinaryReaderLogging::OnComdatBegin(string_view name,
Result BinaryReaderLogging::OnComdatBegin(std::string_view name,
uint32_t flags,
Index count) {
LOGF("OnComdatBegin(" PRIstringview ", flags: %d, count: %" PRIindex ")\n",
@ -657,6 +638,22 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) {
return reader_->OnComdatEntry(kind, index);
}
Result BinaryReaderLogging::BeginCodeMetadataSection(std::string_view name,
Offset size) {
LOGF("BeginCodeMetadataSection('" PRIstringview "', size:%" PRIzd ")\n",
WABT_PRINTF_STRING_VIEW_ARG(name), size);
Indent();
return reader_->BeginCodeMetadataSection(name, size);
}
Result BinaryReaderLogging::OnCodeMetadata(Offset code_offset,
const void* data,
Address size) {
std::string_view content(static_cast<const char*>(data), size);
LOGF("OnCodeMetadata(offset: %" PRIzd ", data: \"" PRIstringview "\")\n",
code_offset, WABT_PRINTF_STRING_VIEW_ARG(content));
return reader_->OnCodeMetadata(code_offset, data, size);
}
#define DEFINE_BEGIN(name) \
Result BinaryReaderLogging::name(Offset size) { \
LOGF(#name "(%" PRIzd ")\n", size); \
@ -677,10 +674,10 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) {
return reader_->name(value); \
}
#define DEFINE_TYPE(name) \
Result BinaryReaderLogging::name(Type type) { \
LOGF(#name "(%s)\n", type.GetName()); \
return reader_->name(type); \
#define DEFINE_TYPE(name) \
Result BinaryReaderLogging::name(Type type) { \
LOGF(#name "(%s)\n", type.GetName().c_str()); \
return reader_->name(type); \
}
#define DEFINE_INDEX_DESC(name, desc) \
@ -689,10 +686,11 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) {
return reader_->name(value); \
}
#define DEFINE_INDEX_TYPE(name) \
Result BinaryReaderLogging::name(Index value, Type type) { \
LOGF(#name "(index: %" PRIindex ", type: %s)\n", value, type.GetName()); \
return reader_->name(value, type); \
#define DEFINE_INDEX_TYPE(name) \
Result BinaryReaderLogging::name(Index value, Type type) { \
LOGF(#name "(index: %" PRIindex ", type: %s)\n", value, \
type.GetName().c_str()); \
return reader_->name(value, type); \
}
#define DEFINE_INDEX_INDEX(name, desc0, desc1) \
@ -717,22 +715,25 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) {
return reader_->name(opcode); \
}
#define DEFINE_LOAD_STORE_OPCODE(name) \
Result BinaryReaderLogging::name(Opcode opcode, Address alignment_log2, \
Address offset) { \
LOGF(#name "(opcode: \"%s\" (%u), align log2: %" PRIaddress \
", offset: %" PRIaddress ")\n", \
opcode.GetName(), opcode.GetCode(), alignment_log2, offset); \
return reader_->name(opcode, alignment_log2, offset); \
#define DEFINE_LOAD_STORE_OPCODE(name) \
Result BinaryReaderLogging::name(Opcode opcode, Index memidx, \
Address alignment_log2, Address offset) { \
LOGF(#name "(opcode: \"%s\" (%u), memidx: %" PRIindex \
", align log2: %" PRIaddress ", offset: %" PRIaddress ")\n", \
opcode.GetName(), opcode.GetCode(), memidx, alignment_log2, offset); \
return reader_->name(opcode, memidx, alignment_log2, offset); \
}
#define DEFINE_SIMD_LOAD_STORE_LANE_OPCODE(name) \
Result BinaryReaderLogging::name(Opcode opcode, Address alignment_log2, \
Address offset, uint64_t value) { \
LOGF(#name "(opcode: \"%s\" (%u), align log2: %" PRIaddress \
", offset: %" PRIaddress ", lane: %" PRIu64 ")\n", \
opcode.GetName(), opcode.GetCode(), alignment_log2, offset, value); \
return reader_->name(opcode, alignment_log2, offset, value); \
Result BinaryReaderLogging::name(Opcode opcode, Index memidx, \
Address alignment_log2, Address offset, \
uint64_t value) { \
LOGF(#name "(opcode: \"%s\" (%u), memidx: %" PRIindex \
", align log2: %" PRIaddress ", offset: %" PRIaddress \
", lane: %" PRIu64 ")\n", \
opcode.GetName(), opcode.GetCode(), memidx, alignment_log2, offset, \
value); \
return reader_->name(opcode, memidx, alignment_log2, offset, value); \
}
#define DEFINE0(name) \
@ -810,12 +811,12 @@ DEFINE_LOAD_STORE_OPCODE(OnLoadExpr);
DEFINE_INDEX_DESC(OnLocalGetExpr, "index")
DEFINE_INDEX_DESC(OnLocalSetExpr, "index")
DEFINE_INDEX_DESC(OnLocalTeeExpr, "index")
DEFINE0(OnMemoryCopyExpr)
DEFINE_INDEX_INDEX(OnMemoryCopyExpr, "src_memory_index", "dest_memory_index")
DEFINE_INDEX(OnDataDropExpr)
DEFINE0(OnMemoryFillExpr)
DEFINE0(OnMemoryGrowExpr)
DEFINE_INDEX(OnMemoryInitExpr)
DEFINE0(OnMemorySizeExpr)
DEFINE_INDEX(OnMemoryFillExpr)
DEFINE_INDEX(OnMemoryGrowExpr)
DEFINE_INDEX_INDEX(OnMemoryInitExpr, "segment_index", "memory_index")
DEFINE_INDEX(OnMemorySizeExpr)
DEFINE_INDEX_INDEX(OnTableCopyExpr, "dst_index", "src_index")
DEFINE_INDEX(OnElemDropExpr)
DEFINE_INDEX_INDEX(OnTableInitExpr, "segment_index", "table_index")
@ -876,14 +877,16 @@ DEFINE_END(EndNamesSection)
DEFINE_BEGIN(BeginRelocSection)
DEFINE_END(EndRelocSection)
DEFINE_INDEX_INDEX(OnInitExprGlobalGetExpr, "index", "global_index")
DEFINE_INDEX_TYPE(OnInitExprRefNull)
DEFINE_INDEX_INDEX(OnInitExprRefFunc, "index", "func_index")
DEFINE_BEGIN(BeginDylinkSection)
DEFINE_INDEX(OnDylinkNeededCount)
DEFINE_INDEX(OnDylinkExportCount)
DEFINE_INDEX(OnDylinkImportCount)
DEFINE_END(EndDylinkSection)
DEFINE_BEGIN(BeginTargetFeaturesSection)
DEFINE_INDEX(OnFeatureCount)
DEFINE_END(EndTargetFeaturesSection)
DEFINE_BEGIN(BeginLinkingSection)
DEFINE_INDEX(OnSymbolCount)
DEFINE_INDEX(OnSegmentInfoCount)
@ -896,6 +899,10 @@ DEFINE_INDEX(OnTagCount);
DEFINE_INDEX_INDEX(OnTagType, "index", "sig_index")
DEFINE_END(EndTagSection);
DEFINE_INDEX(OnCodeMetadataFuncCount);
DEFINE_INDEX_INDEX(OnCodeMetadataCount, "func_index", "count");
DEFINE_END(EndCodeMetadataSection);
// We don't need to log these (the individual opcodes are logged instead), but
// we still need to forward the calls.
Result BinaryReaderLogging::OnOpcode(Opcode opcode) {
@ -929,6 +936,14 @@ Result BinaryReaderLogging::OnOpcodeUint32Uint32Uint32(uint32_t value,
return reader_->OnOpcodeUint32Uint32Uint32(value, value2, value3);
}
Result BinaryReaderLogging::OnOpcodeUint32Uint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3,
uint32_t value4) {
return reader_->OnOpcodeUint32Uint32Uint32Uint32(value, value2, value3,
value4);
}
Result BinaryReaderLogging::OnOpcodeUint64(uint64_t value) {
return reader_->OnOpcodeUint64(value);
}
@ -953,8 +968,4 @@ Result BinaryReaderLogging::OnOpcodeType(Type type) {
return reader_->OnOpcodeType(type);
}
Result BinaryReaderLogging::OnEndFunc() {
return reader_->OnEndFunc();
}
} // namespace wabt

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
#include "src/binary-reader-opcnt.h"
#include "wabt/binary-reader-opcnt.h"
#include <cassert>
#include <cinttypes>
@ -22,10 +22,10 @@
#include <cstdint>
#include <cstdio>
#include "src/binary-reader-nop.h"
#include "src/common.h"
#include "src/literal.h"
#include "src/stream.h"
#include "wabt/binary-reader-nop.h"
#include "wabt/common.h"
#include "wabt/literal.h"
#include "wabt/stream.h"
namespace wabt {
@ -61,19 +61,19 @@ std::pair<const T*, size_t> OpcodeInfo::GetDataArray() const {
template <typename T>
const T* OpcodeInfo::GetData(size_t expected_size) const {
auto pair = GetDataArray<T>();
assert(pair.second == expected_size);
return pair.first;
auto [data, size] = GetDataArray<T>();
assert(size == expected_size);
return data;
}
template <typename T, typename F>
void OpcodeInfo::WriteArray(Stream& stream, F&& write_func) {
auto pair = GetDataArray<T>();
for (size_t i = 0; i < pair.second; ++i) {
auto [data, size] = GetDataArray<T>();
for (size_t i = 0; i < size; ++i) {
// Write an initial space (to separate from the opcode name) first, then
// comma-separate.
stream.Writef("%s", i == 0 ? " " : ", ");
write_func(pair.first[i]);
write_func(data[i]);
}
}
@ -113,7 +113,20 @@ void OpcodeInfo::Write(Stream& stream) {
break;
}
case Kind::V128: {
auto data = *GetData<v128>();
auto l0 = data.u32(0);
auto l1 = data.u32(1);
auto l2 = data.u32(2);
auto l3 = data.u32(3);
stream.Writef(" %u %u %u %u (0x%x 0x%x 0x%x 0x%x)", l0, l1, l2, l3, l0,
l1, l2, l3);
break;
}
case Kind::Uint32Uint32:
case Kind::Uint32Uint32Uint32:
case Kind::Uint32Uint32Uint32Uint32:
WriteArray<uint32_t>(
stream, [&stream](uint32_t value) { stream.Writef("%u", value); });
break;
@ -123,7 +136,7 @@ void OpcodeInfo::Write(Stream& stream) {
if (type.IsIndex()) {
stream.Writef(" type:%d", type.GetIndex());
} else if (type != Type::Void) {
stream.Writef(" %s", type.GetName());
stream.Writef(" %s", type.GetName().c_str());
}
break;
}
@ -191,15 +204,18 @@ class BinaryReaderOpcnt : public BinaryReaderNop {
Result OnOpcodeUint32(uint32_t value) override;
Result OnOpcodeIndex(Index value) override;
Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override;
Result OnOpcodeUint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3) override;
Result OnOpcodeUint64(uint64_t value) override;
Result OnOpcodeF32(uint32_t value) override;
Result OnOpcodeF64(uint64_t value) override;
Result OnOpcodeV128(v128 value) override;
Result OnOpcodeBlockSig(Type sig_type) override;
Result OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) override;
Result OnEndExpr() override;
Result OnEndFunc() override;
private:
template <typename... Args>
@ -246,6 +262,14 @@ Result BinaryReaderOpcnt::OnOpcodeUint32Uint32(uint32_t value0,
return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32Uint32, array, 2);
}
Result BinaryReaderOpcnt::OnOpcodeUint32Uint32Uint32(uint32_t value0,
uint32_t value1,
uint32_t value2) {
uint32_t array[3] = {value0, value1, value2};
return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32Uint32Uint32, array,
3);
}
Result BinaryReaderOpcnt::OnOpcodeUint64(uint64_t value) {
return Emplace(current_opcode_, OpcodeInfo::Kind::Uint64, &value);
}
@ -258,6 +282,10 @@ Result BinaryReaderOpcnt::OnOpcodeF64(uint64_t value) {
return Emplace(current_opcode_, OpcodeInfo::Kind::Float64, &value);
}
Result BinaryReaderOpcnt::OnOpcodeV128(v128 value) {
return Emplace(current_opcode_, OpcodeInfo::Kind::V128, &value);
}
Result BinaryReaderOpcnt::OnOpcodeBlockSig(Type sig_type) {
return Emplace(current_opcode_, OpcodeInfo::Kind::BlockSig, &sig_type);
}
@ -273,10 +301,6 @@ Result BinaryReaderOpcnt::OnEndExpr() {
return Emplace(Opcode::End, OpcodeInfo::Kind::Bare);
}
Result BinaryReaderOpcnt::OnEndFunc() {
return Emplace(Opcode::End, OpcodeInfo::Kind::Bare);
}
} // end anonymous namespace
Result ReadBinaryOpcnt(const void* data,

File diff suppressed because it is too large Load Diff

View File

@ -14,21 +14,21 @@
* limitations under the License.
*/
#include "src/binary-writer-spec.h"
#include "wabt/binary-writer-spec.h"
#include <cassert>
#include <cinttypes>
#include <string_view>
#include "config.h"
#include "wabt/config.h"
#include "src/binary-writer.h"
#include "src/binary.h"
#include "src/cast.h"
#include "src/filenames.h"
#include "src/ir.h"
#include "src/literal.h"
#include "src/stream.h"
#include "src/string-view.h"
#include "wabt/binary-writer.h"
#include "wabt/binary.h"
#include "wabt/cast.h"
#include "wabt/filenames.h"
#include "wabt/ir.h"
#include "wabt/literal.h"
#include "wabt/stream.h"
namespace wabt {
@ -38,8 +38,8 @@ class BinaryWriterSpec {
public:
BinaryWriterSpec(Stream* json_stream,
WriteBinarySpecStreamFactory module_stream_factory,
string_view source_filename,
string_view module_filename_noext,
std::string_view source_filename,
std::string_view module_filename_noext,
const WriteBinaryOptions& options);
Result WriteScript(const Script& script);
@ -49,7 +49,7 @@ class BinaryWriterSpec {
void WriteString(const char* s);
void WriteKey(const char* key);
void WriteSeparator();
void WriteEscapedString(string_view);
void WriteEscapedString(std::string_view);
void WriteCommandType(const Command& command);
void WriteLocation(const Location& loc);
void WriteVar(const Var& var);
@ -61,10 +61,10 @@ class BinaryWriterSpec {
void WriteConstVector(const ConstVector& consts);
void WriteAction(const Action& action);
void WriteActionResultType(const Action& action);
void WriteModule(string_view filename, const Module& module);
void WriteScriptModule(string_view filename,
void WriteModule(std::string_view filename, const Module& module);
void WriteScriptModule(std::string_view filename,
const ScriptModule& script_module);
void WriteInvalidModule(const ScriptModule& module, string_view text);
void WriteInvalidModule(const ScriptModule& module, std::string_view text);
void WriteCommands();
const Script* script_ = nullptr;
@ -80,8 +80,8 @@ class BinaryWriterSpec {
BinaryWriterSpec::BinaryWriterSpec(
Stream* json_stream,
WriteBinarySpecStreamFactory module_stream_factory,
string_view source_filename,
string_view module_filename_noext,
std::string_view source_filename,
std::string_view module_filename_noext,
const WriteBinaryOptions& options)
: json_stream_(json_stream),
module_stream_factory_(module_stream_factory),
@ -110,7 +110,7 @@ void BinaryWriterSpec::WriteSeparator() {
json_stream_->Writef(", ");
}
void BinaryWriterSpec::WriteEscapedString(string_view s) {
void BinaryWriterSpec::WriteEscapedString(std::string_view s) {
json_stream_->WriteChar('"');
for (size_t i = 0; i < s.length(); ++i) {
uint8_t c = s[i];
@ -125,6 +125,7 @@ void BinaryWriterSpec::WriteEscapedString(string_view s) {
void BinaryWriterSpec::WriteCommandType(const Command& command) {
static const char* s_command_names[] = {
"module",
"module",
"action",
"register",
@ -135,6 +136,7 @@ void BinaryWriterSpec::WriteCommandType(const Command& command) {
"assert_return",
"assert_trap",
"assert_exhaustion",
"assert_exception",
};
WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_command_names) == kCommandTypeCount);
@ -159,7 +161,7 @@ void BinaryWriterSpec::WriteVar(const Var& var) {
void BinaryWriterSpec::WriteTypeObject(Type type) {
json_stream_->Writef("{");
WriteKey("type");
WriteString(type.GetName());
WriteString(type.GetName().c_str());
json_stream_->Writef("}");
}
@ -258,7 +260,7 @@ void BinaryWriterSpec::WriteConst(const Const& const_) {
WriteString("v128");
WriteSeparator();
WriteKey("lane_type");
WriteString(const_.lane_type().GetName());
WriteString(const_.lane_type().GetName().c_str());
WriteSeparator();
WriteKey("value");
json_stream_->Writef("[");
@ -380,12 +382,13 @@ void BinaryWriterSpec::WriteActionResultType(const Action& action) {
json_stream_->Writef("]");
}
void BinaryWriterSpec::WriteModule(string_view filename, const Module& module) {
void BinaryWriterSpec::WriteModule(std::string_view filename,
const Module& module) {
result_ |=
WriteBinaryModule(module_stream_factory_(filename), &module, options_);
}
void BinaryWriterSpec::WriteScriptModule(string_view filename,
void BinaryWriterSpec::WriteScriptModule(std::string_view filename,
const ScriptModule& script_module) {
switch (script_module.type()) {
case ScriptModuleType::Text:
@ -405,7 +408,7 @@ void BinaryWriterSpec::WriteScriptModule(string_view filename,
}
void BinaryWriterSpec::WriteInvalidModule(const ScriptModule& module,
string_view text) {
std::string_view text) {
const char* extension = "";
const char* module_type = "";
switch (module.type()) {
@ -475,6 +478,25 @@ void BinaryWriterSpec::WriteCommands() {
break;
}
case CommandType::ScriptModule: {
auto* script_module_command = cast<ScriptModuleCommand>(command);
const auto& module = script_module_command->module;
std::string filename = GetModuleFilename(kWasmExtension);
WriteLocation(module.loc);
WriteSeparator();
if (!module.name.empty()) {
WriteKey("name");
WriteEscapedString(module.name);
WriteSeparator();
}
WriteKey("filename");
WriteEscapedString(GetBasename(filename));
WriteScriptModule(filename, *script_module_command->script_module);
num_modules_++;
last_module_index = i;
break;
}
case CommandType::Action: {
const Action& action = *cast<ActionCommand>(command)->action;
WriteLocation(action.loc);
@ -546,8 +568,17 @@ void BinaryWriterSpec::WriteCommands() {
WriteSeparator();
WriteAction(*assert_return_command->action);
WriteSeparator();
WriteKey("expected");
WriteConstVector(assert_return_command->expected);
const Expectation* expectation = assert_return_command->expected.get();
switch (expectation->type()) {
case ExpectationType::Values:
WriteKey("expected");
break;
case ExpectationType::Either:
WriteKey("either");
break;
}
WriteConstVector(expectation->expected);
break;
}
@ -579,6 +610,17 @@ void BinaryWriterSpec::WriteCommands() {
WriteActionResultType(*assert_exhaustion_command->action);
break;
}
case CommandType::AssertException: {
auto* assert_exception_command = cast<AssertExceptionCommand>(command);
WriteLocation(assert_exception_command->action->loc);
WriteSeparator();
WriteAction(*assert_exception_command->action);
WriteSeparator();
WriteKey("expected");
WriteActionResultType(*assert_exception_command->action);
break;
}
}
json_stream_->Writef("}");
@ -597,8 +639,8 @@ Result BinaryWriterSpec::WriteScript(const Script& script) {
Result WriteBinarySpecScript(Stream* json_stream,
WriteBinarySpecStreamFactory module_stream_factory,
Script* script,
string_view source_filename,
string_view module_filename_noext,
std::string_view source_filename,
std::string_view module_filename_noext,
const WriteBinaryOptions& options) {
BinaryWriterSpec binary_writer_spec(json_stream, module_stream_factory,
source_filename, module_filename_noext,
@ -609,15 +651,15 @@ Result WriteBinarySpecScript(Stream* json_stream,
Result WriteBinarySpecScript(
Stream* json_stream,
Script* script,
string_view source_filename,
string_view module_filename_noext,
std::string_view source_filename,
std::string_view module_filename_noext,
const WriteBinaryOptions& options,
std::vector<FilenameMemoryStreamPair>* out_module_streams,
Stream* log_stream) {
WriteBinarySpecStreamFactory module_stream_factory =
[&](string_view filename) {
out_module_streams->emplace_back(filename,
MakeUnique<MemoryStream>(log_stream));
[&](std::string_view filename) {
out_module_streams->emplace_back(
filename, std::make_unique<MemoryStream>(log_stream));
return out_module_streams->back().stream.get();
};

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
#include "src/binary-writer.h"
#include "wabt/binary-writer.h"
#include <cassert>
#include <cmath>
@ -22,16 +22,17 @@
#include <cstdint>
#include <cstdio>
#include <set>
#include <string_view>
#include <vector>
#include "config.h"
#include "wabt/config.h"
#include "src/binary.h"
#include "src/cast.h"
#include "src/ir.h"
#include "src/leb128.h"
#include "src/stream.h"
#include "src/string-view.h"
#include "wabt/binary.h"
#include "wabt/cast.h"
#include "wabt/expr-visitor.h"
#include "wabt/ir.h"
#include "wabt/leb128.h"
#include "wabt/stream.h"
#define PRINT_HEADER_NO_INDEX -1
#define MAX_U32_LEB128_BYTES 5
@ -39,7 +40,7 @@
namespace wabt {
void WriteStr(Stream* stream,
string_view s,
std::string_view s,
const char* desc,
PrintChars print_chars) {
WriteU32Leb128(stream, s.length(), "string length");
@ -56,7 +57,11 @@ void WriteOpcode(Stream* stream, Opcode opcode) {
}
void WriteType(Stream* stream, Type type, const char* desc) {
WriteS32Leb128(stream, type, desc ? desc : type.GetName());
WriteS32Leb128(stream, type, desc ? desc : type.GetName().c_str());
if (type.IsReferenceWithIndex()) {
WriteS32Leb128(stream, type.GetReferenceIndex(),
desc ? desc : type.GetName().c_str());
}
}
void WriteLimits(Stream* stream, const Limits* limits) {
@ -73,12 +78,12 @@ void WriteLimits(Stream* stream, const Limits* limits) {
WriteU32Leb128(stream, limits->initial, "limits: initial");
if (limits->has_max) {
WriteU32Leb128(stream, limits->max, "limits: max");
}
}
}
}
void WriteDebugName(Stream* stream, string_view name, const char* desc) {
string_view stripped_name = name;
void WriteDebugName(Stream* stream, std::string_view name, const char* desc) {
std::string_view stripped_name = name;
if (!stripped_name.empty()) {
// Strip leading $ from name
assert(stripped_name.front() == '$');
@ -91,7 +96,7 @@ namespace {
/* TODO(binji): better leb size guess. Some sections we know will only be 1
byte, but others we can be fairly certain will be larger. */
static const size_t LEB_SECTION_SIZE_GUESS = 1;
constexpr size_t LEB_SECTION_SIZE_GUESS = 1;
#define ALLOC_FAILURE \
fprintf(stderr, "%s:%d: allocation failed\n", __FILE__, __LINE__)
@ -136,7 +141,7 @@ class Symbol {
private:
SymbolType type_;
string_view name_;
std::string_view name_;
uint8_t flags_;
union {
Function function_;
@ -148,21 +153,21 @@ class Symbol {
};
public:
Symbol(const string_view& name, uint8_t flags, const Function& f)
Symbol(const std::string_view& name, uint8_t flags, const Function& f)
: type_(Function::type), name_(name), flags_(flags), function_(f) {}
Symbol(const string_view& name, uint8_t flags, const Data& d)
Symbol(const std::string_view& name, uint8_t flags, const Data& d)
: type_(Data::type), name_(name), flags_(flags), data_(d) {}
Symbol(const string_view& name, uint8_t flags, const Global& g)
Symbol(const std::string_view& name, uint8_t flags, const Global& g)
: type_(Global::type), name_(name), flags_(flags), global_(g) {}
Symbol(const string_view& name, uint8_t flags, const Section& s)
Symbol(const std::string_view& name, uint8_t flags, const Section& s)
: type_(Section::type), name_(name), flags_(flags), section_(s) {}
Symbol(const string_view& name, uint8_t flags, const Tag& e)
Symbol(const std::string_view& name, uint8_t flags, const Tag& e)
: type_(Tag::type), name_(name), flags_(flags), tag_(e) {}
Symbol(const string_view& name, uint8_t flags, const Table& t)
Symbol(const std::string_view& name, uint8_t flags, const Table& t)
: type_(Table::type), name_(name), flags_(flags), table_(t) {}
SymbolType type() const { return type_; }
const string_view& name() const { return name_; }
const std::string_view& name() const { return name_; }
uint8_t flags() const { return flags_; }
SymbolVisibility visibility() const {
@ -174,7 +179,9 @@ class Symbol {
bool undefined() const { return flags() & WABT_SYMBOL_FLAG_UNDEFINED; }
bool defined() const { return !undefined(); }
bool exported() const { return flags() & WABT_SYMBOL_FLAG_EXPORTED; }
bool explicit_name() const { return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME; }
bool explicit_name() const {
return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME;
}
bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; }
bool IsFunction() const { return type() == Function::type; }
@ -219,12 +226,14 @@ class SymbolTable {
std::vector<Index> tables_;
std::vector<Index> globals_;
std::set<string_view> seen_names_;
std::set<std::string_view> seen_names_;
Result EnsureUnique(const string_view& name) {
Result EnsureUnique(const std::string_view& name) {
if (seen_names_.count(name)) {
fprintf(stderr, "error: duplicate symbol when writing relocatable "
"binary: %s\n", &name[0]);
fprintf(stderr,
"error: duplicate symbol when writing relocatable "
"binary: %s\n",
&name[0]);
return Result::Error;
}
seen_names_.insert(name);
@ -232,15 +241,18 @@ class SymbolTable {
};
template <typename T>
Result AddSymbol(std::vector<Index>* map, string_view name,
bool imported, bool exported, T&& sym) {
Result AddSymbol(std::vector<Index>* map,
std::string_view name,
bool imported,
bool exported,
T&& sym) {
uint8_t flags = 0;
if (imported) {
flags |= WABT_SYMBOL_FLAG_UNDEFINED;
// Wabt currently has no way for a user to explicitly specify the name of
// an import, so never set the EXPLICIT_NAME flag, and ignore any display
// name fabricated by wabt.
name = string_view();
name = std::string_view();
} else {
if (name.empty()) {
// Definitions without a name are local.
@ -286,20 +298,20 @@ class SymbolTable {
for (const Export* export_ : module->exports) {
switch (export_->kind) {
case ExternalKind::Func:
exported_funcs.insert(module->GetFuncIndex(export_->var));
break;
case ExternalKind::Table:
exported_tables.insert(module->GetTableIndex(export_->var));
break;
case ExternalKind::Memory:
break;
case ExternalKind::Global:
exported_globals.insert(module->GetGlobalIndex(export_->var));
break;
case ExternalKind::Tag:
exported_tags.insert(module->GetTagIndex(export_->var));
break;
case ExternalKind::Func:
exported_funcs.insert(module->GetFuncIndex(export_->var));
break;
case ExternalKind::Table:
exported_tables.insert(module->GetTableIndex(export_->var));
break;
case ExternalKind::Memory:
break;
case ExternalKind::Global:
exported_globals.insert(module->GetGlobalIndex(export_->var));
break;
case ExternalKind::Tag:
exported_tags.insert(module->GetTagIndex(export_->var));
break;
}
}
@ -344,6 +356,23 @@ class SymbolTable {
}
};
struct CodeMetadata {
Offset offset;
std::vector<uint8_t> data;
CodeMetadata(Offset offset, std::vector<uint8_t> data)
: offset(offset), data(std::move(data)) {}
};
struct FuncCodeMetadata {
Index func_idx;
std::vector<CodeMetadata> entries;
FuncCodeMetadata(Index func_idx) : func_idx(func_idx) {}
};
struct CodeMetadataSection {
std::vector<FuncCodeMetadata> entries;
};
using CodeMetadataSections =
std::unordered_map<std::string_view, CodeMetadataSection>;
class BinaryWriter {
WABT_DISALLOW_COPY_AND_ASSIGN(BinaryWriter);
@ -382,7 +411,9 @@ class BinaryWriter {
template <typename T>
void WriteLoadStoreExpr(const Func* func, const Expr* expr, const char* desc);
template <typename T>
void WriteSimdLoadStoreLaneExpr(const Func* func, const Expr* expr, const char* desc);
void WriteSimdLoadStoreLaneExpr(const Func* func,
const Expr* expr,
const char* desc);
void WriteExpr(const Func* func, const Expr* expr);
void WriteExprList(const Func* func, const ExprList& exprs);
void WriteInitExpr(const ExprList& expr);
@ -396,6 +427,7 @@ class BinaryWriter {
void WriteLinkingSection();
template <typename T>
void WriteNames(const std::vector<T*>& elems, NameSectionSubsection type);
void WriteCodeMetadataSections();
Stream* stream_;
const WriteBinaryOptions& options_;
@ -421,6 +453,10 @@ class BinaryWriter {
size_t data_count_start_ = 0;
size_t data_count_end_ = 0;
bool has_data_segment_instruction_ = false;
CodeMetadataSections code_metadata_sections_;
Offset cur_func_start_offset_;
Index cur_func_index_;
};
static uint8_t log2_u32(uint32_t x) {
@ -494,7 +530,8 @@ void BinaryWriter::WriteBlockDecl(const BlockDeclaration& decl) {
Index index = decl.has_func_type ? module_->GetFuncTypeIndex(decl.type_var)
: module_->GetFuncTypeIndex(decl.sig);
assert(index != kInvalidIndex);
WriteS32Leb128WithReloc(index, "block type function index", RelocType::TypeIndexLEB);
WriteS32Leb128WithReloc(index, "block type function index",
RelocType::TypeIndexLEB);
}
void BinaryWriter::WriteSectionHeader(const char* desc,
@ -579,7 +616,8 @@ void BinaryWriter::AddReloc(RelocType reloc_type, Index index) {
// Add a new reloc section if needed
if (!current_reloc_section_ ||
current_reloc_section_->section_index != section_count_) {
reloc_sections_.emplace_back(GetSectionName(last_section_type_), section_count_);
reloc_sections_.emplace_back(GetSectionName(last_section_type_),
section_count_);
current_reloc_section_ = &reloc_sections_.back();
}
@ -618,8 +656,7 @@ void BinaryWriter::WriteS32Leb128WithReloc(int32_t value,
}
}
void BinaryWriter::WriteTableNumberWithReloc(Index value,
const char* desc) {
void BinaryWriter::WriteTableNumberWithReloc(Index value, const char* desc) {
// Unless reference types are enabled, all references to tables refer to table
// 0, so no relocs need be emitted when making relocatable binaries.
if (options_.relocatable && options_.features.reference_types_enabled()) {
@ -650,7 +687,13 @@ void BinaryWriter::WriteLoadStoreExpr(const Func* func,
auto* typed_expr = cast<T>(expr);
WriteOpcode(stream_, typed_expr->opcode);
Address align = typed_expr->opcode.GetAlignment(typed_expr->align);
stream_->WriteU8(log2_u32(align), "alignment");
Index memidx = module_->GetMemoryIndex(typed_expr->memidx);
if (memidx != 0) {
stream_->WriteU8(log2_u32(align) | (1 << 6), "alignment");
WriteU32Leb128(stream_, memidx, "memidx");
} else {
stream_->WriteU8(log2_u32(align), "alignment");
}
WriteU32Leb128(stream_, typed_expr->offset, desc);
}
@ -658,11 +701,8 @@ template <typename T>
void BinaryWriter::WriteSimdLoadStoreLaneExpr(const Func* func,
const Expr* expr,
const char* desc) {
WriteLoadStoreExpr<T>(func, expr, desc);
auto* typed_expr = cast<T>(expr);
WriteOpcode(stream_, typed_expr->opcode);
Address align = typed_expr->opcode.GetAlignment(typed_expr->align);
stream_->WriteU8(log2_u32(align), "alignment");
WriteU32Leb128(stream_, typed_expr->offset, desc);
stream_->WriteU8(static_cast<uint8_t>(typed_expr->val), "Simd Lane literal");
}
@ -725,7 +765,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
WriteU32Leb128(stream_, depth, "break depth for default");
break;
}
case ExprType::Call:{
case ExprType::Call: {
Index index = module_->GetFuncIndex(cast<CallExpr>(expr)->var);
WriteOpcode(stream_, Opcode::Call);
WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB);
@ -737,17 +777,18 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB);
break;
}
case ExprType::CallIndirect:{
case ExprType::CallIndirect: {
Index sig_index =
module_->GetFuncTypeIndex(cast<CallIndirectExpr>(expr)->decl);
module_->GetFuncTypeIndex(cast<CallIndirectExpr>(expr)->decl);
Index table_index =
module_->GetTableIndex(cast<CallIndirectExpr>(expr)->table);
module_->GetTableIndex(cast<CallIndirectExpr>(expr)->table);
WriteOpcode(stream_, Opcode::CallIndirect);
WriteU32Leb128WithReloc(sig_index, "signature index", RelocType::TypeIndexLEB);
WriteU32Leb128WithReloc(sig_index, "signature index",
RelocType::TypeIndexLEB);
WriteTableNumberWithReloc(table_index, "table index");
break;
}
case ExprType::CallRef:{
case ExprType::CallRef: {
WriteOpcode(stream_, Opcode::CallRef);
break;
}
@ -757,7 +798,8 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
Index table_index =
module_->GetTableIndex(cast<ReturnCallIndirectExpr>(expr)->table);
WriteOpcode(stream_, Opcode::ReturnCallIndirect);
WriteU32Leb128WithReloc(sig_index, "signature index", RelocType::TypeIndexLEB);
WriteU32Leb128WithReloc(sig_index, "signature index",
RelocType::TypeIndexLEB);
WriteTableNumberWithReloc(table_index, "table index");
break;
}
@ -850,40 +892,55 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
WriteExprList(func, cast<LoopExpr>(expr)->block.exprs);
WriteOpcode(stream_, Opcode::End);
break;
case ExprType::MemoryCopy:
case ExprType::MemoryCopy: {
Index srcmemidx =
module_->GetMemoryIndex(cast<MemoryCopyExpr>(expr)->srcmemidx);
Index destmemidx =
module_->GetMemoryIndex(cast<MemoryCopyExpr>(expr)->destmemidx);
WriteOpcode(stream_, Opcode::MemoryCopy);
WriteU32Leb128(stream_, 0, "memory.copy reserved");
WriteU32Leb128(stream_, 0, "memory.copy reserved");
WriteU32Leb128(stream_, srcmemidx, "memory.copy srcmemidx");
WriteU32Leb128(stream_, destmemidx, "memory.copy destmemidx");
break;
}
case ExprType::DataDrop: {
Index index =
module_->GetDataSegmentIndex(cast<DataDropExpr>(expr)->var);
Index index = module_->GetDataSegmentIndex(cast<DataDropExpr>(expr)->var);
WriteOpcode(stream_, Opcode::DataDrop);
WriteU32Leb128(stream_, index, "data.drop segment");
has_data_segment_instruction_ = true;
break;
}
case ExprType::MemoryFill:
case ExprType::MemoryFill: {
Index memidx =
module_->GetMemoryIndex(cast<MemoryFillExpr>(expr)->memidx);
WriteOpcode(stream_, Opcode::MemoryFill);
WriteU32Leb128(stream_, 0, "memory.fill reserved");
WriteU32Leb128(stream_, memidx, "memory.fill memidx");
break;
case ExprType::MemoryGrow:
}
case ExprType::MemoryGrow: {
Index memidx =
module_->GetMemoryIndex(cast<MemoryGrowExpr>(expr)->memidx);
WriteOpcode(stream_, Opcode::MemoryGrow);
WriteU32Leb128(stream_, 0, "memory.grow reserved");
WriteU32Leb128(stream_, memidx, "memory.grow memidx");
break;
}
case ExprType::MemoryInit: {
Index index =
module_->GetDataSegmentIndex(cast<MemoryInitExpr>(expr)->var);
Index memidx =
module_->GetMemoryIndex(cast<MemoryInitExpr>(expr)->memidx);
WriteOpcode(stream_, Opcode::MemoryInit);
WriteU32Leb128(stream_, index, "memory.init segment");
WriteU32Leb128(stream_, 0, "memory.init reserved");
WriteU32Leb128(stream_, memidx, "memory.init memidx");
has_data_segment_instruction_ = true;
break;
}
case ExprType::MemorySize:
case ExprType::MemorySize: {
Index memidx =
module_->GetMemoryIndex(cast<MemorySizeExpr>(expr)->memidx);
WriteOpcode(stream_, Opcode::MemorySize);
WriteU32Leb128(stream_, 0, "memory.size reserved");
WriteU32Leb128(stream_, memidx, "memory.size memidx");
break;
}
case ExprType::TableCopy: {
auto* copy_expr = cast<TableCopyExpr>(expr);
Index dst = module_->GetTableIndex(copy_expr->dst_table);
@ -894,8 +951,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
break;
}
case ExprType::ElemDrop: {
Index index =
module_->GetElemSegmentIndex(cast<ElemDropExpr>(expr)->var);
Index index = module_->GetElemSegmentIndex(cast<ElemDropExpr>(expr)->var);
WriteOpcode(stream_, Opcode::ElemDrop);
WriteU32Leb128(stream_, index, "elem.drop segment");
break;
@ -911,36 +967,31 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
break;
}
case ExprType::TableGet: {
Index index =
module_->GetTableIndex(cast<TableGetExpr>(expr)->var);
Index index = module_->GetTableIndex(cast<TableGetExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableGet);
WriteTableNumberWithReloc(index, "table.get table index");
break;
}
case ExprType::TableSet: {
Index index =
module_->GetTableIndex(cast<TableSetExpr>(expr)->var);
Index index = module_->GetTableIndex(cast<TableSetExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableSet);
WriteTableNumberWithReloc(index, "table.set table index");
break;
}
case ExprType::TableGrow: {
Index index =
module_->GetTableIndex(cast<TableGrowExpr>(expr)->var);
Index index = module_->GetTableIndex(cast<TableGrowExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableGrow);
WriteTableNumberWithReloc(index, "table.grow table index");
break;
}
case ExprType::TableSize: {
Index index =
module_->GetTableIndex(cast<TableSizeExpr>(expr)->var);
Index index = module_->GetTableIndex(cast<TableSizeExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableSize);
WriteTableNumberWithReloc(index, "table.size table index");
break;
}
case ExprType::TableFill: {
Index index =
module_->GetTableIndex(cast<TableFillExpr>(expr)->var);
Index index = module_->GetTableIndex(cast<TableFillExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableFill);
WriteTableNumberWithReloc(index, "table.fill table index");
break;
@ -1012,8 +1063,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
break;
case TryKind::Delegate:
WriteOpcode(stream_, Opcode::Delegate);
WriteU32Leb128(stream_,
GetLabelVarDepth(&try_expr->delegate_target),
WriteU32Leb128(stream_, GetLabelVarDepth(&try_expr->delegate_target),
"delegate depth");
break;
case TryKind::Plain:
@ -1059,6 +1109,17 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
case ExprType::Unreachable:
WriteOpcode(stream_, Opcode::Unreachable);
break;
case ExprType::CodeMetadata: {
auto* meta_expr = cast<CodeMetadataExpr>(expr);
auto& s = code_metadata_sections_[meta_expr->name];
if (s.entries.empty() || s.entries.back().func_idx != cur_func_index_) {
s.entries.emplace_back(cur_func_index_);
}
auto& a = s.entries.back();
Offset code_offset = stream_->offset() - cur_func_start_offset_;
a.entries.emplace_back(code_offset, meta_expr->data);
break;
}
}
}
@ -1495,31 +1556,25 @@ Result BinaryWriter::WriteModule() {
// preceeded by length
WriteU32Leb128(stream_, segment->elem_exprs.size(), "num elems");
if (flags & SegUseElemExprs) {
for (const ElemExpr& elem_expr : segment->elem_exprs) {
switch (elem_expr.kind) {
case ElemExprKind::RefNull:
WriteOpcode(stream_, Opcode::RefNull);
WriteType(stream_, elem_expr.type, "elem expr ref.null type");
break;
case ElemExprKind::RefFunc:
WriteOpcode(stream_, Opcode::RefFunc);
WriteU32Leb128(stream_, module_->GetFuncIndex(elem_expr.var), "elem expr function index");
break;
}
WriteOpcode(stream_, Opcode::End);
for (const ExprList& elem_expr : segment->elem_exprs) {
WriteInitExpr(elem_expr);
}
} else {
for (const ElemExpr& elem_expr : segment->elem_exprs) {
assert(elem_expr.kind == ElemExprKind::RefFunc);
WriteU32Leb128(stream_, module_->GetFuncIndex(elem_expr.var), "elem function index");
for (const ExprList& elem_expr : segment->elem_exprs) {
assert(elem_expr.size() == 1);
const Expr* expr = &elem_expr.front();
assert(expr->type() == ExprType::RefFunc);
WriteU32Leb128(stream_,
module_->GetFuncIndex(cast<RefFuncExpr>(expr)->var),
"elem function index");
}
}
}
EndSection();
}
if (options_.features.bulk_memory_enabled()) {
if (options_.features.bulk_memory_enabled() &&
module_->data_segments.size()) {
// Keep track of the data count section offset so it can be removed if
// it isn't needed.
data_count_start_ = stream_->offset();
@ -1535,21 +1590,24 @@ Result BinaryWriter::WriteModule() {
WriteU32Leb128(stream_, num_funcs, "num functions");
for (size_t i = 0; i < num_funcs; ++i) {
cur_func_index_ = i + module_->num_func_imports;
WriteHeader("function body", i);
const Func* func = module_->funcs[i + module_->num_func_imports];
const Func* func = module_->funcs[cur_func_index_];
/* TODO(binji): better guess of the size of the function body section */
const Offset leb_size_guess = 1;
Offset body_size_offset =
WriteU32Leb128Space(leb_size_guess, "func body size (guess)");
cur_func_start_offset_ = stream_->offset();
WriteFunc(func);
auto func_start_offset = body_size_offset - last_section_payload_offset_;
auto func_end_offset = stream_->offset() - last_section_payload_offset_;
auto delta = WriteFixupU32Leb128Size(body_size_offset, leb_size_guess,
"FIXUP func body size");
"FIXUP func body size");
if (current_reloc_section_ && delta != 0) {
for (Reloc& reloc : current_reloc_section_->relocations) {
if (reloc.offset >= func_start_offset && reloc.offset <= func_end_offset) {
if (reloc.offset >= func_start_offset &&
reloc.offset <= func_end_offset) {
reloc.offset += delta;
}
}
@ -1560,7 +1618,7 @@ Result BinaryWriter::WriteModule() {
// Remove the DataCount section if there are no instructions that require it.
if (options_.features.bulk_memory_enabled() &&
!has_data_segment_instruction_) {
module_->data_segments.size() && !has_data_segment_instruction_) {
Offset size = stream_->offset() - data_count_end_;
if (size) {
// If the DataCount section was followed by anything, assert that it's
@ -1569,6 +1627,7 @@ Result BinaryWriter::WriteModule() {
assert(data_count_end_ == code_start_);
assert(last_section_type_ == BinarySection::Code);
stream_->MoveData(data_count_start_, data_count_end_, size);
code_start_ = data_count_start_;
}
stream_->Truncate(data_count_start_ + size);
@ -1584,6 +1643,8 @@ Result BinaryWriter::WriteModule() {
}
}
WriteCodeMetadataSections();
if (module_->data_segments.size()) {
BeginKnownSection(BinarySection::Data);
WriteU32Leb128(stream_, module_->data_segments.size(), "num data segments");
@ -1593,7 +1654,13 @@ Result BinaryWriter::WriteModule() {
uint8_t flags = segment->GetFlags(module_);
stream_->WriteU8(flags, "segment flags");
if (!(flags & SegPassive)) {
assert(module_->GetMemoryIndex(segment->memory_var) == 0);
if (options_.features.multi_memory_enabled() &&
(flags & SegExplicitIndex)) {
WriteU32Leb128(stream_, module_->GetMemoryIndex(segment->memory_var),
"memidx");
} else {
assert(module_->GetMemoryIndex(segment->memory_var) == 0);
}
WriteInitExpr(segment->offset);
}
WriteU32Leb128(stream_, segment->data.size(), "data segment size");
@ -1626,17 +1693,25 @@ Result BinaryWriter::WriteModule() {
for (size_t i = 0; i < module_->funcs.size(); ++i) {
const Func* func = module_->funcs[i];
Index num_params_and_locals = func->GetNumParamsAndLocals();
WriteU32Leb128(stream_, i, "function index");
WriteU32Leb128(stream_, num_params_and_locals, "num locals");
MakeTypeBindingReverseMapping(num_params_and_locals, func->bindings,
&index_to_name);
Index num_named = 0;
for (auto s : index_to_name) {
if (!s.empty()) {
num_named++;
}
}
WriteU32Leb128(stream_, i, "function index");
WriteU32Leb128(stream_, num_named, "num locals");
for (size_t j = 0; j < num_params_and_locals; ++j) {
const std::string& name = index_to_name[j];
wabt_snprintf(desc, sizeof(desc), "local name %" PRIzd, j);
WriteU32Leb128(stream_, j, "local index");
WriteDebugName(stream_, name, desc);
if (!name.empty()) {
wabt_snprintf(desc, sizeof(desc), "local name %" PRIzd, j);
WriteU32Leb128(stream_, j, "local index");
WriteDebugName(stream_, name, desc);
}
}
}
EndSubsection();
@ -1649,6 +1724,7 @@ Result BinaryWriter::WriteModule() {
NameSectionSubsection::ElemSegment);
WriteNames<DataSegment>(module_->data_segments,
NameSectionSubsection::DataSegment);
WriteNames<Tag>(module_->tags, NameSectionSubsection::Tag);
EndSection();
}
@ -1663,6 +1739,53 @@ Result BinaryWriter::WriteModule() {
return stream_->result();
}
void BinaryWriter::WriteCodeMetadataSections() {
if (code_metadata_sections_.empty())
return;
section_count_ -= 1;
// We have to increment the code section's index; adjust anything
// that might have captured it.
for (RelocSection& section : reloc_sections_) {
if (section.section_index == section_count_) {
assert(last_section_type_ == BinarySection::Code);
section.section_index += code_metadata_sections_.size();
}
}
MemoryStream tmp_stream;
Stream* main_stream = stream_;
stream_ = &tmp_stream;
for (auto& s : code_metadata_sections_) {
std::string name = "metadata.code.";
name.append(s.first);
auto& section = s.second;
BeginCustomSection(name.c_str());
WriteU32Leb128(stream_, section.entries.size(), "function count");
for (auto& f : section.entries) {
WriteU32Leb128WithReloc(f.func_idx, "function index",
RelocType::FuncIndexLEB);
WriteU32Leb128(stream_, f.entries.size(), "instances count");
for (auto& a : f.entries) {
WriteU32Leb128(stream_, a.offset, "code offset");
WriteU32Leb128(stream_, a.data.size(), "data length");
stream_->WriteData(a.data.data(), a.data.size(), "data",
PrintChars::Yes);
}
}
EndSection();
}
stream_ = main_stream;
auto buf = tmp_stream.ReleaseOutputBuffer();
stream_->MoveData(code_start_ + buf->data.size(), code_start_,
stream_->offset() - code_start_);
stream_->WriteDataAt(code_start_, buf->data.data(), buf->data.size());
stream_->AddOffset(buf->data.size());
code_start_ += buf->data.size();
section_count_ += 1;
last_section_type_ = BinarySection::Code;
}
} // end anonymous namespace
Result WriteBinaryModule(Stream* stream,

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
#include "src/binary.h"
#include "wabt/binary.h"
namespace wabt {
@ -25,8 +25,8 @@ BinarySectionOrder GetSectionOrder(BinarySection sec) {
return BinarySectionOrder::Name;
WABT_FOREACH_BINARY_SECTION(V)
#undef V
default:
WABT_UNREACHABLE;
default:
WABT_UNREACHABLE;
}
}
@ -42,20 +42,26 @@ const char* GetSectionName(BinarySection sec) {
}
}
// clang-format off
const char* NameSubsectionName[] = {
"module",
"function",
"local",
"label",
"type",
"table",
"memory",
"global",
"elemseg",
"dataseg",
"module",
"function",
"local",
"label",
"type",
"table",
"memory",
"global",
"elemseg",
"dataseg",
"tag",
};
// clang-format on
const char* GetNameSectionSubsectionName(NameSectionSubsection subsec) {
static_assert(WABT_ENUM_COUNT(NameSectionSubsection) ==
WABT_ARRAY_SIZE(NameSubsectionName),
"Malformed ExprTypeName array");
return NameSubsectionName[size_t(subsec)];
}

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
#include "src/binding-hash.h"
#include "wabt/binding-hash.h"
#include <algorithm>
#include <vector>
#include "src/ir.h"
#include "wabt/ir.h"
namespace wabt {

File diff suppressed because it is too large Load Diff

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
#include "src/color.h"
#include "wabt/color.h"
#include <cstdlib>
#include "src/common.h"
#include "wabt/common.h"
#if _WIN32
#include <io.h>

View File

@ -14,16 +14,17 @@
* limitations under the License.
*/
#include "src/common.h"
#include "wabt/common.h"
#include <cassert>
#include <cerrno>
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#if COMPILER_IS_MSVC
#include <fcntl.h>
@ -76,8 +77,8 @@ static Result ReadStdin(std::vector<uint8_t>* out_data) {
}
}
Result ReadFile(string_view filename, std::vector<uint8_t>* out_data) {
std::string filename_str = filename.to_string();
Result ReadFile(std::string_view filename, std::vector<uint8_t>* out_data) {
std::string filename_str(filename);
const char* filename_cstr = filename_str.c_str();
if (filename == "-") {

Some files were not shown because too many files have changed in this diff Show More