blob: 37f0e2a1381e93226e72e2b5e17c8a1f240fc6a4 [file] [log] [blame] [edit]
/*
* Copyright 2016 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_INTERPRETER_H_
#define WABT_INTERPRETER_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "common.h"
#include "binding-hash.h"
#include "opcode.h"
#include "writer.h"
namespace wabt {
class Stream;
#define FOREACH_INTERPRETER_RESULT(V) \
V(Ok, "ok") \
/* returned from the top-most function */ \
V(Returned, "returned") \
/* memory access is out of bounds */ \
V(TrapMemoryAccessOutOfBounds, "out of bounds memory access") \
/* converting from float -> int would overflow int */ \
V(TrapIntegerOverflow, "integer overflow") \
/* dividend is zero in integer divide */ \
V(TrapIntegerDivideByZero, "integer divide by zero") \
/* converting from float -> int where float is nan */ \
V(TrapInvalidConversionToInteger, "invalid conversion to integer") \
/* function table index is out of bounds */ \
V(TrapUndefinedTableIndex, "undefined table index") \
/* function table element is uninitialized */ \
V(TrapUninitializedTableElement, "uninitialized table element") \
/* unreachable instruction executed */ \
V(TrapUnreachable, "unreachable executed") \
/* call indirect signature doesn't match function table signature */ \
V(TrapIndirectCallSignatureMismatch, "indirect call signature mismatch") \
/* ran out of call stack frames (probably infinite recursion) */ \
V(TrapCallStackExhausted, "call stack exhausted") \
/* ran out of value stack space */ \
V(TrapValueStackExhausted, "value stack exhausted") \
/* we called a host function, but the return value didn't match the */ \
/* expected type */ \
V(TrapHostResultTypeMismatch, "host result type mismatch") \
/* we called an import function, but it didn't complete succesfully */ \
V(TrapHostTrapped, "host function trapped") \
/* we attempted to call a function with the an argument list that doesn't \
* match the function signature */ \
V(ArgumentTypeMismatch, "argument type mismatch") \
/* we tried to get an export by name that doesn't exist */ \
V(UnknownExport, "unknown export") \
/* the expected export kind doesn't match. */ \
V(ExportKindMismatch, "export kind mismatch")
enum class InterpreterResult {
#define V(Name, str) Name,
FOREACH_INTERPRETER_RESULT(V)
#undef V
};
#define WABT_INVALID_INDEX static_cast<uint32_t>(~0)
#define WABT_INVALID_OFFSET static_cast<uint32_t>(~0)
#define WABT_TABLE_ENTRY_SIZE (sizeof(uint32_t) * 2 + sizeof(uint8_t))
#define WABT_TABLE_ENTRY_OFFSET_OFFSET 0
#define WABT_TABLE_ENTRY_DROP_OFFSET sizeof(uint32_t)
#define WABT_TABLE_ENTRY_KEEP_OFFSET (sizeof(uint32_t) * 2)
enum class InterpreterOpcode {
/* push space on the value stack for N entries */
#define WABT_OPCODE(rtype, type1, type2, mem_size, code, Name, text) Name = code,
#include "interpreter-opcode.def"
#undef WABT_OPCODE
First = static_cast<int>(Opcode::First),
Last = DropKeep,
};
static const int kInterpreterOpcodeCount = WABT_ENUM_COUNT(InterpreterOpcode);
struct InterpreterFuncSignature {
std::vector<Type> param_types;
std::vector<Type> result_types;
};
struct InterpreterTable {
explicit InterpreterTable(const Limits& limits)
: limits(limits), func_indexes(limits.initial, WABT_INVALID_INDEX) {}
Limits limits;
std::vector<uint32_t> func_indexes;
};
struct InterpreterMemory {
InterpreterMemory() {
WABT_ZERO_MEMORY(page_limits);
}
explicit InterpreterMemory(const Limits& limits)
: page_limits(limits), data(limits.initial * WABT_PAGE_SIZE) {}
Limits page_limits;
std::vector<char> data;
};
union InterpreterValue {
uint32_t i32;
uint64_t i64;
uint32_t f32_bits;
uint64_t f64_bits;
};
struct InterpreterTypedValue {
InterpreterTypedValue() {}
explicit InterpreterTypedValue(Type type): type(type) {}
InterpreterTypedValue(Type type, const InterpreterValue& value)
: type(type), value(value) {}
Type type;
InterpreterValue value;
};
struct InterpreterGlobal {
InterpreterGlobal() : mutable_(false), import_index(WABT_INVALID_INDEX) {}
InterpreterGlobal(const InterpreterTypedValue& typed_value, bool mutable_)
: typed_value(typed_value), mutable_(mutable_) {}
InterpreterTypedValue typed_value;
bool mutable_;
uint32_t import_index; /* or INVALID_INDEX if not imported */
};
struct InterpreterImport {
InterpreterImport();
InterpreterImport(InterpreterImport&&);
InterpreterImport& operator=(InterpreterImport&&);
~InterpreterImport();
StringSlice module_name;
StringSlice field_name;
ExternalKind kind;
union {
struct {
uint32_t sig_index;
} func;
struct {
Limits limits;
} table, memory;
struct {
Type type;
bool mutable_;
} global;
};
};
struct InterpreterFunc;
typedef Result (*InterpreterHostFuncCallback)(
const struct HostInterpreterFunc* func,
const InterpreterFuncSignature* sig,
uint32_t num_args,
InterpreterTypedValue* args,
uint32_t num_results,
InterpreterTypedValue* out_results,
void* user_data);
struct InterpreterFunc {
WABT_DISALLOW_COPY_AND_ASSIGN(InterpreterFunc);
InterpreterFunc(uint32_t sig_index, bool is_host)
: sig_index(sig_index), is_host(is_host) {}
virtual ~InterpreterFunc() {}
inline struct DefinedInterpreterFunc* as_defined();
inline struct HostInterpreterFunc* as_host();
uint32_t sig_index;
bool is_host;
};
struct DefinedInterpreterFunc : InterpreterFunc {
DefinedInterpreterFunc(uint32_t sig_index)
: InterpreterFunc(sig_index, false),
offset(WABT_INVALID_INDEX),
local_decl_count(0),
local_count(0) {}
uint32_t offset;
uint32_t local_decl_count;
uint32_t local_count;
std::vector<Type> param_and_local_types;
};
struct HostInterpreterFunc : InterpreterFunc {
HostInterpreterFunc(const StringSlice& module_name,
const StringSlice& field_name,
uint32_t sig_index)
: InterpreterFunc(sig_index, true),
module_name(module_name),
field_name(field_name) {}
StringSlice module_name;
StringSlice field_name;
InterpreterHostFuncCallback callback;
void* user_data;
};
DefinedInterpreterFunc* InterpreterFunc::as_defined() {
assert(!is_host);
return static_cast<DefinedInterpreterFunc*>(this);
}
HostInterpreterFunc* InterpreterFunc::as_host() {
assert(is_host);
return static_cast<HostInterpreterFunc*>(this);
}
struct InterpreterExport {
InterpreterExport(const StringSlice& name, ExternalKind kind, uint32_t index)
: name(name), kind(kind), index(index) {}
InterpreterExport(InterpreterExport&&);
InterpreterExport& operator=(InterpreterExport&&);
~InterpreterExport();
StringSlice name;
ExternalKind kind;
uint32_t index;
};
struct PrintErrorCallback {
void* user_data;
void (*print_error)(const char* msg, void* user_data);
};
struct InterpreterHostImportDelegate {
void* user_data;
Result (*import_func)(InterpreterImport*,
InterpreterFunc*,
InterpreterFuncSignature*,
PrintErrorCallback,
void* user_data);
Result (*import_table)(InterpreterImport*,
InterpreterTable*,
PrintErrorCallback,
void* user_data);
Result (*import_memory)(InterpreterImport*,
InterpreterMemory*,
PrintErrorCallback,
void* user_data);
Result (*import_global)(InterpreterImport*,
InterpreterGlobal*,
PrintErrorCallback,
void* user_data);
};
struct InterpreterModule {
WABT_DISALLOW_COPY_AND_ASSIGN(InterpreterModule);
explicit InterpreterModule(bool is_host);
InterpreterModule(const StringSlice& name, bool is_host);
virtual ~InterpreterModule();
inline struct DefinedInterpreterModule* as_defined();
inline struct HostInterpreterModule* as_host();
StringSlice name;
std::vector<InterpreterExport> exports;
BindingHash export_bindings;
uint32_t memory_index; /* INVALID_INDEX if not defined */
uint32_t table_index; /* INVALID_INDEX if not defined */
bool is_host;
};
struct DefinedInterpreterModule : InterpreterModule {
explicit DefinedInterpreterModule(size_t istream_start);
std::vector<InterpreterImport> imports;
uint32_t start_func_index; /* INVALID_INDEX if not defined */
size_t istream_start;
size_t istream_end;
};
struct HostInterpreterModule : InterpreterModule {
HostInterpreterModule(const StringSlice& name);
InterpreterHostImportDelegate import_delegate;
};
DefinedInterpreterModule* InterpreterModule::as_defined() {
assert(!is_host);
return static_cast<DefinedInterpreterModule*>(this);
}
HostInterpreterModule* InterpreterModule::as_host() {
assert(is_host);
return static_cast<HostInterpreterModule*>(this);
}
/* Used to track and reset the state of the environment. */
struct InterpreterEnvironmentMark {
size_t modules_size;
size_t sigs_size;
size_t funcs_size;
size_t memories_size;
size_t tables_size;
size_t globals_size;
size_t istream_size;
};
struct InterpreterEnvironment {
InterpreterEnvironment();
std::vector<std::unique_ptr<InterpreterModule>> modules;
std::vector<InterpreterFuncSignature> sigs;
std::vector<std::unique_ptr<InterpreterFunc>> funcs;
std::vector<InterpreterMemory> memories;
std::vector<InterpreterTable> tables;
std::vector<InterpreterGlobal> globals;
std::unique_ptr<OutputBuffer> istream;
BindingHash module_bindings;
BindingHash registered_module_bindings;
};
struct InterpreterThread {
InterpreterThread();
InterpreterEnvironment* env;
std::vector<InterpreterValue> value_stack;
std::vector<uint32_t> call_stack;
InterpreterValue* value_stack_top;
InterpreterValue* value_stack_end;
uint32_t* call_stack_top;
uint32_t* call_stack_end;
uint32_t pc;
};
#define WABT_INTERPRETER_THREAD_OPTIONS_DEFAULT \
{ 512 * 1024 / sizeof(InterpreterValue), 64 * 1024, WABT_INVALID_OFFSET }
struct InterpreterThreadOptions {
uint32_t value_stack_size;
uint32_t call_stack_size;
uint32_t pc;
};
bool is_canonical_nan_f32(uint32_t f32_bits);
bool is_canonical_nan_f64(uint64_t f64_bits);
bool is_arithmetic_nan_f32(uint32_t f32_bits);
bool is_arithmetic_nan_f64(uint64_t f64_bits);
bool func_signatures_are_equal(InterpreterEnvironment* env,
uint32_t sig_index_0,
uint32_t sig_index_1);
void destroy_interpreter_environment(InterpreterEnvironment* env);
InterpreterEnvironmentMark mark_interpreter_environment(
InterpreterEnvironment* env);
void reset_interpreter_environment_to_mark(InterpreterEnvironment* env,
InterpreterEnvironmentMark mark);
HostInterpreterModule* append_host_module(InterpreterEnvironment* env,
StringSlice name);
void init_interpreter_thread(InterpreterEnvironment* env,
InterpreterThread* thread,
InterpreterThreadOptions* options);
InterpreterResult push_thread_value(InterpreterThread* thread,
InterpreterValue value);
void destroy_interpreter_thread(InterpreterThread* thread);
InterpreterResult call_host(InterpreterThread* thread,
HostInterpreterFunc* func);
InterpreterResult run_interpreter(InterpreterThread* thread,
uint32_t num_instructions,
uint32_t* call_stack_return_top);
void trace_pc(InterpreterThread* thread, Stream* stream);
void disassemble(InterpreterEnvironment* env,
Stream* stream,
uint32_t from,
uint32_t to);
void disassemble_module(InterpreterEnvironment* env,
Stream* stream,
InterpreterModule* module);
InterpreterExport* get_interpreter_export_by_name(InterpreterModule* module,
const StringSlice* name);
} // namespace wabt
#endif /* WABT_INTERPRETER_H_ */