Skip to content

Commit

Permalink
Always do a full roundtrip in run-roundtrip.py
Browse files Browse the repository at this point in the history
Even when the result is to be printed rather than compared byte for byte
with the first version its still good to process the resulting wat
output file so that we know we can parse what we generate.

Case in point, this changed caused me to fix two latent bugs:

1. We were not correctly parsing events with inline import/export.
2. We were output element segment names even when bulk memory
   was not enabled (See #1651)

The fix for (2) is a little more involved that we might like since for
the first time the wat writer needs to know what features are enabled.

Fixes: #1651
  • Loading branch information
sbc100 committed Apr 8, 2021
1 parent 6e5684a commit cb85409
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 54 deletions.
18 changes: 12 additions & 6 deletions src/tools/wasm2wat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ static int s_verbose;
static std::string s_infile;
static std::string s_outfile;
static Features s_features;
static WriteWatOptions s_write_wat_options;
static bool s_generate_names = false;
static bool s_generate_names;
static bool s_fold_exprs;
static bool s_inline_import;
static bool s_inline_export;
static bool s_read_debug_names = true;
static bool s_fail_on_custom_section_error = true;
static std::unique_ptr<FileStream> s_log_stream;
Expand Down Expand Up @@ -72,12 +74,12 @@ static void ParseOptions(int argc, char** argv) {
ConvertBackslashToSlash(&s_outfile);
});
parser.AddOption('f', "fold-exprs", "Write folded expressions where possible",
[]() { s_write_wat_options.fold_exprs = true; });
[]() { s_fold_exprs = true; });
s_features.AddOptions(&parser);
parser.AddOption("inline-exports", "Write all exports inline",
[]() { s_write_wat_options.inline_export = true; });
[]() { s_inline_export = true; });
parser.AddOption("inline-imports", "Write all imports inline",
[]() { s_write_wat_options.inline_import = true; });
[]() { s_inline_import = true; });
parser.AddOption("no-debug-names", "Ignore debug names in the binary file",
[]() { s_read_debug_names = false; });
parser.AddOption("ignore-custom-section-errors",
Expand Down Expand Up @@ -132,9 +134,13 @@ int ProgramMain(int argc, char** argv) {
}

if (Succeeded(result)) {
WriteWatOptions wat_options(s_features);
wat_options.fold_exprs = s_fold_exprs;
wat_options.inline_import = s_inline_import;
wat_options.inline_export = s_inline_export;
FileStream stream(!s_outfile.empty() ? FileStream(s_outfile)
: FileStream(stdout));
result = WriteWat(&stream, &module, s_write_wat_options);
result = WriteWat(&stream, &module, wat_options);
}
}
FormatErrorsToFile(errors, Location::Type::Binary);
Expand Down
18 changes: 12 additions & 6 deletions src/tools/wat-desugar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ using namespace wabt;

static const char* s_infile;
static const char* s_outfile;
static WriteWatOptions s_write_wat_options;
static bool s_generate_names;
static bool s_debug_parsing;
static bool s_fold_exprs;
static bool s_generate_names;
static bool s_inline_import;
static bool s_inline_export;
static Features s_features;

static const char s_description[] =
Expand All @@ -64,11 +66,11 @@ static void ParseOptions(int argc, char** argv) {
parser.AddOption("debug-parser", "Turn on debugging the parser of wat files",
[]() { s_debug_parsing = true; });
parser.AddOption('f', "fold-exprs", "Write folded expressions where possible",
[]() { s_write_wat_options.fold_exprs = true; });
[]() { s_fold_exprs = true; });
parser.AddOption("inline-exports", "Write all exports inline",
[]() { s_write_wat_options.inline_export = true; });
[]() { s_inline_export = true; });
parser.AddOption("inline-imports", "Write all imports inline",
[]() { s_write_wat_options.inline_import = true; });
[]() { s_inline_import = true; });
s_features.AddOptions(&parser);
parser.AddOption(
"generate-names",
Expand Down Expand Up @@ -115,8 +117,12 @@ int ProgramMain(int argc, char** argv) {
}

if (Succeeded(result)) {
WriteWatOptions wat_options(s_features);
wat_options.fold_exprs = s_fold_exprs;
wat_options.inline_import = s_inline_import;
wat_options.inline_export = s_inline_export;
FileStream stream(s_outfile ? FileStream(s_outfile) : FileStream(stdout));
result = WriteWat(&stream, module, s_write_wat_options);
result = WriteWat(&stream, module, wat_options);
}
}

