diff options
Diffstat (limited to 'src/binary-reader-interp.cc')
-rw-r--r-- | src/binary-reader-interp.cc | 1555 |
1 files changed, 1555 insertions, 0 deletions
diff --git a/src/binary-reader-interp.cc b/src/binary-reader-interp.cc new file mode 100644 index 00000000..a49a38ce --- /dev/null +++ b/src/binary-reader-interp.cc @@ -0,0 +1,1555 @@ +/* + * 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 "src/binary-reader-interp.h" + +#include <cassert> +#include <cinttypes> +#include <cstdarg> +#include <cstdio> +#include <vector> + +#include "src/binary-reader-nop.h" +#include "src/cast.h" +#include "src/error-handler.h" +#include "src/interp.h" +#include "src/stream.h" +#include "src/type-checker.h" + +namespace wabt { + +using namespace interp; + +namespace { + +typedef std::vector<Index> IndexVector; +typedef std::vector<IstreamOffset> IstreamOffsetVector; +typedef std::vector<IstreamOffsetVector> IstreamOffsetVectorVector; + +struct Label { + Label(IstreamOffset offset, IstreamOffset fixup_offset); + + IstreamOffset offset; + IstreamOffset fixup_offset; +}; + +Label::Label(IstreamOffset offset, IstreamOffset fixup_offset) + : offset(offset), fixup_offset(fixup_offset) {} + +struct ElemSegmentInfo { + ElemSegmentInfo(Index* dst, Index func_index) + : dst(dst), func_index(func_index) {} + + Index* dst; + Index func_index; +}; + +struct DataSegmentInfo { + DataSegmentInfo(void* dst_data, const void* src_data, IstreamOffset size) + : dst_data(dst_data), src_data(src_data), size(size) {} + + void* dst_data; // Not owned. + const void* src_data; // Not owned. + IstreamOffset size; +}; + +class BinaryReaderInterp : public BinaryReaderNop { + public: + BinaryReaderInterp(Environment* env, + DefinedModule* module, + std::unique_ptr<OutputBuffer> istream, + ErrorHandler* error_handler); + + wabt::Result ReadBinary(DefinedModule* out_module); + + std::unique_ptr<OutputBuffer> ReleaseOutputBuffer(); + + // Implement BinaryReader. + bool OnError(const char* message) override; + + wabt::Result EndModule() override; + + wabt::Result OnTypeCount(Index count) override; + wabt::Result OnType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) override; + + wabt::Result OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) override; + wabt::Result OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) override; + wabt::Result OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) override; + wabt::Result OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) override; + + wabt::Result OnFunctionCount(Index count) override; + wabt::Result OnFunction(Index index, Index sig_index) override; + + wabt::Result OnTable(Index index, + Type elem_type, + const Limits* elem_limits) override; + + wabt::Result OnMemory(Index index, const Limits* limits) override; + + wabt::Result OnGlobalCount(Index count) override; + wabt::Result BeginGlobal(Index index, Type type, bool mutable_) override; + wabt::Result EndGlobalInitExpr(Index index) override; + + wabt::Result OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) override; + + wabt::Result OnStartFunction(Index func_index) override; + + wabt::Result BeginFunctionBody(Index index) override; + wabt::Result OnLocalDeclCount(Index count) override; + wabt::Result OnLocalDecl(Index decl_index, Index count, Type type) override; + + wabt::Result OnAtomicLoadExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) override; + wabt::Result OnAtomicStoreExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) override; + wabt::Result OnAtomicRmwExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) override; + wabt::Result OnAtomicRmwCmpxchgExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) override; + wabt::Result OnBinaryExpr(wabt::Opcode opcode) override; + wabt::Result OnBlockExpr(Index num_types, Type* sig_types) override; + wabt::Result OnBrExpr(Index depth) override; + wabt::Result OnBrIfExpr(Index depth) override; + wabt::Result OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) override; + wabt::Result OnCallExpr(Index func_index) override; + wabt::Result OnCallIndirectExpr(Index sig_index) override; + wabt::Result OnCompareExpr(wabt::Opcode opcode) override; + wabt::Result OnConvertExpr(wabt::Opcode opcode) override; + wabt::Result OnCurrentMemoryExpr() override; + wabt::Result OnDropExpr() override; + wabt::Result OnElseExpr() override; + wabt::Result OnEndExpr() override; + wabt::Result OnF32ConstExpr(uint32_t value_bits) override; + wabt::Result OnF64ConstExpr(uint64_t value_bits) override; + wabt::Result OnGetGlobalExpr(Index global_index) override; + wabt::Result OnGetLocalExpr(Index local_index) override; + wabt::Result OnGrowMemoryExpr() override; + wabt::Result OnI32ConstExpr(uint32_t value) override; + wabt::Result OnI64ConstExpr(uint64_t value) override; + wabt::Result OnIfExpr(Index num_types, Type* sig_types) override; + wabt::Result OnLoadExpr(wabt::Opcode opcode, + uint32_t alignment_log2, + Address offset) override; + wabt::Result OnLoopExpr(Index num_types, Type* sig_types) override; + wabt::Result OnNopExpr() override; + wabt::Result OnReturnExpr() override; + wabt::Result OnSelectExpr() override; + wabt::Result OnSetGlobalExpr(Index global_index) override; + wabt::Result OnSetLocalExpr(Index local_index) override; + wabt::Result OnStoreExpr(wabt::Opcode opcode, + uint32_t alignment_log2, + Address offset) override; + wabt::Result OnTeeLocalExpr(Index local_index) override; + wabt::Result OnUnaryExpr(wabt::Opcode opcode) override; + wabt::Result OnUnreachableExpr() override; + wabt::Result OnWaitExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) override; + wabt::Result OnWakeExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) override; + wabt::Result EndFunctionBody(Index index) override; + + wabt::Result EndElemSegmentInitExpr(Index index) override; + wabt::Result OnElemSegmentFunctionIndex(Index index, + Index func_index) override; + + wabt::Result OnDataSegmentData(Index index, + const void* data, + Address size) override; + + wabt::Result OnInitExprF32ConstExpr(Index index, uint32_t value) override; + wabt::Result OnInitExprF64ConstExpr(Index index, uint64_t value) override; + wabt::Result OnInitExprGetGlobalExpr(Index index, + Index global_index) override; + wabt::Result OnInitExprI32ConstExpr(Index index, uint32_t value) override; + wabt::Result OnInitExprI64ConstExpr(Index index, uint64_t value) override; + + private: + Label* GetLabel(Index depth); + Label* TopLabel(); + void PushLabel(IstreamOffset offset, IstreamOffset fixup_offset); + void PopLabel(); + + bool HandleError(Offset offset, const char* message); + void PrintError(const char* format, ...); + + Index TranslateSigIndexToEnv(Index sig_index); + FuncSignature* GetSignatureByModuleIndex(Index sig_index); + Index TranslateFuncIndexToEnv(Index func_index); + Index TranslateModuleFuncIndexToDefined(Index func_index); + Func* GetFuncByModuleIndex(Index func_index); + Index TranslateGlobalIndexToEnv(Index global_index); + Global* GetGlobalByModuleIndex(Index global_index); + Type GetGlobalTypeByModuleIndex(Index global_index); + Index TranslateLocalIndex(Index local_index); + Type GetLocalTypeByIndex(Func* func, Index local_index); + + IstreamOffset GetIstreamOffset(); + + wabt::Result EmitDataAt(IstreamOffset offset, + const void* data, + IstreamOffset size); + wabt::Result EmitData(const void* data, IstreamOffset size); + wabt::Result EmitOpcode(Opcode opcode); + wabt::Result EmitI8(uint8_t value); + wabt::Result EmitI32(uint32_t value); + wabt::Result EmitI64(uint64_t value); + wabt::Result EmitI32At(IstreamOffset offset, uint32_t value); + wabt::Result EmitDropKeep(uint32_t drop, uint8_t keep); + wabt::Result AppendFixup(IstreamOffsetVectorVector* fixups_vector, + Index index); + wabt::Result EmitBrOffset(Index depth, IstreamOffset offset); + wabt::Result GetBrDropKeepCount(Index depth, + Index* out_drop_count, + Index* out_keep_count); + wabt::Result GetReturnDropKeepCount(Index* out_drop_count, + Index* out_keep_count); + wabt::Result EmitBr(Index depth, Index drop_count, Index keep_count); + wabt::Result EmitBrTableOffset(Index depth); + wabt::Result FixupTopLabel(); + wabt::Result EmitFuncOffset(DefinedFunc* func, Index func_index); + + wabt::Result CheckLocal(Index local_index); + wabt::Result CheckGlobal(Index global_index); + wabt::Result CheckImportKind(Import* import, ExternalKind expected_kind); + wabt::Result CheckImportLimits(const Limits* declared_limits, + const Limits* actual_limits); + wabt::Result CheckHasMemory(wabt::Opcode opcode); + wabt::Result CheckAlign(uint32_t alignment_log2, Address natural_alignment); + wabt::Result CheckAtomicAlign(uint32_t alignment_log2, + Address natural_alignment); + + wabt::Result AppendExport(Module* module, + ExternalKind kind, + Index item_index, + string_view name); + wabt::Result FindRegisteredModule(string_view module_name, + Module** out_module); + wabt::Result GetModuleExport(Module* module, + string_view field_name, + Export** out_export); + + HostImportDelegate::ErrorCallback MakePrintErrorCallback(); + + ErrorHandler* error_handler_ = nullptr; + Environment* env_ = nullptr; + DefinedModule* module_ = nullptr; + DefinedFunc* current_func_ = nullptr; + TypeChecker typechecker_; + std::vector<Label> label_stack_; + IstreamOffsetVectorVector func_fixups_; + IstreamOffsetVectorVector depth_fixups_; + MemoryStream istream_; + IstreamOffset 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 */ + IndexVector sig_index_mapping_; + IndexVector func_index_mapping_; + IndexVector global_index_mapping_; + + Index num_func_imports_ = 0; + Index 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. + TypedValue init_expr_value_; + IstreamOffset table_offset_ = 0; +}; + +BinaryReaderInterp::BinaryReaderInterp(Environment* env, + DefinedModule* module, + std::unique_ptr<OutputBuffer> istream, + ErrorHandler* error_handler) + : error_handler_(error_handler), + env_(env), + module_(module), + istream_(std::move(istream)), + istream_offset_(istream_.output_buffer().size()) { + typechecker_.set_error_callback( + [this](const char* msg) { PrintError("%s", msg); }); +} + +std::unique_ptr<OutputBuffer> BinaryReaderInterp::ReleaseOutputBuffer() { + return istream_.ReleaseOutputBuffer(); +} + +Label* BinaryReaderInterp::GetLabel(Index depth) { + assert(depth < label_stack_.size()); + return &label_stack_[label_stack_.size() - depth - 1]; +} + +Label* BinaryReaderInterp::TopLabel() { + return GetLabel(0); +} + +bool BinaryReaderInterp::HandleError(Offset offset, const char* message) { + return error_handler_->OnError(offset, message); +} + +void WABT_PRINTF_FORMAT(2, 3) BinaryReaderInterp::PrintError(const char* format, + ...) { + WABT_SNPRINTF_ALLOCA(buffer, length, format); + HandleError(kInvalidOffset, buffer); +} + +Index BinaryReaderInterp::TranslateSigIndexToEnv(Index sig_index) { + assert(sig_index < sig_index_mapping_.size()); + return sig_index_mapping_[sig_index]; +} + +FuncSignature* BinaryReaderInterp::GetSignatureByModuleIndex(Index sig_index) { + return env_->GetFuncSignature(TranslateSigIndexToEnv(sig_index)); +} + +Index BinaryReaderInterp::TranslateFuncIndexToEnv(Index func_index) { + assert(func_index < func_index_mapping_.size()); + return func_index_mapping_[func_index]; +} + +Index BinaryReaderInterp::TranslateModuleFuncIndexToDefined(Index func_index) { + assert(func_index >= num_func_imports_); + return func_index - num_func_imports_; +} + +Func* BinaryReaderInterp::GetFuncByModuleIndex(Index func_index) { + return env_->GetFunc(TranslateFuncIndexToEnv(func_index)); +} + +Index BinaryReaderInterp::TranslateGlobalIndexToEnv(Index global_index) { + return global_index_mapping_[global_index]; +} + +Global* BinaryReaderInterp::GetGlobalByModuleIndex(Index global_index) { + return env_->GetGlobal(TranslateGlobalIndexToEnv(global_index)); +} + +Type BinaryReaderInterp::GetGlobalTypeByModuleIndex(Index global_index) { + return GetGlobalByModuleIndex(global_index)->typed_value.type; +} + +Type BinaryReaderInterp::GetLocalTypeByIndex(Func* func, Index local_index) { + assert(!func->is_host); + return cast<DefinedFunc>(func)->param_and_local_types[local_index]; +} + +IstreamOffset BinaryReaderInterp::GetIstreamOffset() { + return istream_offset_; +} + +wabt::Result BinaryReaderInterp::EmitDataAt(IstreamOffset offset, + const void* data, + IstreamOffset size) { + istream_.WriteDataAt(offset, data, size); + return istream_.result(); +} + +wabt::Result BinaryReaderInterp::EmitData(const void* data, + IstreamOffset size) { + CHECK_RESULT(EmitDataAt(istream_offset_, data, size)); + istream_offset_ += size; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::EmitOpcode(Opcode opcode) { + if (opcode.HasPrefix()) { + CHECK_RESULT(EmitI8(opcode.GetPrefix())); + } + + // Assume opcode codes are all 1 byte for now (excluding the prefix). + uint32_t code = opcode.GetCode(); + assert(code < 256); + return EmitI8(code); +} + +wabt::Result BinaryReaderInterp::EmitI8(uint8_t value) { + return EmitData(&value, sizeof(value)); +} + +wabt::Result BinaryReaderInterp::EmitI32(uint32_t value) { + return EmitData(&value, sizeof(value)); +} + +wabt::Result BinaryReaderInterp::EmitI64(uint64_t value) { + return EmitData(&value, sizeof(value)); +} + +wabt::Result BinaryReaderInterp::EmitI32At(IstreamOffset offset, + uint32_t value) { + return EmitDataAt(offset, &value, sizeof(value)); +} + +wabt::Result BinaryReaderInterp::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(Opcode::Drop)); + } else { + CHECK_RESULT(EmitOpcode(Opcode::InterpDropKeep)); + CHECK_RESULT(EmitI32(drop)); + CHECK_RESULT(EmitI8(keep)); + } + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::AppendFixup( + IstreamOffsetVectorVector* fixups_vector, + Index index) { + if (index >= fixups_vector->size()) + fixups_vector->resize(index + 1); + (*fixups_vector)[index].push_back(GetIstreamOffset()); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::EmitBrOffset(Index depth, + IstreamOffset offset) { + if (offset == kInvalidIstreamOffset) { + /* 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 wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::GetBrDropKeepCount(Index depth, + Index* out_drop_count, + Index* out_keep_count) { + TypeChecker::Label* label; + CHECK_RESULT(typechecker_.GetLabel(depth, &label)); + *out_keep_count = + label->label_type != LabelType::Loop ? label->sig.size() : 0; + if (typechecker_.IsUnreachable()) { + *out_drop_count = 0; + } else { + *out_drop_count = + (typechecker_.type_stack_size() - label->type_stack_limit) - + *out_keep_count; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::GetReturnDropKeepCount(Index* out_drop_count, + Index* out_keep_count) { + CHECK_RESULT(GetBrDropKeepCount(label_stack_.size() - 1, out_drop_count, + out_keep_count)); + *out_drop_count += current_func_->param_and_local_types.size(); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::EmitBr(Index depth, + Index drop_count, + Index keep_count) { + CHECK_RESULT(EmitDropKeep(drop_count, keep_count)); + CHECK_RESULT(EmitOpcode(Opcode::Br)); + CHECK_RESULT(EmitBrOffset(depth, GetLabel(depth)->offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::EmitBrTableOffset(Index depth) { + Index 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 wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::FixupTopLabel() { + IstreamOffset offset = GetIstreamOffset(); + Index top = label_stack_.size() - 1; + if (top >= depth_fixups_.size()) { + /* nothing to fixup */ + return wabt::Result::Ok; + } + + IstreamOffsetVector& fixups = depth_fixups_[top]; + for (IstreamOffset fixup : fixups) + CHECK_RESULT(EmitI32At(fixup, offset)); + fixups.clear(); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::EmitFuncOffset(DefinedFunc* func, + Index func_index) { + if (func->offset == kInvalidIstreamOffset) { + Index defined_index = TranslateModuleFuncIndexToDefined(func_index); + CHECK_RESULT(AppendFixup(&func_fixups_, defined_index)); + } + CHECK_RESULT(EmitI32(func->offset)); + return wabt::Result::Ok; +} + +bool BinaryReaderInterp::OnError(const char* message) { + return HandleError(state->offset, message); +} + +wabt::Result BinaryReaderInterp::OnTypeCount(Index count) { + Index sig_count = env_->GetFuncSignatureCount(); + sig_index_mapping_.resize(count); + for (Index i = 0; i < count; ++i) + sig_index_mapping_[i] = sig_count + i; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) { + assert(TranslateSigIndexToEnv(index) == env_->GetFuncSignatureCount()); + env_->EmplaceBackFuncSignature(param_count, param_types, result_count, + result_types); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::CheckLocal(Index local_index) { + Index max_local_index = current_func_->param_and_local_types.size(); + if (local_index >= max_local_index) { + PrintError("invalid local_index: %" PRIindex " (max %" PRIindex ")", + local_index, max_local_index); + return wabt::Result::Error; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::CheckGlobal(Index global_index) { + Index max_global_index = global_index_mapping_.size(); + if (global_index >= max_global_index) { + PrintError("invalid global_index: %" PRIindex " (max %" PRIindex ")", + global_index, max_global_index); + return wabt::Result::Error; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::CheckImportKind(Import* import, + ExternalKind actual_kind) { + if (import->kind != actual_kind) { + PrintError("expected import \"" PRIstringview "." PRIstringview + "\" to have kind %s, not %s", + WABT_PRINTF_STRING_VIEW_ARG(import->module_name), + WABT_PRINTF_STRING_VIEW_ARG(import->field_name), + GetKindName(import->kind), GetKindName(actual_kind)); + return wabt::Result::Error; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::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 wabt::Result::Error; + } + + if (declared_limits->has_max) { + if (!actual_limits->has_max) { + PrintError("max size (unspecified) larger than declared (%" PRIu64 ")", + declared_limits->max); + return wabt::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 wabt::Result::Error; + } + } + + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::AppendExport(Module* module, + ExternalKind kind, + Index item_index, + string_view name) { + if (module->export_bindings.FindIndex(name) != kInvalidIndex) { + PrintError("duplicate export \"" PRIstringview "\"", + WABT_PRINTF_STRING_VIEW_ARG(name)); + return wabt::Result::Error; + } + + module->exports.emplace_back(name, kind, item_index); + Export* export_ = &module->exports.back(); + + module->export_bindings.emplace(export_->name, + Binding(module->exports.size() - 1)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::FindRegisteredModule(string_view module_name, + Module** out_module) { + Module* module = env_->FindRegisteredModule(module_name); + if (!module) { + PrintError("unknown import module \"" PRIstringview "\"", + WABT_PRINTF_STRING_VIEW_ARG(module_name)); + return wabt::Result::Error; + } + + *out_module = module; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::GetModuleExport(Module* module, + string_view field_name, + Export** out_export) { + Export* export_ = module->GetExport(field_name); + if (!export_) { + PrintError("unknown module field \"" PRIstringview "\"", + WABT_PRINTF_STRING_VIEW_ARG(field_name)); + return wabt::Result::Error; + } + + *out_export = export_; + return wabt::Result::Ok; +} + +HostImportDelegate::ErrorCallback BinaryReaderInterp::MakePrintErrorCallback() { + return [this](const char* msg) { PrintError("%s", msg); }; +} + +wabt::Result BinaryReaderInterp::OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) { + module_->func_imports.emplace_back(module_name, field_name); + FuncImport* import = &module_->func_imports.back(); + import->sig_index = TranslateSigIndexToEnv(sig_index); + + Module* import_module; + CHECK_RESULT(FindRegisteredModule(import->module_name, &import_module)); + + Index func_env_index; + if (auto* host_import_module = dyn_cast<HostModule>(import_module)) { + HostFunc* func = new HostFunc(import->module_name, import->field_name, + import->sig_index); + env_->EmplaceBackFunc(func); + + FuncSignature* sig = env_->GetFuncSignature(func->sig_index); + CHECK_RESULT(host_import_module->import_delegate->ImportFunc( + import, func, sig, MakePrintErrorCallback())); + assert(func->callback); + + func_env_index = env_->GetFuncCount() - 1; + AppendExport(host_import_module, ExternalKind::Func, func_env_index, + import->field_name); + } else { + Export* export_; + CHECK_RESULT(GetModuleExport(import_module, import->field_name, &export_)); + CHECK_RESULT(CheckImportKind(import, export_->kind)); + + Func* func = env_->GetFunc(export_->index); + if (!env_->FuncSignaturesAreEqual(import->sig_index, func->sig_index)) { + PrintError("import signature mismatch"); + return wabt::Result::Error; + } + + func_env_index = export_->index; + } + func_index_mapping_.push_back(func_env_index); + num_func_imports_++; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) { + if (module_->table_index != kInvalidIndex) { + PrintError("only one table allowed"); + return wabt::Result::Error; + } + + module_->table_imports.emplace_back(module_name, field_name); + TableImport* import = &module_->table_imports.back(); + + Module* import_module; + CHECK_RESULT(FindRegisteredModule(import->module_name, &import_module)); + + if (auto* host_import_module = dyn_cast<HostModule>(import_module)) { + Table* table = env_->EmplaceBackTable(*elem_limits); + + CHECK_RESULT(host_import_module->import_delegate->ImportTable( + import, table, MakePrintErrorCallback())); + + CHECK_RESULT(CheckImportLimits(elem_limits, &table->limits)); + + module_->table_index = env_->GetTableCount() - 1; + AppendExport(host_import_module, ExternalKind::Table, module_->table_index, + import->field_name); + } else { + Export* export_; + CHECK_RESULT(GetModuleExport(import_module, import->field_name, &export_)); + CHECK_RESULT(CheckImportKind(import, export_->kind)); + + Table* table = env_->GetTable(export_->index); + CHECK_RESULT(CheckImportLimits(elem_limits, &table->limits)); + + import->limits = *elem_limits; + module_->table_index = export_->index; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) { + if (module_->memory_index != kInvalidIndex) { + PrintError("only one memory allowed"); + return wabt::Result::Error; + } + + module_->memory_imports.emplace_back(module_name, field_name); + MemoryImport* import = &module_->memory_imports.back(); + + Module* import_module; + CHECK_RESULT(FindRegisteredModule(import->module_name, &import_module)); + + if (auto* host_import_module = dyn_cast<HostModule>(import_module)) { + Memory* memory = env_->EmplaceBackMemory(); + + CHECK_RESULT(host_import_module->import_delegate->ImportMemory( + import, memory, MakePrintErrorCallback())); + + CHECK_RESULT(CheckImportLimits(page_limits, &memory->page_limits)); + + module_->memory_index = env_->GetMemoryCount() - 1; + AppendExport(host_import_module, ExternalKind::Memory, + module_->memory_index, import->field_name); + } else { + Export* export_; + CHECK_RESULT(GetModuleExport(import_module, import->field_name, &export_)); + CHECK_RESULT(CheckImportKind(import, export_->kind)); + + Memory* memory = env_->GetMemory(export_->index); + CHECK_RESULT(CheckImportLimits(page_limits, &memory->page_limits)); + + import->limits = *page_limits; + module_->memory_index = export_->index; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) { + module_->global_imports.emplace_back(module_name, field_name); + GlobalImport* import = &module_->global_imports.back(); + + Module* import_module; + CHECK_RESULT(FindRegisteredModule(import->module_name, &import_module)); + + Index global_env_index = env_->GetGlobalCount() - 1; + if (auto* host_import_module = dyn_cast<HostModule>(import_module)) { + Global* global = env_->EmplaceBackGlobal(TypedValue(type), mutable_); + + CHECK_RESULT(host_import_module->import_delegate->ImportGlobal( + import, global, MakePrintErrorCallback())); + + global_env_index = env_->GetGlobalCount() - 1; + AppendExport(host_import_module, ExternalKind::Global, global_env_index, + import->field_name); + } else { + Export* export_; + CHECK_RESULT(GetModuleExport(import_module, import->field_name, &export_)); + CHECK_RESULT(CheckImportKind(import, export_->kind)); + + // TODO: check type and mutability + import->type = type; + import->mutable_ = mutable_; + global_env_index = export_->index; + } + global_index_mapping_.push_back(global_env_index); + num_global_imports_++; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnFunctionCount(Index count) { + for (Index i = 0; i < count; ++i) + func_index_mapping_.push_back(env_->GetFuncCount() + i); + func_fixups_.resize(count); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnFunction(Index index, Index sig_index) { + env_->EmplaceBackFunc(new DefinedFunc(TranslateSigIndexToEnv(sig_index))); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnTable(Index index, + Type elem_type, + const Limits* elem_limits) { + if (module_->table_index != kInvalidIndex) { + PrintError("only one table allowed"); + return wabt::Result::Error; + } + env_->EmplaceBackTable(*elem_limits); + module_->table_index = env_->GetTableCount() - 1; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnMemory(Index index, + const Limits* page_limits) { + if (module_->memory_index != kInvalidIndex) { + PrintError("only one memory allowed"); + return wabt::Result::Error; + } + env_->EmplaceBackMemory(*page_limits); + module_->memory_index = env_->GetMemoryCount() - 1; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnGlobalCount(Index count) { + for (Index i = 0; i < count; ++i) + global_index_mapping_.push_back(env_->GetGlobalCount() + i); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::BeginGlobal(Index index, + Type type, + bool mutable_) { + assert(TranslateGlobalIndexToEnv(index) == env_->GetGlobalCount()); + env_->EmplaceBackGlobal(TypedValue(type), mutable_); + init_expr_value_.type = Type::Void; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::EndGlobalInitExpr(Index index) { + Global* global = GetGlobalByModuleIndex(index); + if (init_expr_value_.type != global->typed_value.type) { + PrintError("type mismatch in global, expected %s but got %s.", + GetTypeName(global->typed_value.type), + GetTypeName(init_expr_value_.type)); + return wabt::Result::Error; + } + global->typed_value = init_expr_value_; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnInitExprF32ConstExpr(Index index, + uint32_t value_bits) { + init_expr_value_.type = Type::F32; + init_expr_value_.value.f32_bits = value_bits; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnInitExprF64ConstExpr(Index index, + uint64_t value_bits) { + init_expr_value_.type = Type::F64; + init_expr_value_.value.f64_bits = value_bits; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnInitExprGetGlobalExpr(Index index, + Index global_index) { + if (global_index >= num_global_imports_) { + PrintError("initializer expression can only reference an imported global"); + return wabt::Result::Error; + } + Global* ref_global = GetGlobalByModuleIndex(global_index); + if (ref_global->mutable_) { + PrintError("initializer expression cannot reference a mutable global"); + return wabt::Result::Error; + } + init_expr_value_ = ref_global->typed_value; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnInitExprI32ConstExpr(Index index, + uint32_t value) { + init_expr_value_.type = Type::I32; + init_expr_value_.value.i32 = value; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnInitExprI64ConstExpr(Index index, + uint64_t value) { + init_expr_value_.type = Type::I64; + init_expr_value_.value.i64 = value; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view 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); + Global* global = env_->GetGlobal(item_index); + if (global->mutable_) { + PrintError("mutable globals cannot be exported"); + return wabt::Result::Error; + } + break; + } + + case ExternalKind::Except: + // TODO(karlschimpf) Define + WABT_FATAL("BinaryReaderInterp::OnExport(except) not implemented"); + break; + } + return AppendExport(module_, kind, item_index, name); +} + +wabt::Result BinaryReaderInterp::OnStartFunction(Index func_index) { + Index start_func_index = TranslateFuncIndexToEnv(func_index); + Func* start_func = env_->GetFunc(start_func_index); + FuncSignature* sig = env_->GetFuncSignature(start_func->sig_index); + if (sig->param_types.size() != 0) { + PrintError("start function must be nullary"); + return wabt::Result::Error; + } + if (sig->result_types.size() != 0) { + PrintError("start function must not return anything"); + return wabt::Result::Error; + } + module_->start_func_index = start_func_index; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) { + assert(init_expr_value_.type == Type::I32); + table_offset_ = init_expr_value_.value.i32; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnElemSegmentFunctionIndex(Index index, + Index func_index) { + assert(module_->table_index != kInvalidIndex); + Table* table = env_->GetTable(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 wabt::Result::Error; + } + + Index max_func_index = func_index_mapping_.size(); + if (func_index >= max_func_index) { + PrintError("invalid func_index: %" PRIindex " (max %" PRIindex ")", + func_index, max_func_index); + return wabt::Result::Error; + } + + elem_segment_infos_.emplace_back(&table->func_indexes[table_offset_++], + TranslateFuncIndexToEnv(func_index)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnDataSegmentData(Index index, + const void* src_data, + Address size) { + assert(module_->memory_index != kInvalidIndex); + Memory* memory = env_->GetMemory(module_->memory_index); + assert(init_expr_value_.type == Type::I32); + Address 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: [%" PRIaddress ", %" PRIu64 + ") >= max value %" PRIzd, + address, end_address, memory->data.size()); + return wabt::Result::Error; + } + + if (size > 0) + data_segment_infos_.emplace_back(&memory->data[address], src_data, size); + + return wabt::Result::Ok; +} + +void BinaryReaderInterp::PushLabel(IstreamOffset offset, + IstreamOffset fixup_offset) { + label_stack_.emplace_back(offset, fixup_offset); +} + +void BinaryReaderInterp::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()); + } +} + +wabt::Result BinaryReaderInterp::BeginFunctionBody(Index index) { + auto* func = cast<DefinedFunc>(GetFuncByModuleIndex(index)); + FuncSignature* sig = env_->GetFuncSignature(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 */ + Index defined_index = TranslateModuleFuncIndexToDefined(index); + IstreamOffsetVector& fixups = func_fixups_[defined_index]; + for (IstreamOffset 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_.BeginFunction(&sig->result_types)); + + /* push implicit func label (equivalent to return) */ + PushLabel(kInvalidIstreamOffset, kInvalidIstreamOffset); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::EndFunctionBody(Index index) { + FixupTopLabel(); + Index drop_count, keep_count; + CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count)); + CHECK_RESULT(typechecker_.EndFunction()); + CHECK_RESULT(EmitDropKeep(drop_count, keep_count)); + CHECK_RESULT(EmitOpcode(Opcode::Return)); + PopLabel(); + current_func_ = nullptr; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnLocalDeclCount(Index count) { + current_func_->local_decl_count = count; + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnLocalDecl(Index decl_index, + Index count, + Type type) { + current_func_->local_count += count; + + for (Index 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(Opcode::InterpAlloca)); + CHECK_RESULT(EmitI32(current_func_->local_count)); + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::CheckHasMemory(wabt::Opcode opcode) { + if (module_->memory_index == kInvalidIndex) { + PrintError("%s requires an imported or defined memory.", opcode.GetName()); + return wabt::Result::Error; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::CheckAlign(uint32_t alignment_log2, + Address natural_alignment) { + if (alignment_log2 >= 32 || (1U << alignment_log2) > natural_alignment) { + PrintError("alignment must not be larger than natural alignment (%u)", + natural_alignment); + return wabt::Result::Error; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::CheckAtomicAlign(uint32_t alignment_log2, + Address natural_alignment) { + if (alignment_log2 >= 32 || (1U << alignment_log2) != natural_alignment) { + PrintError("alignment must be equal to natural alignment (%u)", + natural_alignment); + return wabt::Result::Error; + } + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnUnaryExpr(wabt::Opcode opcode) { + CHECK_RESULT(typechecker_.OnUnary(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnAtomicLoadExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) { + CHECK_RESULT(CheckHasMemory(opcode)); + CHECK_RESULT(CheckAtomicAlign(alignment_log2, opcode.GetMemorySize())); + CHECK_RESULT(typechecker_.OnAtomicLoad(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + CHECK_RESULT(EmitI32(module_->memory_index)); + CHECK_RESULT(EmitI32(offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnAtomicStoreExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) { + CHECK_RESULT(CheckHasMemory(opcode)); + CHECK_RESULT(CheckAtomicAlign(alignment_log2, opcode.GetMemorySize())); + CHECK_RESULT(typechecker_.OnAtomicStore(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + CHECK_RESULT(EmitI32(module_->memory_index)); + CHECK_RESULT(EmitI32(offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnAtomicRmwExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) { + CHECK_RESULT(CheckHasMemory(opcode)); + CHECK_RESULT(CheckAtomicAlign(alignment_log2, opcode.GetMemorySize())); + CHECK_RESULT(typechecker_.OnAtomicRmw(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + CHECK_RESULT(EmitI32(module_->memory_index)); + CHECK_RESULT(EmitI32(offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnAtomicRmwCmpxchgExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) { + CHECK_RESULT(CheckHasMemory(opcode)); + CHECK_RESULT(CheckAtomicAlign(alignment_log2, opcode.GetMemorySize())); + CHECK_RESULT(typechecker_.OnAtomicRmwCmpxchg(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + CHECK_RESULT(EmitI32(module_->memory_index)); + CHECK_RESULT(EmitI32(offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnBinaryExpr(wabt::Opcode opcode) { + CHECK_RESULT(typechecker_.OnBinary(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnBlockExpr(Index num_types, Type* sig_types) { + TypeVector sig(sig_types, sig_types + num_types); + CHECK_RESULT(typechecker_.OnBlock(&sig)); + PushLabel(kInvalidIstreamOffset, kInvalidIstreamOffset); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnLoopExpr(Index num_types, Type* sig_types) { + TypeVector sig(sig_types, sig_types + num_types); + CHECK_RESULT(typechecker_.OnLoop(&sig)); + PushLabel(GetIstreamOffset(), kInvalidIstreamOffset); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnIfExpr(Index num_types, Type* sig_types) { + TypeVector sig(sig_types, sig_types + num_types); + CHECK_RESULT(typechecker_.OnIf(&sig)); + CHECK_RESULT(EmitOpcode(Opcode::InterpBrUnless)); + IstreamOffset fixup_offset = GetIstreamOffset(); + CHECK_RESULT(EmitI32(kInvalidIstreamOffset)); + PushLabel(kInvalidIstreamOffset, fixup_offset); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnElseExpr() { + CHECK_RESULT(typechecker_.OnElse()); + Label* label = TopLabel(); + IstreamOffset fixup_cond_offset = label->fixup_offset; + CHECK_RESULT(EmitOpcode(Opcode::Br)); + label->fixup_offset = GetIstreamOffset(); + CHECK_RESULT(EmitI32(kInvalidIstreamOffset)); + CHECK_RESULT(EmitI32At(fixup_cond_offset, GetIstreamOffset())); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnEndExpr() { + TypeChecker::Label* label; + CHECK_RESULT(typechecker_.GetLabel(0, &label)); + LabelType label_type = label->label_type; + CHECK_RESULT(typechecker_.OnEnd()); + if (label_type == LabelType::If || label_type == LabelType::Else) { + CHECK_RESULT(EmitI32At(TopLabel()->fixup_offset, GetIstreamOffset())); + } + FixupTopLabel(); + PopLabel(); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnBrExpr(Index depth) { + Index drop_count, keep_count; + CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); + CHECK_RESULT(typechecker_.OnBr(depth)); + CHECK_RESULT(EmitBr(depth, drop_count, keep_count)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnBrIfExpr(Index depth) { + Index drop_count, keep_count; + CHECK_RESULT(typechecker_.OnBrIf(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(Opcode::InterpBrUnless)); + IstreamOffset fixup_br_offset = GetIstreamOffset(); + CHECK_RESULT(EmitI32(kInvalidIstreamOffset)); + CHECK_RESULT(EmitBr(depth, drop_count, keep_count)); + CHECK_RESULT(EmitI32At(fixup_br_offset, GetIstreamOffset())); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) { + CHECK_RESULT(typechecker_.BeginBrTable()); + CHECK_RESULT(EmitOpcode(Opcode::BrTable)); + CHECK_RESULT(EmitI32(num_targets)); + IstreamOffset fixup_table_offset = GetIstreamOffset(); + CHECK_RESULT(EmitI32(kInvalidIstreamOffset)); + /* not necessary for the interp, but it makes it easier to disassemble. + * This opcode specifies how many bytes of data follow. */ + CHECK_RESULT(EmitOpcode(Opcode::InterpData)); + CHECK_RESULT(EmitI32((num_targets + 1) * WABT_TABLE_ENTRY_SIZE)); + CHECK_RESULT(EmitI32At(fixup_table_offset, GetIstreamOffset())); + + for (Index i = 0; i <= num_targets; ++i) { + Index depth = i != num_targets ? target_depths[i] : default_target_depth; + CHECK_RESULT(typechecker_.OnBrTableTarget(depth)); + CHECK_RESULT(EmitBrTableOffset(depth)); + } + + CHECK_RESULT(typechecker_.EndBrTable()); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnCallExpr(Index func_index) { + Func* func = GetFuncByModuleIndex(func_index); + FuncSignature* sig = env_->GetFuncSignature(func->sig_index); + CHECK_RESULT(typechecker_.OnCall(&sig->param_types, &sig->result_types)); + + if (func->is_host) { + CHECK_RESULT(EmitOpcode(Opcode::InterpCallHost)); + CHECK_RESULT(EmitI32(TranslateFuncIndexToEnv(func_index))); + } else { + CHECK_RESULT(EmitOpcode(Opcode::Call)); + CHECK_RESULT(EmitFuncOffset(cast<DefinedFunc>(func), func_index)); + } + + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnCallIndirectExpr(Index sig_index) { + if (module_->table_index == kInvalidIndex) { + PrintError("found call_indirect operator, but no table"); + return wabt::Result::Error; + } + FuncSignature* sig = GetSignatureByModuleIndex(sig_index); + CHECK_RESULT( + typechecker_.OnCallIndirect(&sig->param_types, &sig->result_types)); + + CHECK_RESULT(EmitOpcode(Opcode::CallIndirect)); + CHECK_RESULT(EmitI32(module_->table_index)); + CHECK_RESULT(EmitI32(TranslateSigIndexToEnv(sig_index))); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnCompareExpr(wabt::Opcode opcode) { + return OnBinaryExpr(opcode); +} + +wabt::Result BinaryReaderInterp::OnConvertExpr(wabt::Opcode opcode) { + return OnUnaryExpr(opcode); +} + +wabt::Result BinaryReaderInterp::OnDropExpr() { + CHECK_RESULT(typechecker_.OnDrop()); + CHECK_RESULT(EmitOpcode(Opcode::Drop)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnI32ConstExpr(uint32_t value) { + CHECK_RESULT(typechecker_.OnConst(Type::I32)); + CHECK_RESULT(EmitOpcode(Opcode::I32Const)); + CHECK_RESULT(EmitI32(value)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnI64ConstExpr(uint64_t value) { + CHECK_RESULT(typechecker_.OnConst(Type::I64)); + CHECK_RESULT(EmitOpcode(Opcode::I64Const)); + CHECK_RESULT(EmitI64(value)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnF32ConstExpr(uint32_t value_bits) { + CHECK_RESULT(typechecker_.OnConst(Type::F32)); + CHECK_RESULT(EmitOpcode(Opcode::F32Const)); + CHECK_RESULT(EmitI32(value_bits)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnF64ConstExpr(uint64_t value_bits) { + CHECK_RESULT(typechecker_.OnConst(Type::F64)); + CHECK_RESULT(EmitOpcode(Opcode::F64Const)); + CHECK_RESULT(EmitI64(value_bits)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnGetGlobalExpr(Index global_index) { + CHECK_RESULT(CheckGlobal(global_index)); + Type type = GetGlobalTypeByModuleIndex(global_index); + CHECK_RESULT(typechecker_.OnGetGlobal(type)); + CHECK_RESULT(EmitOpcode(Opcode::GetGlobal)); + CHECK_RESULT(EmitI32(TranslateGlobalIndexToEnv(global_index))); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnSetGlobalExpr(Index global_index) { + CHECK_RESULT(CheckGlobal(global_index)); + Global* global = GetGlobalByModuleIndex(global_index); + if (!global->mutable_) { + PrintError("can't set_global on immutable global at index %" PRIindex ".", + global_index); + return wabt::Result::Error; + } + CHECK_RESULT(typechecker_.OnSetGlobal(global->typed_value.type)); + CHECK_RESULT(EmitOpcode(Opcode::SetGlobal)); + CHECK_RESULT(EmitI32(TranslateGlobalIndexToEnv(global_index))); + return wabt::Result::Ok; +} + +Index BinaryReaderInterp::TranslateLocalIndex(Index local_index) { + return typechecker_.type_stack_size() + + current_func_->param_and_local_types.size() - local_index; +} + +wabt::Result BinaryReaderInterp::OnGetLocalExpr(Index local_index) { + CHECK_RESULT(CheckLocal(local_index)); + Type type = GetLocalTypeByIndex(current_func_, local_index); + // Get the translated index before calling typechecker_.OnGetLocal because it + // will update the type stack size. We need the index to be relative to the + // old stack size. + Index translated_local_index = TranslateLocalIndex(local_index); + CHECK_RESULT(typechecker_.OnGetLocal(type)); + CHECK_RESULT(EmitOpcode(Opcode::GetLocal)); + CHECK_RESULT(EmitI32(translated_local_index)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnSetLocalExpr(Index local_index) { + CHECK_RESULT(CheckLocal(local_index)); + Type type = GetLocalTypeByIndex(current_func_, local_index); + CHECK_RESULT(typechecker_.OnSetLocal(type)); + CHECK_RESULT(EmitOpcode(Opcode::SetLocal)); + CHECK_RESULT(EmitI32(TranslateLocalIndex(local_index))); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnTeeLocalExpr(Index local_index) { + CHECK_RESULT(CheckLocal(local_index)); + Type type = GetLocalTypeByIndex(current_func_, local_index); + CHECK_RESULT(typechecker_.OnTeeLocal(type)); + CHECK_RESULT(EmitOpcode(Opcode::TeeLocal)); + CHECK_RESULT(EmitI32(TranslateLocalIndex(local_index))); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnGrowMemoryExpr() { + CHECK_RESULT(CheckHasMemory(wabt::Opcode::GrowMemory)); + CHECK_RESULT(typechecker_.OnGrowMemory()); + CHECK_RESULT(EmitOpcode(Opcode::GrowMemory)); + CHECK_RESULT(EmitI32(module_->memory_index)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnLoadExpr(wabt::Opcode opcode, + uint32_t alignment_log2, + Address offset) { + CHECK_RESULT(CheckHasMemory(opcode)); + CHECK_RESULT(CheckAlign(alignment_log2, opcode.GetMemorySize())); + CHECK_RESULT(typechecker_.OnLoad(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + CHECK_RESULT(EmitI32(module_->memory_index)); + CHECK_RESULT(EmitI32(offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnStoreExpr(wabt::Opcode opcode, + uint32_t alignment_log2, + Address offset) { + CHECK_RESULT(CheckHasMemory(opcode)); + CHECK_RESULT(CheckAlign(alignment_log2, opcode.GetMemorySize())); + CHECK_RESULT(typechecker_.OnStore(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + CHECK_RESULT(EmitI32(module_->memory_index)); + CHECK_RESULT(EmitI32(offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnCurrentMemoryExpr() { + CHECK_RESULT(CheckHasMemory(wabt::Opcode::CurrentMemory)); + CHECK_RESULT(typechecker_.OnCurrentMemory()); + CHECK_RESULT(EmitOpcode(Opcode::CurrentMemory)); + CHECK_RESULT(EmitI32(module_->memory_index)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnNopExpr() { + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnReturnExpr() { + Index drop_count, keep_count; + CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count)); + CHECK_RESULT(typechecker_.OnReturn()); + CHECK_RESULT(EmitDropKeep(drop_count, keep_count)); + CHECK_RESULT(EmitOpcode(Opcode::Return)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnSelectExpr() { + CHECK_RESULT(typechecker_.OnSelect()); + CHECK_RESULT(EmitOpcode(Opcode::Select)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnUnreachableExpr() { + CHECK_RESULT(typechecker_.OnUnreachable()); + CHECK_RESULT(EmitOpcode(Opcode::Unreachable)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnWaitExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) { + CHECK_RESULT(CheckHasMemory(opcode)); + CHECK_RESULT(CheckAtomicAlign(alignment_log2, opcode.GetMemorySize())); + CHECK_RESULT(typechecker_.OnWait(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + CHECK_RESULT(EmitI32(module_->memory_index)); + CHECK_RESULT(EmitI32(offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnWakeExpr(Opcode opcode, + uint32_t alignment_log2, + Address offset) { + CHECK_RESULT(CheckHasMemory(opcode)); + CHECK_RESULT(CheckAtomicAlign(alignment_log2, opcode.GetMemorySize())); + CHECK_RESULT(typechecker_.OnWake(opcode)); + CHECK_RESULT(EmitOpcode(opcode)); + CHECK_RESULT(EmitI32(module_->memory_index)); + CHECK_RESULT(EmitI32(offset)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::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 wabt::Result::Ok; +} + +} // end anonymous namespace + +wabt::Result ReadBinaryInterp(Environment* env, + const void* data, + size_t size, + const ReadBinaryOptions* options, + ErrorHandler* error_handler, + DefinedModule** out_module) { + // Need to mark before taking ownership of env->istream. + Environment::MarkPoint mark = env->Mark(); + + std::unique_ptr<OutputBuffer> istream = env->ReleaseIstream(); + IstreamOffset istream_offset = istream->size(); + DefinedModule* module = new DefinedModule(); + + BinaryReaderInterp reader(env, module, std::move(istream), error_handler); + env->EmplaceBackModule(module); + + wabt::Result result = ReadBinary(data, size, &reader, options); + env->SetIstream(reader.ReleaseOutputBuffer()); + + if (Succeeded(result)) { + module->istream_start = istream_offset; + module->istream_end = env->istream().size(); + *out_module = module; + } else { + env->ResetToMarkPoint(mark); + *out_module = nullptr; + } + return result; +} + +} // namespace wabt |