summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interp.cc5
-rw-r--r--src/resolve-names.cc13
-rw-r--r--src/type-checker.cc8
-rw-r--r--src/validator.cc30
-rw-r--r--src/wast-parser.cc39
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) {