Expand Down
33 changes: 28 additions & 5 deletions src/wast-parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1195,13 +1195,36 @@ Result WastParser::ParseElemModuleField(Module* module) {
Result WastParser::ParseEventModuleField(Module* module) {
WABT_TRACE(ParseEventModuleField);
EXPECT(Lpar);
auto field = MakeUnique<EventModuleField>(GetLocation());
Location loc = GetLocation();
EXPECT(Event);
ParseBindVarOpt(&field->event.name);
CHECK_RESULT(ParseTypeUseOpt(&field->event.decl));
CHECK_RESULT(ParseUnboundFuncSignature(&field->event.decl.sig));

std::string name;
ParseBindVarOpt(&name);

ModuleFieldList export_fields;
CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Event));

if (PeekMatchLpar(TokenType::Import)) {
CheckImportOrdering(module);
auto import = MakeUnique<EventImport>(name);
Event& event = import->event;
CHECK_RESULT(ParseInlineImport(import.get()));
CHECK_RESULT(ParseTypeUseOpt(&event.decl));
CHECK_RESULT(ParseUnboundFuncSignature(&event.decl.sig));
CHECK_RESULT(ErrorIfLpar({"type", "param", "result"}));
auto field =
MakeUnique<ImportModuleField>(std::move(import), GetLocation());
module->AppendField(std::move(field));
} else {
auto field = MakeUnique<EventModuleField>(loc, name);
CHECK_RESULT(ParseTypeUseOpt(&field->event.decl));
CHECK_RESULT(ParseUnboundFuncSignature(&field->event.decl.sig));
module->AppendField(std::move(field));
}

AppendInlineExportFields(module, &export_fields, module->events.size() - 1);

EXPECT(Rpar);
module->AppendField(std::move(field));
return Result::Ok;
}

