diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/interp.cc | 5 | ||||
-rw-r--r-- | src/resolve-names.cc | 13 | ||||
-rw-r--r-- | src/type-checker.cc | 8 | ||||
-rw-r--r-- | src/validator.cc | 30 | ||||
-rw-r--r-- | src/wast-parser.cc | 39 |
5 files changed, 74 insertions, 21 deletions
diff --git a/src/interp.cc b/src/interp.cc index d30b2bbe..60641485 100644 --- a/src/interp.cc +++ b/src/interp.cc @@ -860,8 +860,9 @@ ValueTypeRep<T> Thread::PopRep() { } void Thread::DropKeep(uint32_t drop_count, uint32_t keep_count) { - for (uint32_t i = 0; i < keep_count; ++i) { - Pick(drop_count + i + 1) = Pick(i + 1); + // Copy backward to avoid clobbering when the regions overlap. + for (uint32_t i = keep_count; i > 0; --i) { + Pick(drop_count + i) = Pick(i); } value_stack_top_ -= drop_count; } diff --git a/src/resolve-names.cc b/src/resolve-names.cc index c424001f..d1cf0345 100644 --- a/src/resolve-names.cc +++ b/src/resolve-names.cc @@ -72,6 +72,7 @@ class NameResolver : public ExprVisitor::DelegateNop { void ResolveMemoryVar(Var* var); void ResolveExceptionVar(Var* var); void ResolveLocalVar(Var* var); + void ResolveBlockDeclarationVar(BlockDeclaration* decl); void VisitFunc(Func* func); void VisitExport(Export* export_); void VisitGlobal(Global* global); @@ -121,7 +122,6 @@ void NameResolver::CheckDuplicateBindings(const BindingHash* bindings, const Location& b_loc = b.second.loc; const Location& loc = a_loc.line > b_loc.line ? a_loc : b_loc; PrintError(&loc, "redefinition of %s \"%s\"", desc, a.first.c_str()); - }); } @@ -195,8 +195,15 @@ void NameResolver::ResolveLocalVar(Var* var) { } } +void NameResolver::ResolveBlockDeclarationVar(BlockDeclaration* decl) { + if (decl->has_func_type) { + ResolveFuncTypeVar(&decl->type_var); + } +} + Result NameResolver::BeginBlockExpr(BlockExpr* expr) { PushLabel(expr->block.label); + ResolveBlockDeclarationVar(&expr->block.decl); return Result::Ok; } @@ -207,6 +214,7 @@ Result NameResolver::EndBlockExpr(BlockExpr* expr) { Result NameResolver::BeginLoopExpr(LoopExpr* expr) { PushLabel(expr->block.label); + ResolveBlockDeclarationVar(&expr->block.decl); return Result::Ok; } @@ -256,6 +264,7 @@ Result NameResolver::OnGetLocalExpr(GetLocalExpr* expr) { Result NameResolver::BeginIfExpr(IfExpr* expr) { PushLabel(expr->true_.label); + ResolveBlockDeclarationVar(&expr->true_.decl); return Result::Ok; } @@ -266,6 +275,7 @@ Result NameResolver::EndIfExpr(IfExpr* expr) { Result NameResolver::BeginIfExceptExpr(IfExceptExpr* expr) { PushLabel(expr->true_.label); + ResolveBlockDeclarationVar(&expr->true_.decl); ResolveExceptionVar(&expr->except_var); return Result::Ok; } @@ -292,6 +302,7 @@ Result NameResolver::OnTeeLocalExpr(TeeLocalExpr* expr) { Result NameResolver::BeginTryExpr(TryExpr* expr) { PushLabel(expr->block.label); + ResolveBlockDeclarationVar(&expr->block.decl); return Result::Ok; } diff --git a/src/type-checker.cc b/src/type-checker.cc index a1e0c28f..2623c3e8 100644 --- a/src/type-checker.cc +++ b/src/type-checker.cc @@ -473,10 +473,10 @@ Result TypeChecker::OnEnd() { assert(static_cast<int>(label->label_type) < kLabelTypeCount); if (label->label_type == LabelType::If || label->label_type == LabelType::IfExcept) { - if (label->result_types.size() != 0) { - PrintError("if without else cannot have results."); - result = Result::Error; - } + // An if without an else will just pass the params through, so the result + // types must be the same as the param types. It has the same behavior as + // an empty else block. + CHECK_RESULT(OnElse()); } const char* desc = s_label_type_name[static_cast<int>(label->label_type)]; result |= OnEnd(label, desc, desc); diff --git a/src/validator.cc b/src/validator.cc index a418e309..27bf2422 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -1398,11 +1398,41 @@ class Validator::CheckFuncSignatureExprVisitorDelegate explicit CheckFuncSignatureExprVisitorDelegate(Validator* validator) : validator_(validator) {} + Result BeginBlockExpr(BlockExpr* expr) override { + validator_->CheckBlockDeclaration(&expr->loc, Opcode::Block, + &expr->block.decl); + return Result::Ok; + } + Result OnCallIndirectExpr(CallIndirectExpr* expr) override { validator_->CheckFuncSignature(&expr->loc, expr->decl); return Result::Ok; } + Result BeginIfExpr(IfExpr* expr) override { + validator_->CheckBlockDeclaration(&expr->loc, Opcode::If, + &expr->true_.decl); + return Result::Ok; + } + + Result BeginIfExceptExpr(IfExceptExpr* expr) override { + validator_->CheckBlockDeclaration(&expr->loc, Opcode::IfExcept, + &expr->true_.decl); + return Result::Ok; + } + + Result BeginLoopExpr(LoopExpr* expr) override { + validator_->CheckBlockDeclaration(&expr->loc, Opcode::Loop, + &expr->block.decl); + return Result::Ok; + } + + Result BeginTryExpr(TryExpr* expr) override { + validator_->CheckBlockDeclaration(&expr->loc, Opcode::Try, + &expr->block.decl); + return Result::Ok; + } + private: Validator* validator_; }; diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 3b707848..1fef262b 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -218,41 +218,50 @@ bool IsCommand(TokenTypePair pair) { } } -bool IsEmptySignature(const FuncSignature* sig) { - return sig->result_types.empty() && sig->param_types.empty(); +bool IsEmptySignature(const FuncSignature& sig) { + return sig.result_types.empty() && sig.param_types.empty(); } -void ResolveFuncType(const Location& loc, - Module* module, - FuncDeclaration* decl) { +void ResolveFuncTypeWithEmptySignature(const Module& module, + FuncDeclaration* decl) { // Resolve func type variables where the signature was not specified // explicitly, e.g.: (func (type 1) ...) - if (decl->has_func_type && IsEmptySignature(&decl->sig)) { - FuncType* func_type = module->GetFuncType(decl->type_var); + if (decl->has_func_type && IsEmptySignature(decl->sig)) { + const FuncType* func_type = module.GetFuncType(decl->type_var); if (func_type) { decl->sig = func_type->sig; } } +} + +void ResolveImplicitlyDefinedFunctionType(const Location& loc, + Module* module, + const FuncDeclaration& decl) { // Resolve implicitly defined function types, e.g.: (func (param i32) ...) - if (!decl->has_func_type) { - Index func_type_index = module->GetFuncTypeIndex(decl->sig); + if (!decl.has_func_type) { + Index func_type_index = module->GetFuncTypeIndex(decl.sig); if (func_type_index == kInvalidIndex) { auto func_type_field = MakeUnique<FuncTypeModuleField>(loc); - func_type_field->func_type.sig = decl->sig; + func_type_field->func_type.sig = decl.sig; module->AppendField(std::move(func_type_field)); } } } +bool IsInlinableFuncSignature(const FuncSignature& sig) { + return sig.GetNumParams() == 0 && sig.GetNumResults() <= 1; +} + class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop { public: explicit ResolveFuncTypesExprVisitorDelegate(Module* module) : module_(module) {} void ResolveBlockDeclaration(const Location& loc, BlockDeclaration* decl) { - if (decl->GetNumParams() != 0 || decl->GetNumResults() > 1) { - ResolveFuncType(loc, module_, decl); + ResolveFuncTypeWithEmptySignature(*module_, decl); + if (!IsInlinableFuncSignature(decl->sig)) { + ResolveImplicitlyDefinedFunctionType(loc, module_, *decl); } } @@ -282,7 +291,8 @@ class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop { } Result OnCallIndirectExpr(CallIndirectExpr* expr) override { - ResolveFuncType(expr->loc, module_, &expr->decl); + ResolveFuncTypeWithEmptySignature(*module_, &expr->decl); + ResolveImplicitlyDefinedFunctionType(expr->loc, module_, expr->decl); return Result::Ok; } @@ -311,7 +321,8 @@ void ResolveFuncTypes(Module* module) { } if (decl) { - ResolveFuncType(field.loc, module, decl); + ResolveFuncTypeWithEmptySignature(*module, decl); + ResolveImplicitlyDefinedFunctionType(field.loc, module, *decl); } if (func) { |