/* * 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 #include #include #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(~0) #define WABT_INVALID_OFFSET static_cast(~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(Opcode::First), Last = DropKeep, }; static const int kInterpreterOpcodeCount = WABT_ENUM_COUNT(InterpreterOpcode); struct InterpreterFuncSignature { std::vector param_types; std::vector result_types; }; struct InterpreterTable { explicit InterpreterTable(const Limits& limits) : limits(limits), func_indexes(limits.initial, WABT_INVALID_INDEX) {} Limits limits; std::vector 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 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 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(this); } HostInterpreterFunc* InterpreterFunc::as_host() { assert(is_host); return static_cast(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 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 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(this); } HostInterpreterModule* InterpreterModule::as_host() { assert(is_host); return static_cast(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> modules; std::vector sigs; std::vector> funcs; std::vector memories; std::vector tables; std::vector globals; std::unique_ptr istream; BindingHash module_bindings; BindingHash registered_module_bindings; }; struct InterpreterThread { InterpreterThread(); InterpreterEnvironment* env; std::vector value_stack; std::vector 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_ */