From 3c4c2649e23f633d25faad590cd21aee3a8d27e4 Mon Sep 17 00:00:00 2001 From: Alexander Guryanov Date: Wed, 25 Oct 2023 09:55:47 +0300 Subject: [PATCH] Fix #6047, #5271: Support one-line-one-function file format for asyncify lists Co-authored-by: Alon Zakai --- src/passes/Asyncify.cpp | 11 ++++-- src/support/string.h | 39 +++++++++++++++++-- test/lit/passes/asyncify-foo,bar-nl.txt | 2 + ...y_pass-arg=asyncify-blacklist@foo,bar.wast | 1 + ...fy_pass-arg=asyncify-onlylist@foo,bar.wast | 1 + 5 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 test/lit/passes/asyncify-foo,bar-nl.txt diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp index 342cd013d78..b60f25d6946 100644 --- a/src/passes/Asyncify.cpp +++ b/src/passes/Asyncify.cpp @@ -1533,7 +1533,8 @@ struct Asyncify : public Pass { options.getArgumentOrDefault("asyncify-ignore-imports", ""); bool allImportsCanChangeState = stateChangingImports == "" && ignoreImports == ""; - String::Split listedImports(stateChangingImports, ","); + String::Split listedImports(stateChangingImports, + String::Split::NewLineOr(",")); // canIndirectChangeState is the default. asyncify-ignore-indirect sets it // to false. auto canIndirectChangeState = @@ -1545,11 +1546,12 @@ struct Asyncify : public Pass { removeListInput = options.getArgumentOrDefault("asyncify-blacklist", ""); } String::Split removeList( - String::trim(read_possible_response_file(removeListInput)), ","); + String::trim(read_possible_response_file(removeListInput)), + String::Split::NewLineOr(",")); String::Split addList( String::trim(read_possible_response_file( options.getArgumentOrDefault("asyncify-addlist", ""))), - ","); + String::Split::NewLineOr(",")); std::string onlyListInput = options.getArgumentOrDefault("asyncify-onlylist", ""); if (onlyListInput.empty()) { @@ -1557,7 +1559,8 @@ struct Asyncify : public Pass { onlyListInput = options.getArgumentOrDefault("asyncify-whitelist", ""); } String::Split onlyList( - String::trim(read_possible_response_file(onlyListInput)), ","); + String::trim(read_possible_response_file(onlyListInput)), + String::Split::NewLineOr(",")); auto asserts = options.hasArgument("asyncify-asserts"); auto verbose = options.hasArgument("asyncify-verbose"); auto relocatable = options.hasArgument("asyncify-relocatable"); diff --git a/src/support/string.h b/src/support/string.h index a73121f6b8e..751efdac5bc 100644 --- a/src/support/string.h +++ b/src/support/string.h @@ -31,10 +31,14 @@ namespace wasm::String { // Creates a vector of the split parts of a string, by a delimiter. class Split : public std::vector { -public: - Split() = default; +private: + // If we split on newlines then we do not need to handle bracketing at all. + // Otherwise, splitting on say "," does require us to understanding the + // scoping of brackets, e.g., "foo(x, y),bar" should be split as "foo(x, y)", + // "bar". + bool needToHandleBracketingOperations = true; - Split(const std::string& input, const std::string& delim) { + void split(const std::string& input, const std::string& delim) { size_t lastEnd = 0; while (lastEnd < input.size()) { auto nextDelim = input.find(delim, lastEnd); @@ -44,6 +48,31 @@ class Split : public std::vector { (*this).push_back(input.substr(lastEnd, nextDelim - lastEnd)); lastEnd = nextDelim + delim.size(); } + needToHandleBracketingOperations = delim != "\n"; + } + friend String::Split handleBracketingOperators(String::Split split); + +public: + // This can be used when we want to split on newlines if there are any, and if + // there are not, then using the given delimiter. + struct NewLineOr { + const std::string delim; + explicit NewLineOr(const std::string& delim) : delim(delim) {} + }; + + Split() = default; + + Split(const std::string& input, const NewLineOr& newLineOrDelim) { + auto first = input.find("\n", 0); + if (first != std::string::npos && first != input.length() - 1) { + split(input, "\n"); + } else { + split(input, newLineOrDelim.delim); + } + } + + Split(const std::string& input, const std::string& delim) { + split(input, delim); } }; @@ -53,6 +82,10 @@ class Split : public std::vector { // must be kept together because of the "(". Likewise, "{", "<", "[" are // handled. inline String::Split handleBracketingOperators(String::Split split) { + if (!split.needToHandleBracketingOperations) { + return split; + } + String::Split ret; std::string last; int nesting = 0; diff --git a/test/lit/passes/asyncify-foo,bar-nl.txt b/test/lit/passes/asyncify-foo,bar-nl.txt new file mode 100644 index 00000000000..a907ec3f431 --- /dev/null +++ b/test/lit/passes/asyncify-foo,bar-nl.txt @@ -0,0 +1,2 @@ +foo +bar \ No newline at end of file diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.wast b/test/lit/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.wast index 83dd0a2ced5..9b98a4b5099 100644 --- a/test/lit/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.wast +++ b/test/lit/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.wast @@ -2,6 +2,7 @@ ;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. ;; RUN: foreach %s %t wasm-opt --asyncify --pass-arg=asyncify-blacklist@foo,bar -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --asyncify --pass-arg=asyncify-blacklist@@%S/asyncify-foo,bar-nl.txt -S -o - | filecheck %s (module (memory 1 2) diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.wast b/test/lit/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.wast index 438216c5b0f..6c809856689 100644 --- a/test/lit/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.wast +++ b/test/lit/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.wast @@ -2,6 +2,7 @@ ;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. ;; RUN: foreach %s %t wasm-opt --asyncify --pass-arg=asyncify-onlylist@foo,bar -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --asyncify --pass-arg=asyncify-onlylist@@%S/asyncify-foo,bar-nl.txt -S -o - | filecheck %s (module (memory 1 2)