| /* |
| * 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. |
| */ |
| |
| #include "binary-reader-interpreter.h" |
| |
| #include <assert.h> |
| #include <inttypes.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| |
| #include <vector> |
| |
| #include "binary-error-handler.h" |
| #include "binary-reader-nop.h" |
| #include "interpreter.h" |
| #include "type-checker.h" |
| #include "writer.h" |
| |
| #define CHECK_RESULT(expr) \ |
| do { \ |
| if (WABT_FAILED(expr)) \ |
| return Result::Error; \ |
| } while (0) |
| |
| namespace wabt { |
| |
| namespace { |
| |
| typedef std::vector<uint32_t> Uint32Vector; |
| typedef std::vector<Uint32Vector> Uint32VectorVector; |
| |
| struct Label { |
| Label(uint32_t offset, uint32_t fixup_offset); |
| |
| uint32_t offset; /* branch location in the istream */ |
| uint32_t fixup_offset; |
| }; |
| |
| Label::Label(uint32_t offset, uint32_t fixup_offset) |
| : offset(offset), fixup_offset(fixup_offset) {} |
| |
| struct ElemSegmentInfo { |
| ElemSegmentInfo(uint32_t* dst, uint32_t func_index) |
| : dst(dst), func_index(func_index) {} |
| |
| uint32_t* dst; |
| uint32_t func_index; |
| }; |
| |
| struct DataSegmentInfo { |
| DataSegmentInfo(void* dst_data, const void* src_data, uint32_t size) |
| : dst_data(dst_data), src_data(src_data), size(size) {} |
| |
| void* dst_data; // Not owned. |
| const void* src_data; // Not owned. |
| uint32_t size; |
| }; |
| |
| class BinaryReaderInterpreter : public BinaryReaderNop { |
| public: |
| BinaryReaderInterpreter(InterpreterEnvironment* env, |
| DefinedInterpreterModule* module, |
| size_t istream_offset, |
| BinaryErrorHandler* error_handler); |
| |
| std::unique_ptr<OutputBuffer> ReleaseOutputBuffer(); |
| size_t get_istream_offset() { return istream_offset; } |
| |
| // Implement BinaryReader. |
| virtual bool OnError(const char* message); |
| |
| virtual Result EndModule(); |
| |
| virtual Result OnTypeCount(uint32_t count); |
| virtual Result OnType(uint32_t index, |
| uint32_t param_count, |
| Type* param_types, |
| uint32_t result_count, |
| Type* result_types); |
| |
| virtual Result OnImportCount(uint32_t count); |
| virtual Result OnImport(uint32_t index, |
| StringSlice module_name, |
| StringSlice field_name); |
| virtual Result OnImportFunc(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t func_index, |
| uint32_t sig_index); |
| virtual Result OnImportTable(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t table_index, |
| Type elem_type, |
| const Limits* elem_limits); |
| virtual Result OnImportMemory(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t memory_index, |
| const Limits* page_limits); |
| virtual Result OnImportGlobal(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t global_index, |
| Type type, |
| bool mutable_); |
| |
| virtual Result OnFunctionCount(uint32_t count); |
| virtual Result OnFunction(uint32_t index, uint32_t sig_index); |
| |
| virtual Result OnTable(uint32_t index, |
| Type elem_type, |
| const Limits* elem_limits); |
| |
| virtual Result OnMemory(uint32_t index, const Limits* limits); |
| |
| virtual Result OnGlobalCount(uint32_t count); |
| virtual Result BeginGlobal(uint32_t index, Type type, bool mutable_); |
| virtual Result EndGlobalInitExpr(uint32_t index); |
| |
| virtual Result OnExport(uint32_t index, |
| ExternalKind kind, |
| uint32_t item_index, |
| StringSlice name); |
| |
| virtual Result OnStartFunction(uint32_t func_index); |
| |
| virtual Result BeginFunctionBody(uint32_t index); |
| virtual Result OnLocalDeclCount(uint32_t count); |
| virtual Result OnLocalDecl(uint32_t decl_index, uint32_t count, Type type); |
| |
| virtual Result OnBinaryExpr(Opcode opcode); |
| virtual Result OnBlockExpr(uint32_t num_types, Type* sig_types); |
| virtual Result OnBrExpr(uint32_t depth); |
| virtual Result OnBrIfExpr(uint32_t depth); |
| virtual Result OnBrTableExpr(uint32_t num_targets, |
| uint32_t* target_depths, |
| uint32_t default_target_depth); |
| virtual Result OnCallExpr(uint32_t func_index); |
| virtual Result OnCallIndirectExpr(uint32_t sig_index); |
| virtual Result OnCompareExpr(Opcode opcode); |
| virtual Result OnConvertExpr(Opcode opcode); |
| virtual Result OnCurrentMemoryExpr(); |
| virtual Result OnDropExpr(); |
| virtual Result OnElseExpr(); |
| virtual Result OnEndExpr(); |
| virtual Result OnF32ConstExpr(uint32_t value_bits); |
| virtual Result OnF64ConstExpr(uint64_t value_bits); |
| virtual Result OnGetGlobalExpr(uint32_t global_index); |
| virtual Result OnGetLocalExpr(uint32_t local_index); |
| virtual Result OnGrowMemoryExpr(); |
| virtual Result OnI32ConstExpr(uint32_t value); |
| virtual Result OnI64ConstExpr(uint64_t value); |
| virtual Result OnIfExpr(uint32_t num_types, Type* sig_types); |
| virtual Result OnLoadExpr(Opcode opcode, |
| uint32_t alignment_log2, |
| uint32_t offset); |
| virtual Result OnLoopExpr(uint32_t num_types, Type* sig_types); |
| virtual Result OnNopExpr(); |
| virtual Result OnReturnExpr(); |
| virtual Result OnSelectExpr(); |
| virtual Result OnSetGlobalExpr(uint32_t global_index); |
| virtual Result OnSetLocalExpr(uint32_t local_index); |
| virtual Result OnStoreExpr(Opcode opcode, |
| uint32_t alignment_log2, |
| uint32_t offset); |
| virtual Result OnTeeLocalExpr(uint32_t local_index); |
| virtual Result OnUnaryExpr(Opcode opcode); |
| virtual Result OnUnreachableExpr(); |
| virtual Result EndFunctionBody(uint32_t index); |
| |
| virtual Result EndElemSegmentInitExpr(uint32_t index); |
| virtual Result OnElemSegmentFunctionIndex(uint32_t index, |
| uint32_t func_index); |
| |
| virtual Result OnDataSegmentData(uint32_t index, |
| const void* data, |
| uint32_t size); |
| |
| virtual Result OnInitExprF32ConstExpr(uint32_t index, uint32_t value); |
| virtual Result OnInitExprF64ConstExpr(uint32_t index, uint64_t value); |
| virtual Result OnInitExprGetGlobalExpr(uint32_t index, uint32_t global_index); |
| virtual Result OnInitExprI32ConstExpr(uint32_t index, uint32_t value); |
| virtual Result OnInitExprI64ConstExpr(uint32_t index, uint64_t value); |
| |
| private: |
| Label* GetLabel(uint32_t depth); |
| Label* TopLabel(); |
| void PushLabel(uint32_t offset, uint32_t fixup_offset); |
| void PopLabel(); |
| |
| bool HandleError(uint32_t offset, const char* message); |
| void PrintError(const char* format, ...); |
| static void OnTypecheckerError(const char* msg, void* user_data); |
| |
| uint32_t TranslateSigIndexToEnv(uint32_t sig_index); |
| InterpreterFuncSignature* GetSignatureByEnvIndex(uint32_t sig_index); |
| InterpreterFuncSignature* GetSignatureByModuleIndex(uint32_t sig_index); |
| uint32_t TranslateFuncIndexToEnv(uint32_t func_index); |
| uint32_t TranslateModuleFuncIndexToDefined(uint32_t func_index); |
| InterpreterFunc* GetFuncByEnvIndex(uint32_t func_index); |
| InterpreterFunc* GetFuncByModuleIndex(uint32_t func_index); |
| uint32_t TranslateGlobalIndexToEnv(uint32_t global_index); |
| InterpreterGlobal* GetGlobalByEnvIndex(uint32_t global_index); |
| InterpreterGlobal* GetGlobalByModuleIndex(uint32_t global_index); |
| Type GetGlobalTypeByModuleIndex(uint32_t global_index); |
| uint32_t TranslateLocalIndex(uint32_t local_index); |
| Type GetLocalTypeByIndex(InterpreterFunc* func, uint32_t local_index); |
| |
| uint32_t GetIstreamOffset(); |
| |
| Result EmitDataAt(size_t offset, const void* data, size_t size); |
| Result EmitData(const void* data, size_t size); |
| Result EmitOpcode(Opcode opcode); |
| Result EmitOpcode(InterpreterOpcode opcode); |
| Result EmitI8(uint8_t value); |
| Result EmitI32(uint32_t value); |
| Result EmitI64(uint64_t value); |
| Result EmitI32At(uint32_t offset, uint32_t value); |
| Result EmitDropKeep(uint32_t drop, uint8_t keep); |
| Result AppendFixup(Uint32VectorVector* fixups_vector, uint32_t index); |
| Result EmitBrOffset(uint32_t depth, uint32_t offset); |
| Result GetBrDropKeepCount(uint32_t depth, |
| uint32_t* out_drop_count, |
| uint32_t* out_keep_count); |
| Result GetReturnDropKeepCount(uint32_t* out_drop_count, |
| uint32_t* out_keep_count); |
| Result EmitBr(uint32_t depth, uint32_t drop_count, uint32_t keep_count); |
| Result EmitBrTableOffset(uint32_t depth); |
| Result FixupTopLabel(); |
| Result EmitFuncOffset(DefinedInterpreterFunc* func, uint32_t func_index); |
| |
| Result CheckLocal(uint32_t local_index); |
| Result CheckGlobal(uint32_t global_index); |
| Result CheckImportKind(InterpreterImport* import, ExternalKind expected_kind); |
| Result CheckImportLimits(const Limits* declared_limits, |
| const Limits* actual_limits); |
| Result CheckHasMemory(Opcode opcode); |
| Result CheckAlign(uint32_t alignment_log2, uint32_t natural_alignment); |
| |
| Result AppendExport(InterpreterModule* module, |
| ExternalKind kind, |
| uint32_t item_index, |
| StringSlice name); |
| |
| PrintErrorCallback MakePrintErrorCallback(); |
| static void OnHostImportPrintError(const char* msg, void* user_data); |
| |
| BinaryErrorHandler* error_handler = nullptr; |
| InterpreterEnvironment* env = nullptr; |
| DefinedInterpreterModule* module = nullptr; |
| DefinedInterpreterFunc* current_func = nullptr; |
| TypeCheckerErrorHandler tc_error_handler; |
| TypeChecker typechecker; |
| std::vector<Label> label_stack; |
| Uint32VectorVector func_fixups; |
| Uint32VectorVector depth_fixups; |
| MemoryWriter istream_writer; |
| uint32_t istream_offset = 0; |
| /* mappings from module index space to env index space; this won't just be a |
| * translation, because imported values will be resolved as well */ |
| Uint32Vector sig_index_mapping; |
| Uint32Vector func_index_mapping; |
| Uint32Vector global_index_mapping; |
| |
| uint32_t num_func_imports = 0; |
| uint32_t num_global_imports = 0; |
| |
| // Changes to linear memory and tables should not apply if a validation error |
| // occurs; these vectors cache the changes that must be applied after we know |
| // that there are no validation errors. |
| std::vector<ElemSegmentInfo> elem_segment_infos; |
| std::vector<DataSegmentInfo> data_segment_infos; |
| |
| /* values cached so they can be shared between callbacks */ |
| InterpreterTypedValue init_expr_value; |
| uint32_t table_offset = 0; |
| bool is_host_import = false; |
| HostInterpreterModule* host_import_module = nullptr; |
| uint32_t import_env_index = 0; |
| }; |
| |
| BinaryReaderInterpreter::BinaryReaderInterpreter( |
| InterpreterEnvironment* env, |
| DefinedInterpreterModule* module, |
| size_t istream_offset, |
| BinaryErrorHandler* error_handler) |
| : error_handler(error_handler), |
| env(env), |
| module(module), |
| istream_writer(std::move(env->istream)), |
| istream_offset(istream_offset) { |
| tc_error_handler.on_error = OnTypecheckerError; |
| tc_error_handler.user_data = this; |
| typechecker.error_handler = &tc_error_handler; |
| } |
| |
| std::unique_ptr<OutputBuffer> BinaryReaderInterpreter::ReleaseOutputBuffer() { |
| return istream_writer.ReleaseOutputBuffer(); |
| } |
| |
| Label* BinaryReaderInterpreter::GetLabel(uint32_t depth) { |
| assert(depth < label_stack.size()); |
| return &label_stack[label_stack.size() - depth - 1]; |
| } |
| |
| Label* BinaryReaderInterpreter::TopLabel() { |
| return GetLabel(0); |
| } |
| |
| bool BinaryReaderInterpreter::HandleError(uint32_t offset, |
| const char* message) { |
| return error_handler->OnError(offset, message); |
| } |
| |
| void WABT_PRINTF_FORMAT(2, 3) |
| BinaryReaderInterpreter::PrintError(const char* format, ...) { |
| WABT_SNPRINTF_ALLOCA(buffer, length, format); |
| HandleError(WABT_INVALID_OFFSET, buffer); |
| } |
| |
| // static |
| void BinaryReaderInterpreter::OnTypecheckerError(const char* msg, |
| void* user_data) { |
| static_cast<BinaryReaderInterpreter*>(user_data)->PrintError("%s", msg); |
| } |
| |
| uint32_t BinaryReaderInterpreter::TranslateSigIndexToEnv(uint32_t sig_index) { |
| assert(sig_index < sig_index_mapping.size()); |
| return sig_index_mapping[sig_index]; |
| } |
| |
| InterpreterFuncSignature* BinaryReaderInterpreter::GetSignatureByEnvIndex( |
| uint32_t sig_index) { |
| return &env->sigs[sig_index]; |
| } |
| |
| InterpreterFuncSignature* BinaryReaderInterpreter::GetSignatureByModuleIndex( |
| uint32_t sig_index) { |
| return GetSignatureByEnvIndex(TranslateSigIndexToEnv(sig_index)); |
| } |
| |
| uint32_t BinaryReaderInterpreter::TranslateFuncIndexToEnv(uint32_t func_index) { |
| assert(func_index < func_index_mapping.size()); |
| return func_index_mapping[func_index]; |
| } |
| |
| uint32_t BinaryReaderInterpreter::TranslateModuleFuncIndexToDefined( |
| uint32_t func_index) { |
| assert(func_index >= num_func_imports); |
| return func_index - num_func_imports; |
| } |
| |
| InterpreterFunc* BinaryReaderInterpreter::GetFuncByEnvIndex( |
| uint32_t func_index) { |
| return env->funcs[func_index].get(); |
| } |
| |
| InterpreterFunc* BinaryReaderInterpreter::GetFuncByModuleIndex( |
| uint32_t func_index) { |
| return GetFuncByEnvIndex(TranslateFuncIndexToEnv(func_index)); |
| } |
| |
| uint32_t BinaryReaderInterpreter::TranslateGlobalIndexToEnv( |
| uint32_t global_index) { |
| return global_index_mapping[global_index]; |
| } |
| |
| InterpreterGlobal* BinaryReaderInterpreter::GetGlobalByEnvIndex( |
| uint32_t global_index) { |
| return &env->globals[global_index]; |
| } |
| |
| InterpreterGlobal* BinaryReaderInterpreter::GetGlobalByModuleIndex( |
| uint32_t global_index) { |
| return GetGlobalByEnvIndex(TranslateGlobalIndexToEnv(global_index)); |
| } |
| |
| Type BinaryReaderInterpreter::GetGlobalTypeByModuleIndex( |
| uint32_t global_index) { |
| return GetGlobalByModuleIndex(global_index)->typed_value.type; |
| } |
| |
| Type BinaryReaderInterpreter::GetLocalTypeByIndex(InterpreterFunc* func, |
| uint32_t local_index) { |
| assert(!func->is_host); |
| return func->as_defined()->param_and_local_types[local_index]; |
| } |
| |
| uint32_t BinaryReaderInterpreter::GetIstreamOffset() { |
| return istream_offset; |
| } |
| |
| Result BinaryReaderInterpreter::EmitDataAt(size_t offset, |
| const void* data, |
| size_t size) { |
| return istream_writer.WriteData(offset, data, size); |
| } |
| |
| Result BinaryReaderInterpreter::EmitData(const void* data, size_t size) { |
| CHECK_RESULT(EmitDataAt(istream_offset, data, size)); |
| istream_offset += size; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EmitOpcode(Opcode opcode) { |
| return EmitData(&opcode, sizeof(uint8_t)); |
| } |
| |
| Result BinaryReaderInterpreter::EmitOpcode(InterpreterOpcode opcode) { |
| return EmitData(&opcode, sizeof(uint8_t)); |
| } |
| |
| Result BinaryReaderInterpreter::EmitI8(uint8_t value) { |
| return EmitData(&value, sizeof(value)); |
| } |
| |
| Result BinaryReaderInterpreter::EmitI32(uint32_t value) { |
| return EmitData(&value, sizeof(value)); |
| } |
| |
| Result BinaryReaderInterpreter::EmitI64(uint64_t value) { |
| return EmitData(&value, sizeof(value)); |
| } |
| |
| Result BinaryReaderInterpreter::EmitI32At(uint32_t offset, uint32_t value) { |
| return EmitDataAt(offset, &value, sizeof(value)); |
| } |
| |
| Result BinaryReaderInterpreter::EmitDropKeep(uint32_t drop, uint8_t keep) { |
| assert(drop != UINT32_MAX); |
| assert(keep <= 1); |
| if (drop > 0) { |
| if (drop == 1 && keep == 0) { |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Drop)); |
| } else { |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::DropKeep)); |
| CHECK_RESULT(EmitI32(drop)); |
| CHECK_RESULT(EmitI8(keep)); |
| } |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::AppendFixup(Uint32VectorVector* fixups_vector, |
| uint32_t index) { |
| if (index >= fixups_vector->size()) |
| fixups_vector->resize(index + 1); |
| (*fixups_vector)[index].push_back(GetIstreamOffset()); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EmitBrOffset(uint32_t depth, uint32_t offset) { |
| if (offset == WABT_INVALID_OFFSET) { |
| /* depth_fixups stores the depth counting up from zero, where zero is the |
| * top-level function scope. */ |
| depth = label_stack.size() - 1 - depth; |
| CHECK_RESULT(AppendFixup(&depth_fixups, depth)); |
| } |
| CHECK_RESULT(EmitI32(offset)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::GetBrDropKeepCount(uint32_t depth, |
| uint32_t* out_drop_count, |
| uint32_t* out_keep_count) { |
| TypeCheckerLabel* label; |
| CHECK_RESULT(typechecker_get_label(&typechecker, depth, &label)); |
| *out_keep_count = |
| label->label_type != LabelType::Loop ? label->sig.size() : 0; |
| if (typechecker_is_unreachable(&typechecker)) { |
| *out_drop_count = 0; |
| } else { |
| *out_drop_count = |
| (typechecker.type_stack.size() - label->type_stack_limit) - |
| *out_keep_count; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::GetReturnDropKeepCount( |
| uint32_t* out_drop_count, |
| uint32_t* out_keep_count) { |
| if (WABT_FAILED(GetBrDropKeepCount(label_stack.size() - 1, out_drop_count, |
| out_keep_count))) { |
| return Result::Error; |
| } |
| |
| *out_drop_count += current_func->param_and_local_types.size(); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EmitBr(uint32_t depth, |
| uint32_t drop_count, |
| uint32_t keep_count) { |
| CHECK_RESULT(EmitDropKeep(drop_count, keep_count)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Br)); |
| CHECK_RESULT(EmitBrOffset(depth, GetLabel(depth)->offset)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EmitBrTableOffset(uint32_t depth) { |
| uint32_t drop_count, keep_count; |
| CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); |
| CHECK_RESULT(EmitBrOffset(depth, GetLabel(depth)->offset)); |
| CHECK_RESULT(EmitI32(drop_count)); |
| CHECK_RESULT(EmitI8(keep_count)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::FixupTopLabel() { |
| uint32_t offset = GetIstreamOffset(); |
| uint32_t top = label_stack.size() - 1; |
| if (top >= depth_fixups.size()) { |
| /* nothing to fixup */ |
| return Result::Ok; |
| } |
| |
| Uint32Vector& fixups = depth_fixups[top]; |
| for (uint32_t fixup : fixups) |
| CHECK_RESULT(EmitI32At(fixup, offset)); |
| fixups.clear(); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EmitFuncOffset(DefinedInterpreterFunc* func, |
| uint32_t func_index) { |
| if (func->offset == WABT_INVALID_OFFSET) { |
| uint32_t defined_index = TranslateModuleFuncIndexToDefined(func_index); |
| CHECK_RESULT(AppendFixup(&func_fixups, defined_index)); |
| } |
| CHECK_RESULT(EmitI32(func->offset)); |
| return Result::Ok; |
| } |
| |
| bool BinaryReaderInterpreter::OnError(const char* message) { |
| return HandleError(state->offset, message); |
| } |
| |
| Result BinaryReaderInterpreter::OnTypeCount(uint32_t count) { |
| sig_index_mapping.resize(count); |
| for (uint32_t i = 0; i < count; ++i) |
| sig_index_mapping[i] = env->sigs.size() + i; |
| env->sigs.resize(env->sigs.size() + count); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnType(uint32_t index, |
| uint32_t param_count, |
| Type* param_types, |
| uint32_t result_count, |
| Type* result_types) { |
| InterpreterFuncSignature* sig = GetSignatureByModuleIndex(index); |
| sig->param_types.insert(sig->param_types.end(), param_types, |
| param_types + param_count); |
| sig->result_types.insert(sig->result_types.end(), result_types, |
| result_types + result_count); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnImportCount(uint32_t count) { |
| module->imports.resize(count); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnImport(uint32_t index, |
| StringSlice module_name, |
| StringSlice field_name) { |
| InterpreterImport* import = &module->imports[index]; |
| import->module_name = dup_string_slice(module_name); |
| import->field_name = dup_string_slice(field_name); |
| int module_index = |
| env->registered_module_bindings.find_index(import->module_name); |
| if (module_index < 0) { |
| PrintError("unknown import module \"" PRIstringslice "\"", |
| WABT_PRINTF_STRING_SLICE_ARG(import->module_name)); |
| return Result::Error; |
| } |
| |
| InterpreterModule* module = env->modules[module_index].get(); |
| if (module->is_host) { |
| /* We don't yet know the kind of a host import module, so just assume it |
| * exists for now. We'll fail later (in on_import_* below) if it doesn't |
| * exist). */ |
| is_host_import = true; |
| host_import_module = module->as_host(); |
| } else { |
| InterpreterExport* export_ = |
| get_interpreter_export_by_name(module, &import->field_name); |
| if (!export_) { |
| PrintError("unknown module field \"" PRIstringslice "\"", |
| WABT_PRINTF_STRING_SLICE_ARG(import->field_name)); |
| return Result::Error; |
| } |
| |
| import->kind = export_->kind; |
| is_host_import = false; |
| import_env_index = export_->index; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::CheckLocal(uint32_t local_index) { |
| uint32_t max_local_index = current_func->param_and_local_types.size(); |
| if (local_index >= max_local_index) { |
| PrintError("invalid local_index: %d (max %d)", local_index, |
| max_local_index); |
| return Result::Error; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::CheckGlobal(uint32_t global_index) { |
| uint32_t max_global_index = global_index_mapping.size(); |
| if (global_index >= max_global_index) { |
| PrintError("invalid global_index: %d (max %d)", global_index, |
| max_global_index); |
| return Result::Error; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::CheckImportKind(InterpreterImport* import, |
| ExternalKind expected_kind) { |
| if (import->kind != expected_kind) { |
| PrintError("expected import \"" PRIstringslice "." PRIstringslice |
| "\" to have kind %s, not %s", |
| WABT_PRINTF_STRING_SLICE_ARG(import->module_name), |
| WABT_PRINTF_STRING_SLICE_ARG(import->field_name), |
| get_kind_name(expected_kind), get_kind_name(import->kind)); |
| return Result::Error; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::CheckImportLimits(const Limits* declared_limits, |
| const Limits* actual_limits) { |
| if (actual_limits->initial < declared_limits->initial) { |
| PrintError("actual size (%" PRIu64 ") smaller than declared (%" PRIu64 ")", |
| actual_limits->initial, declared_limits->initial); |
| return Result::Error; |
| } |
| |
| if (declared_limits->has_max) { |
| if (!actual_limits->has_max) { |
| PrintError("max size (unspecified) larger than declared (%" PRIu64 ")", |
| declared_limits->max); |
| return Result::Error; |
| } else if (actual_limits->max > declared_limits->max) { |
| PrintError("max size (%" PRIu64 ") larger than declared (%" PRIu64 ")", |
| actual_limits->max, declared_limits->max); |
| return Result::Error; |
| } |
| } |
| |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::AppendExport(InterpreterModule* module, |
| ExternalKind kind, |
| uint32_t item_index, |
| StringSlice name) { |
| if (module->export_bindings.find_index(name) != -1) { |
| PrintError("duplicate export \"" PRIstringslice "\"", |
| WABT_PRINTF_STRING_SLICE_ARG(name)); |
| return Result::Error; |
| } |
| |
| module->exports.emplace_back(dup_string_slice(name), kind, item_index); |
| InterpreterExport* export_ = &module->exports.back(); |
| |
| module->export_bindings.emplace(string_slice_to_string(export_->name), |
| Binding(module->exports.size() - 1)); |
| return Result::Ok; |
| } |
| |
| // static |
| void BinaryReaderInterpreter::OnHostImportPrintError(const char* msg, |
| void* user_data) { |
| static_cast<BinaryReaderInterpreter*>(user_data)->PrintError("%s", msg); |
| } |
| |
| PrintErrorCallback BinaryReaderInterpreter::MakePrintErrorCallback() { |
| PrintErrorCallback result; |
| result.print_error = OnHostImportPrintError; |
| result.user_data = this; |
| return result; |
| } |
| |
| Result BinaryReaderInterpreter::OnImportFunc(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t func_index, |
| uint32_t sig_index) { |
| InterpreterImport* import = &module->imports[import_index]; |
| import->func.sig_index = TranslateSigIndexToEnv(sig_index); |
| |
| uint32_t func_env_index; |
| if (is_host_import) { |
| HostInterpreterFunc* func = new HostInterpreterFunc( |
| import->module_name, import->field_name, import->func.sig_index); |
| |
| env->funcs.emplace_back(func); |
| |
| InterpreterHostImportDelegate* host_delegate = |
| &host_import_module->import_delegate; |
| InterpreterFuncSignature* sig = &env->sigs[func->sig_index]; |
| CHECK_RESULT(host_delegate->import_func( |
| import, func, sig, MakePrintErrorCallback(), host_delegate->user_data)); |
| assert(func->callback); |
| |
| func_env_index = env->funcs.size() - 1; |
| AppendExport(host_import_module, ExternalKind::Func, func_env_index, |
| import->field_name); |
| } else { |
| CHECK_RESULT(CheckImportKind(import, ExternalKind::Func)); |
| InterpreterFunc* func = env->funcs[import_env_index].get(); |
| if (!func_signatures_are_equal(env, import->func.sig_index, |
| func->sig_index)) { |
| PrintError("import signature mismatch"); |
| return Result::Error; |
| } |
| |
| func_env_index = import_env_index; |
| } |
| func_index_mapping.push_back(func_env_index); |
| num_func_imports++; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnImportTable(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t table_index, |
| Type elem_type, |
| const Limits* elem_limits) { |
| if (module->table_index != WABT_INVALID_INDEX) { |
| PrintError("only one table allowed"); |
| return Result::Error; |
| } |
| |
| InterpreterImport* import = &module->imports[import_index]; |
| |
| if (is_host_import) { |
| env->tables.emplace_back(*elem_limits); |
| InterpreterTable* table = &env->tables.back(); |
| |
| InterpreterHostImportDelegate* host_delegate = |
| &host_import_module->import_delegate; |
| CHECK_RESULT(host_delegate->import_table( |
| import, table, MakePrintErrorCallback(), host_delegate->user_data)); |
| |
| CHECK_RESULT(CheckImportLimits(elem_limits, &table->limits)); |
| |
| module->table_index = env->tables.size() - 1; |
| AppendExport(host_import_module, ExternalKind::Table, module->table_index, |
| import->field_name); |
| } else { |
| CHECK_RESULT(CheckImportKind(import, ExternalKind::Table)); |
| InterpreterTable* table = &env->tables[import_env_index]; |
| CHECK_RESULT(CheckImportLimits(elem_limits, &table->limits)); |
| |
| import->table.limits = *elem_limits; |
| module->table_index = import_env_index; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnImportMemory(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t memory_index, |
| const Limits* page_limits) { |
| if (module->memory_index != WABT_INVALID_INDEX) { |
| PrintError("only one memory allowed"); |
| return Result::Error; |
| } |
| |
| InterpreterImport* import = &module->imports[import_index]; |
| |
| if (is_host_import) { |
| env->memories.emplace_back(); |
| InterpreterMemory* memory = &env->memories.back(); |
| |
| InterpreterHostImportDelegate* host_delegate = |
| &host_import_module->import_delegate; |
| CHECK_RESULT(host_delegate->import_memory( |
| import, memory, MakePrintErrorCallback(), host_delegate->user_data)); |
| |
| CHECK_RESULT(CheckImportLimits(page_limits, &memory->page_limits)); |
| |
| module->memory_index = env->memories.size() - 1; |
| AppendExport(host_import_module, ExternalKind::Memory, module->memory_index, |
| import->field_name); |
| } else { |
| CHECK_RESULT(CheckImportKind(import, ExternalKind::Memory)); |
| InterpreterMemory* memory = &env->memories[import_env_index]; |
| CHECK_RESULT(CheckImportLimits(page_limits, &memory->page_limits)); |
| |
| import->memory.limits = *page_limits; |
| module->memory_index = import_env_index; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnImportGlobal(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t global_index, |
| Type type, |
| bool mutable_) { |
| InterpreterImport* import = &module->imports[import_index]; |
| |
| uint32_t global_env_index = env->globals.size() - 1; |
| if (is_host_import) { |
| env->globals.emplace_back(InterpreterTypedValue(type), mutable_); |
| InterpreterGlobal* global = &env->globals.back(); |
| |
| InterpreterHostImportDelegate* host_delegate = |
| &host_import_module->import_delegate; |
| CHECK_RESULT(host_delegate->import_global( |
| import, global, MakePrintErrorCallback(), host_delegate->user_data)); |
| |
| global_env_index = env->globals.size() - 1; |
| AppendExport(host_import_module, ExternalKind::Global, global_env_index, |
| import->field_name); |
| } else { |
| CHECK_RESULT(CheckImportKind(import, ExternalKind::Global)); |
| // TODO: check type and mutability |
| import->global.type = type; |
| import->global.mutable_ = mutable_; |
| global_env_index = import_env_index; |
| } |
| global_index_mapping.push_back(global_env_index); |
| num_global_imports++; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnFunctionCount(uint32_t count) { |
| for (uint32_t i = 0; i < count; ++i) |
| func_index_mapping.push_back(env->funcs.size() + i); |
| env->funcs.reserve(env->funcs.size() + count); |
| func_fixups.resize(count); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnFunction(uint32_t index, uint32_t sig_index) { |
| DefinedInterpreterFunc* func = |
| new DefinedInterpreterFunc(TranslateSigIndexToEnv(sig_index)); |
| env->funcs.emplace_back(func); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnTable(uint32_t index, |
| Type elem_type, |
| const Limits* elem_limits) { |
| if (module->table_index != WABT_INVALID_INDEX) { |
| PrintError("only one table allowed"); |
| return Result::Error; |
| } |
| env->tables.emplace_back(*elem_limits); |
| module->table_index = env->tables.size() - 1; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnMemory(uint32_t index, |
| const Limits* page_limits) { |
| if (module->memory_index != WABT_INVALID_INDEX) { |
| PrintError("only one memory allowed"); |
| return Result::Error; |
| } |
| env->memories.emplace_back(*page_limits); |
| module->memory_index = env->memories.size() - 1; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnGlobalCount(uint32_t count) { |
| for (uint32_t i = 0; i < count; ++i) |
| global_index_mapping.push_back(env->globals.size() + i); |
| env->globals.resize(env->globals.size() + count); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::BeginGlobal(uint32_t index, |
| Type type, |
| bool mutable_) { |
| InterpreterGlobal* global = GetGlobalByModuleIndex(index); |
| global->typed_value.type = type; |
| global->mutable_ = mutable_; |
| init_expr_value.type = Type::Void; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EndGlobalInitExpr(uint32_t index) { |
| InterpreterGlobal* global = GetGlobalByModuleIndex(index); |
| if (init_expr_value.type != global->typed_value.type) { |
| PrintError("type mismatch in global, expected %s but got %s.", |
| get_type_name(global->typed_value.type), |
| get_type_name(init_expr_value.type)); |
| return Result::Error; |
| } |
| global->typed_value = init_expr_value; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnInitExprF32ConstExpr(uint32_t index, |
| uint32_t value_bits) { |
| init_expr_value.type = Type::F32; |
| init_expr_value.value.f32_bits = value_bits; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnInitExprF64ConstExpr(uint32_t index, |
| uint64_t value_bits) { |
| init_expr_value.type = Type::F64; |
| init_expr_value.value.f64_bits = value_bits; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnInitExprGetGlobalExpr(uint32_t index, |
| uint32_t global_index) { |
| if (global_index >= num_global_imports) { |
| PrintError("initializer expression can only reference an imported global"); |
| return Result::Error; |
| } |
| InterpreterGlobal* ref_global = GetGlobalByModuleIndex(global_index); |
| if (ref_global->mutable_) { |
| PrintError("initializer expression cannot reference a mutable global"); |
| return Result::Error; |
| } |
| init_expr_value = ref_global->typed_value; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnInitExprI32ConstExpr(uint32_t index, |
| uint32_t value) { |
| init_expr_value.type = Type::I32; |
| init_expr_value.value.i32 = value; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnInitExprI64ConstExpr(uint32_t index, |
| uint64_t value) { |
| init_expr_value.type = Type::I64; |
| init_expr_value.value.i64 = value; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnExport(uint32_t index, |
| ExternalKind kind, |
| uint32_t item_index, |
| StringSlice name) { |
| switch (kind) { |
| case ExternalKind::Func: |
| item_index = TranslateFuncIndexToEnv(item_index); |
| break; |
| |
| case ExternalKind::Table: |
| item_index = module->table_index; |
| break; |
| |
| case ExternalKind::Memory: |
| item_index = module->memory_index; |
| break; |
| |
| case ExternalKind::Global: { |
| item_index = TranslateGlobalIndexToEnv(item_index); |
| InterpreterGlobal* global = &env->globals[item_index]; |
| if (global->mutable_) { |
| PrintError("mutable globals cannot be exported"); |
| return Result::Error; |
| } |
| break; |
| } |
| } |
| return AppendExport(module, kind, item_index, name); |
| } |
| |
| Result BinaryReaderInterpreter::OnStartFunction(uint32_t func_index) { |
| uint32_t start_func_index = TranslateFuncIndexToEnv(func_index); |
| InterpreterFunc* start_func = GetFuncByEnvIndex(start_func_index); |
| InterpreterFuncSignature* sig = GetSignatureByEnvIndex(start_func->sig_index); |
| if (sig->param_types.size() != 0) { |
| PrintError("start function must be nullary"); |
| return Result::Error; |
| } |
| if (sig->result_types.size() != 0) { |
| PrintError("start function must not return anything"); |
| return Result::Error; |
| } |
| module->start_func_index = start_func_index; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EndElemSegmentInitExpr(uint32_t index) { |
| if (init_expr_value.type != Type::I32) { |
| PrintError("type mismatch in elem segment, expected i32 but got %s", |
| get_type_name(init_expr_value.type)); |
| return Result::Error; |
| } |
| table_offset = init_expr_value.value.i32; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnElemSegmentFunctionIndex( |
| |
| uint32_t index, |
| uint32_t func_index) { |
| assert(module->table_index != WABT_INVALID_INDEX); |
| InterpreterTable* table = &env->tables[module->table_index]; |
| if (table_offset >= table->func_indexes.size()) { |
| PrintError("elem segment offset is out of bounds: %u >= max value %" PRIzd, |
| table_offset, table->func_indexes.size()); |
| return Result::Error; |
| } |
| |
| uint32_t max_func_index = func_index_mapping.size(); |
| if (func_index >= max_func_index) { |
| PrintError("invalid func_index: %d (max %d)", func_index, max_func_index); |
| return Result::Error; |
| } |
| |
| elem_segment_infos.emplace_back(&table->func_indexes[table_offset++], |
| TranslateFuncIndexToEnv(func_index)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnDataSegmentData(uint32_t index, |
| const void* src_data, |
| uint32_t size) { |
| assert(module->memory_index != WABT_INVALID_INDEX); |
| InterpreterMemory* memory = &env->memories[module->memory_index]; |
| if (init_expr_value.type != Type::I32) { |
| PrintError("type mismatch in data segment, expected i32 but got %s", |
| get_type_name(init_expr_value.type)); |
| return Result::Error; |
| } |
| uint32_t address = init_expr_value.value.i32; |
| uint64_t end_address = |
| static_cast<uint64_t>(address) + static_cast<uint64_t>(size); |
| if (end_address > memory->data.size()) { |
| PrintError("data segment is out of bounds: [%u, %" PRIu64 |
| ") >= max value %" PRIzd, |
| address, end_address, memory->data.size()); |
| return Result::Error; |
| } |
| |
| if (size > 0) |
| data_segment_infos.emplace_back(&memory->data[address], src_data, size); |
| |
| return Result::Ok; |
| } |
| |
| void BinaryReaderInterpreter::PushLabel(uint32_t offset, |
| uint32_t fixup_offset) { |
| label_stack.emplace_back(offset, fixup_offset); |
| } |
| |
| void BinaryReaderInterpreter::PopLabel() { |
| label_stack.pop_back(); |
| /* reduce the depth_fixups stack as well, but it may be smaller than |
| * label_stack so only do it conditionally. */ |
| if (depth_fixups.size() > label_stack.size()) { |
| depth_fixups.erase(depth_fixups.begin() + label_stack.size(), |
| depth_fixups.end()); |
| } |
| } |
| |
| Result BinaryReaderInterpreter::BeginFunctionBody(uint32_t index) { |
| DefinedInterpreterFunc* func = GetFuncByModuleIndex(index)->as_defined(); |
| InterpreterFuncSignature* sig = GetSignatureByEnvIndex(func->sig_index); |
| |
| func->offset = GetIstreamOffset(); |
| func->local_decl_count = 0; |
| func->local_count = 0; |
| |
| current_func = func; |
| depth_fixups.clear(); |
| label_stack.clear(); |
| |
| /* fixup function references */ |
| uint32_t defined_index = TranslateModuleFuncIndexToDefined(index); |
| Uint32Vector& fixups = func_fixups[defined_index]; |
| for (uint32_t fixup : fixups) |
| CHECK_RESULT(EmitI32At(fixup, func->offset)); |
| |
| /* append param types */ |
| for (Type param_type : sig->param_types) |
| func->param_and_local_types.push_back(param_type); |
| |
| CHECK_RESULT(typechecker_begin_function(&typechecker, &sig->result_types)); |
| |
| /* push implicit func label (equivalent to return) */ |
| PushLabel(WABT_INVALID_OFFSET, WABT_INVALID_OFFSET); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EndFunctionBody(uint32_t index) { |
| FixupTopLabel(); |
| uint32_t drop_count, keep_count; |
| CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count)); |
| CHECK_RESULT(typechecker_end_function(&typechecker)); |
| CHECK_RESULT(EmitDropKeep(drop_count, keep_count)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Return)); |
| PopLabel(); |
| current_func = nullptr; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnLocalDeclCount(uint32_t count) { |
| current_func->local_decl_count = count; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnLocalDecl(uint32_t decl_index, |
| uint32_t count, |
| Type type) { |
| current_func->local_count += count; |
| |
| for (uint32_t i = 0; i < count; ++i) |
| current_func->param_and_local_types.push_back(type); |
| |
| if (decl_index == current_func->local_decl_count - 1) { |
| /* last local declaration, allocate space for all locals. */ |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Alloca)); |
| CHECK_RESULT(EmitI32(current_func->local_count)); |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::CheckHasMemory(Opcode opcode) { |
| if (module->memory_index == WABT_INVALID_INDEX) { |
| PrintError("%s requires an imported or defined memory.", |
| get_opcode_name(opcode)); |
| return Result::Error; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::CheckAlign(uint32_t alignment_log2, |
| uint32_t natural_alignment) { |
| if (alignment_log2 >= 32 || (1U << alignment_log2) > natural_alignment) { |
| PrintError("alignment must not be larger than natural alignment (%u)", |
| natural_alignment); |
| return Result::Error; |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnUnaryExpr(Opcode opcode) { |
| CHECK_RESULT(typechecker_on_unary(&typechecker, opcode)); |
| CHECK_RESULT(EmitOpcode(opcode)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnBinaryExpr(Opcode opcode) { |
| CHECK_RESULT(typechecker_on_binary(&typechecker, opcode)); |
| CHECK_RESULT(EmitOpcode(opcode)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnBlockExpr(uint32_t num_types, |
| Type* sig_types) { |
| TypeVector sig(sig_types, sig_types + num_types); |
| CHECK_RESULT(typechecker_on_block(&typechecker, &sig)); |
| PushLabel(WABT_INVALID_OFFSET, WABT_INVALID_OFFSET); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnLoopExpr(uint32_t num_types, |
| Type* sig_types) { |
| TypeVector sig(sig_types, sig_types + num_types); |
| CHECK_RESULT(typechecker_on_loop(&typechecker, &sig)); |
| PushLabel(GetIstreamOffset(), WABT_INVALID_OFFSET); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnIfExpr(uint32_t num_types, Type* sig_types) { |
| TypeVector sig(sig_types, sig_types + num_types); |
| CHECK_RESULT(typechecker_on_if(&typechecker, &sig)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::BrUnless)); |
| uint32_t fixup_offset = GetIstreamOffset(); |
| CHECK_RESULT(EmitI32(WABT_INVALID_OFFSET)); |
| PushLabel(WABT_INVALID_OFFSET, fixup_offset); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnElseExpr() { |
| CHECK_RESULT(typechecker_on_else(&typechecker)); |
| Label* label = TopLabel(); |
| uint32_t fixup_cond_offset = label->fixup_offset; |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Br)); |
| label->fixup_offset = GetIstreamOffset(); |
| CHECK_RESULT(EmitI32(WABT_INVALID_OFFSET)); |
| CHECK_RESULT(EmitI32At(fixup_cond_offset, GetIstreamOffset())); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnEndExpr() { |
| TypeCheckerLabel* label; |
| CHECK_RESULT(typechecker_get_label(&typechecker, 0, &label)); |
| LabelType label_type = label->label_type; |
| CHECK_RESULT(typechecker_on_end(&typechecker)); |
| if (label_type == LabelType::If || label_type == LabelType::Else) { |
| CHECK_RESULT(EmitI32At(TopLabel()->fixup_offset, GetIstreamOffset())); |
| } |
| FixupTopLabel(); |
| PopLabel(); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnBrExpr(uint32_t depth) { |
| uint32_t drop_count, keep_count; |
| CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); |
| CHECK_RESULT(typechecker_on_br(&typechecker, depth)); |
| CHECK_RESULT(EmitBr(depth, drop_count, keep_count)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnBrIfExpr(uint32_t depth) { |
| uint32_t drop_count, keep_count; |
| CHECK_RESULT(typechecker_on_br_if(&typechecker, depth)); |
| CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); |
| /* flip the br_if so if <cond> is true it can drop values from the stack */ |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::BrUnless)); |
| uint32_t fixup_br_offset = GetIstreamOffset(); |
| CHECK_RESULT(EmitI32(WABT_INVALID_OFFSET)); |
| CHECK_RESULT(EmitBr(depth, drop_count, keep_count)); |
| CHECK_RESULT(EmitI32At(fixup_br_offset, GetIstreamOffset())); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnBrTableExpr(uint32_t num_targets, |
| uint32_t* target_depths, |
| uint32_t default_target_depth) { |
| CHECK_RESULT(typechecker_begin_br_table(&typechecker)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::BrTable)); |
| CHECK_RESULT(EmitI32(num_targets)); |
| uint32_t fixup_table_offset = GetIstreamOffset(); |
| CHECK_RESULT(EmitI32(WABT_INVALID_OFFSET)); |
| /* not necessary for the interpreter, but it makes it easier to disassemble. |
| * This opcode specifies how many bytes of data follow. */ |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Data)); |
| CHECK_RESULT(EmitI32((num_targets + 1) * WABT_TABLE_ENTRY_SIZE)); |
| CHECK_RESULT(EmitI32At(fixup_table_offset, GetIstreamOffset())); |
| |
| for (uint32_t i = 0; i <= num_targets; ++i) { |
| uint32_t depth = i != num_targets ? target_depths[i] : default_target_depth; |
| CHECK_RESULT(typechecker_on_br_table_target(&typechecker, depth)); |
| CHECK_RESULT(EmitBrTableOffset(depth)); |
| } |
| |
| CHECK_RESULT(typechecker_end_br_table(&typechecker)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnCallExpr(uint32_t func_index) { |
| InterpreterFunc* func = GetFuncByModuleIndex(func_index); |
| InterpreterFuncSignature* sig = GetSignatureByEnvIndex(func->sig_index); |
| CHECK_RESULT( |
| typechecker_on_call(&typechecker, &sig->param_types, &sig->result_types)); |
| |
| if (func->is_host) { |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::CallHost)); |
| CHECK_RESULT(EmitI32(TranslateFuncIndexToEnv(func_index))); |
| } else { |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Call)); |
| CHECK_RESULT(EmitFuncOffset(func->as_defined(), func_index)); |
| } |
| |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnCallIndirectExpr(uint32_t sig_index) { |
| if (module->table_index == WABT_INVALID_INDEX) { |
| PrintError("found call_indirect operator, but no table"); |
| return Result::Error; |
| } |
| InterpreterFuncSignature* sig = GetSignatureByModuleIndex(sig_index); |
| CHECK_RESULT(typechecker_on_call_indirect(&typechecker, &sig->param_types, |
| &sig->result_types)); |
| |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::CallIndirect)); |
| CHECK_RESULT(EmitI32(module->table_index)); |
| CHECK_RESULT(EmitI32(TranslateSigIndexToEnv(sig_index))); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnCompareExpr(Opcode opcode) { |
| return OnBinaryExpr(opcode); |
| } |
| |
| Result BinaryReaderInterpreter::OnConvertExpr(Opcode opcode) { |
| return OnUnaryExpr(opcode); |
| } |
| |
| Result BinaryReaderInterpreter::OnDropExpr() { |
| CHECK_RESULT(typechecker_on_drop(&typechecker)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Drop)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnI32ConstExpr(uint32_t value) { |
| CHECK_RESULT(typechecker_on_const(&typechecker, Type::I32)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::I32Const)); |
| CHECK_RESULT(EmitI32(value)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnI64ConstExpr(uint64_t value) { |
| CHECK_RESULT(typechecker_on_const(&typechecker, Type::I64)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::I64Const)); |
| CHECK_RESULT(EmitI64(value)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnF32ConstExpr(uint32_t value_bits) { |
| CHECK_RESULT(typechecker_on_const(&typechecker, Type::F32)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::F32Const)); |
| CHECK_RESULT(EmitI32(value_bits)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnF64ConstExpr(uint64_t value_bits) { |
| CHECK_RESULT(typechecker_on_const(&typechecker, Type::F64)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::F64Const)); |
| CHECK_RESULT(EmitI64(value_bits)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnGetGlobalExpr(uint32_t global_index) { |
| CHECK_RESULT(CheckGlobal(global_index)); |
| Type type = GetGlobalTypeByModuleIndex(global_index); |
| CHECK_RESULT(typechecker_on_get_global(&typechecker, type)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::GetGlobal)); |
| CHECK_RESULT(EmitI32(TranslateGlobalIndexToEnv(global_index))); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnSetGlobalExpr(uint32_t global_index) { |
| CHECK_RESULT(CheckGlobal(global_index)); |
| InterpreterGlobal* global = GetGlobalByModuleIndex(global_index); |
| if (!global->mutable_) { |
| PrintError("can't set_global on immutable global at index %u.", |
| global_index); |
| return Result::Error; |
| } |
| CHECK_RESULT( |
| typechecker_on_set_global(&typechecker, global->typed_value.type)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::SetGlobal)); |
| CHECK_RESULT(EmitI32(TranslateGlobalIndexToEnv(global_index))); |
| return Result::Ok; |
| } |
| |
| uint32_t BinaryReaderInterpreter::TranslateLocalIndex(uint32_t local_index) { |
| return typechecker.type_stack.size() + |
| current_func->param_and_local_types.size() - local_index; |
| } |
| |
| Result BinaryReaderInterpreter::OnGetLocalExpr(uint32_t local_index) { |
| CHECK_RESULT(CheckLocal(local_index)); |
| Type type = GetLocalTypeByIndex(current_func, local_index); |
| /* Get the translated index before calling typechecker_on_get_local |
| * because it will update the type stack size. We need the index to be |
| * relative to the old stack size. */ |
| uint32_t translated_local_index = TranslateLocalIndex(local_index); |
| CHECK_RESULT(typechecker_on_get_local(&typechecker, type)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::GetLocal)); |
| CHECK_RESULT(EmitI32(translated_local_index)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnSetLocalExpr(uint32_t local_index) { |
| CHECK_RESULT(CheckLocal(local_index)); |
| Type type = GetLocalTypeByIndex(current_func, local_index); |
| CHECK_RESULT(typechecker_on_set_local(&typechecker, type)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::SetLocal)); |
| CHECK_RESULT(EmitI32(TranslateLocalIndex(local_index))); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnTeeLocalExpr(uint32_t local_index) { |
| CHECK_RESULT(CheckLocal(local_index)); |
| Type type = GetLocalTypeByIndex(current_func, local_index); |
| CHECK_RESULT(typechecker_on_tee_local(&typechecker, type)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::TeeLocal)); |
| CHECK_RESULT(EmitI32(TranslateLocalIndex(local_index))); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnGrowMemoryExpr() { |
| CHECK_RESULT(CheckHasMemory(Opcode::GrowMemory)); |
| CHECK_RESULT(typechecker_on_grow_memory(&typechecker)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::GrowMemory)); |
| CHECK_RESULT(EmitI32(module->memory_index)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnLoadExpr(Opcode opcode, |
| uint32_t alignment_log2, |
| uint32_t offset) { |
| CHECK_RESULT(CheckHasMemory(opcode)); |
| CHECK_RESULT(CheckAlign(alignment_log2, get_opcode_memory_size(opcode))); |
| CHECK_RESULT(typechecker_on_load(&typechecker, opcode)); |
| CHECK_RESULT(EmitOpcode(opcode)); |
| CHECK_RESULT(EmitI32(module->memory_index)); |
| CHECK_RESULT(EmitI32(offset)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnStoreExpr(Opcode opcode, |
| uint32_t alignment_log2, |
| uint32_t offset) { |
| CHECK_RESULT(CheckHasMemory(opcode)); |
| CHECK_RESULT(CheckAlign(alignment_log2, get_opcode_memory_size(opcode))); |
| CHECK_RESULT(typechecker_on_store(&typechecker, opcode)); |
| CHECK_RESULT(EmitOpcode(opcode)); |
| CHECK_RESULT(EmitI32(module->memory_index)); |
| CHECK_RESULT(EmitI32(offset)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnCurrentMemoryExpr() { |
| CHECK_RESULT(CheckHasMemory(Opcode::CurrentMemory)); |
| CHECK_RESULT(typechecker_on_current_memory(&typechecker)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::CurrentMemory)); |
| CHECK_RESULT(EmitI32(module->memory_index)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnNopExpr() { |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnReturnExpr() { |
| uint32_t drop_count, keep_count; |
| CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count)); |
| CHECK_RESULT(typechecker_on_return(&typechecker)); |
| CHECK_RESULT(EmitDropKeep(drop_count, keep_count)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Return)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnSelectExpr() { |
| CHECK_RESULT(typechecker_on_select(&typechecker)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Select)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::OnUnreachableExpr() { |
| CHECK_RESULT(typechecker_on_unreachable(&typechecker)); |
| CHECK_RESULT(EmitOpcode(InterpreterOpcode::Unreachable)); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderInterpreter::EndModule() { |
| for (ElemSegmentInfo& info : elem_segment_infos) { |
| *info.dst = info.func_index; |
| } |
| for (DataSegmentInfo& info : data_segment_infos) { |
| memcpy(info.dst_data, info.src_data, info.size); |
| } |
| return Result::Ok; |
| } |
| |
| } // namespace |
| |
| Result read_binary_interpreter(InterpreterEnvironment* env, |
| const void* data, |
| size_t size, |
| const ReadBinaryOptions* options, |
| BinaryErrorHandler* error_handler, |
| DefinedInterpreterModule** out_module) { |
| size_t istream_offset = env->istream->data.size(); |
| DefinedInterpreterModule* module = |
| new DefinedInterpreterModule(istream_offset); |
| |
| // Need to mark before constructing the reader since it takes ownership of |
| // env->istream, which makes env->istream == nullptr. |
| InterpreterEnvironmentMark mark = mark_interpreter_environment(env); |
| BinaryReaderInterpreter reader(env, module, istream_offset, error_handler); |
| env->modules.emplace_back(module); |
| |
| Result result = read_binary(data, size, &reader, options); |
| env->istream = reader.ReleaseOutputBuffer(); |
| if (WABT_SUCCEEDED(result)) { |
| env->istream->data.resize(reader.get_istream_offset()); |
| module->istream_end = env->istream->data.size(); |
| *out_module = module; |
| } else { |
| reset_interpreter_environment_to_mark(env, mark); |
| *out_module = nullptr; |
| } |
| return result; |
| } |
| |
| } // namespace wabt |