Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions src/tools/wasm-ctor-eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,8 +798,14 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
// If |possibleDefiningGlobal| is provided, it is the name of a global that we
// are in the init expression of, and which can be reused as defining global,
// if the other conditions are suitable.
//
// Returns nullptr if we cannot serialize.
Expression* getSerialization(Literal value,
Name possibleDefiningGlobal = Name()) {
if (value.isContinuation()) {
return nullptr;
}

Builder builder(*wasm);

// If this is externalized then we want to inspect the inner data, handle
Expand Down Expand Up @@ -861,12 +867,19 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
}

for (auto& value : values) {
args.push_back(getSerialization(value));
auto* serialized = getSerialization(value);
if (!serialized) {
return nullptr;
}
args.push_back(serialized);
}

Expression* desc = nullptr;
if (data->desc.getGCData()) {
desc = getSerialization(data->desc);
if (!desc) {
return nullptr;
}
}

Expression* init;
Expand Down Expand Up @@ -913,7 +926,11 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
assert(possibleDefiningGlobal.isNull());
std::vector<Expression*> children;
for (const auto& value : values) {
children.push_back(getSerialization(value));
auto* serialized = getSerialization(value);
if (!serialized) {
return nullptr;
}
children.push_back(serialized);
}
return Builder(*wasm).makeTupleMake(children);
}
Expand Down Expand Up @@ -1132,7 +1149,17 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance,
// state in case we fail to eval the new function.
localExprs.clear();
for (auto& param : params) {
localExprs.push_back(interface.getSerialization(param));
auto* serialized = interface.getSerialization(param);
if (!serialized) {
break;
}
localExprs.push_back(serialized);
}
if (localExprs.size() < params.size()) {
if (!quiet) {
std::cout << " ...stopping due to non-serializable param\n";
}
break;
}
interface.applyToModule();
goto start_eval;
Expand All @@ -1152,7 +1179,17 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance,
// serialization sets from scratch each time here, for all locals.
localExprs.clear();
for (Index i = 0; i < func->getNumLocals(); i++) {
localExprs.push_back(interface.getSerialization(scope.locals[i]));
auto* serialized = interface.getSerialization(scope.locals[i]);
if (!serialized) {
break;
}
localExprs.push_back(serialized);
}
if (localExprs.size() < func->getNumLocals()) {
if (!quiet) {
std::cout << " ...stopping due to non-serializable local\n";
}
break;
}
interface.applyToModule();
successes++;
Expand Down Expand Up @@ -1341,12 +1378,20 @@ void evalCtors(Module& wasm,
? *exp->getInternalName()
: Name());
auto copyName = Names::getValidFunctionName(wasm, func->name);
auto* copyFunc = ModuleUtils::copyFunction(func, wasm, copyName);
auto copyFunc =
ModuleUtils::copyFunctionWithoutAdd(func, wasm, copyName);
if (func->getResults() == Type::none) {
copyFunc->body = Builder(wasm).makeNop();
} else {
copyFunc->body = interface.getSerialization(*outcome);
if (!copyFunc->body) {
if (!quiet) {
std::cout << " ...stopping due to non-serializable body\n";
}
return;
}
}
wasm.addFunction(std::move(copyFunc));
*wasm.getExport(exp->name)->getInternalName() = copyName;
}
}
Expand Down
57 changes: 57 additions & 0 deletions test/lit/ctor-eval/cont-noserial.wast
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to test the non-serializable defining global, parameter, and local separately.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added specific tests.

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; Test that we do not error on trying to serialize continuations (which cannot
;; be serialized). When we do not --kept-exports, we can at least optimize away
;; that export, since we don't need to serialize anything when it doesn't stick
Comment thread
kripken marked this conversation as resolved.
Outdated
;; around.

;; RUN: foreach %s %t wasm-ctor-eval --ctors=test --kept-exports=test -all --ignore-external-input -S -o - | filecheck %s
;; RUN: foreach %s %t wasm-ctor-eval --ctors=test -all --ignore-external-input -S -o - | filecheck %s --check-prefix=NOKEEP

(module
;; CHECK: (type $func (func))
;; NOKEEP: (type $func (func))
(type $func (func))
;; CHECK: (type $cont (cont $func))
(type $cont (cont $func))

;; CHECK: (type $2 (func (result (ref $cont))))

;; CHECK: (elem declare func $func)

;; CHECK: (export "export" (func $export))

;; CHECK: (export "test" (func $test))
(export "test" (func $test))

;; CHECK: (func $func (type $func)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $func
)

;; CHECK: (func $test (type $2) (result (ref $cont))
;; CHECK-NEXT: (cont.new $cont
;; CHECK-NEXT: (ref.func $func)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (result (ref $cont))
(cont.new $cont
(ref.func $func)
)
)
Comment thread
tlively marked this conversation as resolved.

;; CHECK: (func $export (type $func)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; NOKEEP: (export "export" (func $export))

;; NOKEEP: (func $export (type $func)
;; NOKEEP-NEXT: (nop)
;; NOKEEP-NEXT: )
(func $export (export "export")
;; A dummy export, just to avoid the NOKEEP case ending up with a blank
;; module and no CHECKs.
)
)

Loading