Expand Down
8 changes: 7 additions & 1 deletion src/wat-writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,13 @@ void WatWriter::WriteTable(const Table& table) {

void WatWriter::WriteElemSegment(const ElemSegment& segment) {
WriteOpenSpace("elem");
WriteNameOrIndex(segment.name, elem_segment_index_, NextChar::Space);
// The name there pre-bulk-memory was intended to refer to the table
// so don't write the segment name unless bulk memory is enabled.
if (options_.features.bulk_memory_enabled()) {
WriteNameOrIndex(segment.name, elem_segment_index_, NextChar::Space);
} else {
Writef("(;%u;)", elem_segment_index_);
}

uint8_t flags = segment.GetFlags(&module);

Expand Down
4 changes: 4 additions & 0 deletions src/wat-writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@
#define WABT_WAT_WRITER_H_

#include "src/common.h"
#include "src/feature.h"

namespace wabt {

struct Module;
class Stream;

struct WriteWatOptions {
WriteWatOptions() = default;
WriteWatOptions(const Features& features) : features(features) {}
Features features;
bool fold_exprs = false; // Write folded expressions.
bool inline_export = false;
bool inline_import = false;
Expand Down
2 changes: 1 addition & 1 deletion test/roundtrip/apply-global-names.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
(table $T0 1 funcref)
(memory $M0 1)
(global $g1 i32 (global.get $m.g))
(elem $e0 (global.get $m.g) func $f0)
(elem (;0;) (global.get $m.g) func $f0)
(data $d0 (global.get $m.g) "hi"))
;;; STDOUT ;;)
2 changes: 1 addition & 1 deletion test/roundtrip/generate-func-names.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
(table $T0 3 3 funcref)
(export "zero" (func $zero))
(export "one" (func $one))
(elem $e0 (i32.const 0) func $zero $one $zero))
(elem (;0;) (i32.const 0) func $zero $one $zero))
;;; STDOUT ;;)
2 changes: 1 addition & 1 deletion test/roundtrip/generate-func-type-names.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
call_indirect $T0 (type $t0)
i32.const 1)
(table $T0 1 1 funcref)
(elem $e0 (i32.const 0) func $foo.bar))
(elem (;0;) (i32.const 0) func $foo.bar))
;;; STDOUT ;;)
2 changes: 1 addition & 1 deletion test/roundtrip/generate-some-names.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@
(table $T0 1 1 funcref)
(export "baz" (func $import))
(export "quux" (func $func0))
(elem $e0 (i32.const 0) func $import))
(elem (;0;) (i32.const 0) func $import))
;;; STDOUT ;;)
6 changes: 3 additions & 3 deletions test/roundtrip/inline-export-func.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
;;; TOOL: run-roundtrip
;;; ARGS: --stdout --inline-export
(module
(func $foo
(func $foo (param i32)
nop)
(export "foo" (func $foo)))
(;; STDOUT ;;;
(module
(type (;0;) (func))
(func (;0;) (export "foo") (type 0)
(type (;0;) (func (param i32)))
(func (;0;) (export "foo") (type 0) (param i32)
nop))
;;; STDOUT ;;)
42 changes: 13 additions & 29 deletions test/run-roundtrip.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ def FilesAreEqual(filename1, filename2, verbose=False):
return (OK, '')


def TwoRoundtrips(wat2wasm, wasm2wat, out_dir, filename, verbose):
def DoRoundtrip(wat2wasm, wasm2wat, out_dir, filename, verbose, stdout):
basename = os.path.basename(filename)
basename_noext = os.path.splitext(basename)[0]
wasm1_file = os.path.join(out_dir, basename_noext + '-1.wasm')
wast2_file = os.path.join(out_dir, basename_noext + '-2.wast')
wat2_file = os.path.join(out_dir, basename_noext + '-2.wat')
wasm3_file = os.path.join(out_dir, basename_noext + '-3.wasm')
try:
wat2wasm.RunWithArgs('-o', wasm1_file, filename)
Expand All @@ -68,28 +68,16 @@ def TwoRoundtrips(wat2wasm, wasm2wat, out_dir, filename, verbose):
# test)
return (SKIPPED, None)
try:
wasm2wat.RunWithArgs('-o', wast2_file, wasm1_file)
wat2wasm.RunWithArgs('-o', wasm3_file, wast2_file)
wasm2wat.RunWithArgs('-o', wat2_file, wasm1_file)
wat2wasm.RunWithArgs('-o', wasm3_file, wat2_file)
except Error as e:
return (ERROR, str(e))
return FilesAreEqual(wasm1_file, wasm3_file, verbose)


def OneRoundtripToStdout(wat2wasm, wasm2wat, out_dir, filename, verbose):
basename = os.path.basename(filename)
basename_noext = os.path.splitext(basename)[0]
wasm_file = os.path.join(out_dir, basename_noext + '.wasm')
try:
wat2wasm.RunWithArgs('-o', wasm_file, filename)
except Error:
# if the file doesn't parse properly, just skip it (it may be a "bad-*"
# test)
return (SKIPPED, None)
try:
wasm2wat.RunWithArgs(wasm_file)
except Error as e:
return (ERROR, str(e))
return (OK, '')
if stdout:
with open(wat2_file) as f:
sys.stdout.write(f.read())
return (OK, '')
else:
return FilesAreEqual(wasm1_file, wasm3_file, verbose)


def main(args):
Expand All @@ -102,7 +90,7 @@ def main(args):
default=find_exe.GetDefaultPath(),
help='directory to search for all executables.')
parser.add_argument('--stdout', action='store_true',
help='do one roundtrip and write wast output to stdout')
help='do one roundtrip and write wat output to stdout')
parser.add_argument('--no-error-cmdline',
help='don\'t display the subprocess\'s commandline when '
'an error occurs', dest='error_cmdline',
Expand Down Expand Up @@ -182,12 +170,8 @@ def main(args):
return ERROR

with utils.TempDirectory(options.out_dir, 'roundtrip-') as out_dir:
if options.stdout:
result, msg = OneRoundtripToStdout(wat2wasm, wasm2wat, out_dir,
filename, options.verbose)
else:
result, msg = TwoRoundtrips(wat2wasm, wasm2wat, out_dir, filename,
options.verbose)
result, msg = DoRoundtrip(wat2wasm, wasm2wat, out_dir, filename,
options.verbose, options.stdout)
if result == ERROR:
sys.stderr.write(msg)
return result
Expand Down

0 comments on commit cb85409

Please sign in to comment.