diff options
-rw-r--r-- | src/wasm-binary.h | 10 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 24 | ||||
-rw-r--r-- | test/debugInfo.fromasm.clamp.map | 2 | ||||
-rw-r--r-- | test/debugInfo.fromasm.map | 2 | ||||
-rwxr-xr-x | test/unit/input/bulkmem_bad_datacount.wasm | bin | 0 -> 177 bytes | |||
-rwxr-xr-x | test/unit/input/bulkmem_data.wasm | bin | 0 -> 177 bytes | |||
-rw-r--r-- | test/unit/test_datacount.py | 16 | ||||
-rw-r--r-- | test/unit/test_features.py | 33 | ||||
-rw-r--r-- | test/unit/utils.py | 16 |
9 files changed, 78 insertions, 25 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 50b78fbae..1f6222cba 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -322,7 +322,8 @@ enum Section { Start = 8, Element = 9, Code = 10, - Data = 11 + Data = 11, + DataCount = 12, }; enum SegmentFlag { @@ -891,6 +892,7 @@ public: void writeFunctions(); void writeGlobals(); void writeExports(); + void writeDataCount(); void writeDataSegments(); std::unordered_map<Name, Index> mappedFunctions; // name of the Function => index. first imports, then internals @@ -1083,8 +1085,14 @@ public: std::map<Index, Name> mappedGlobals; // index of the Global => name. first imported globals, then internal globals Name getGlobalName(Index index); + void validateBinary(); // validations that cannot be performed on the Module void processFunctions(); + + size_t dataCount = 0; + bool hasDataCount = false; + void readDataSegments(); + void readDataCount(); std::map<Index, std::vector<Index>> functionTable; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index b351a46e5..f3642203d 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -58,6 +58,7 @@ void WasmBinaryWriter::write() { writeExports(); writeStart(); writeTableElements(); + writeDataCount(); writeFunctions(); writeDataSegments(); if (debugInfo) writeNames(); @@ -312,6 +313,15 @@ void WasmBinaryWriter::writeExports() { finishSection(start); } +void WasmBinaryWriter::writeDataCount() { + if (!wasm->features.hasBulkMemory() || !wasm->memory.segments.size()) { + return; + } + auto start = startSection(BinaryConsts::Section::DataCount); + o << U32LEB(wasm->memory.segments.size()); + finishSection(start); +} + void WasmBinaryWriter::writeDataSegments() { if (wasm->memory.segments.size() == 0) return; if (wasm->memory.segments.size() > WebLimitations::MaxDataSegments) { @@ -657,6 +667,7 @@ void WasmBinaryBuilder::read() { break; } case BinaryConsts::Section::Data: readDataSegments(); break; + case BinaryConsts::Section::DataCount: readDataCount(); break; case BinaryConsts::Section::Table: readFunctionTableDeclaration(); break; default: { readUserSection(payloadLen); @@ -673,6 +684,7 @@ void WasmBinaryBuilder::read() { } } + validateBinary(); processFunctions(); } @@ -1457,6 +1469,12 @@ Name WasmBinaryBuilder::getGlobalName(Index index) { return mappedGlobals[index]; } +void WasmBinaryBuilder::validateBinary() { + if (hasDataCount && wasm.memory.segments.size() != dataCount) { + throwError("Number of segments does not agree with DataCount section"); + } +} + void WasmBinaryBuilder::processFunctions() { for (auto* func : functions) { wasm.addFunction(func); @@ -1504,6 +1522,12 @@ void WasmBinaryBuilder::processFunctions() { wasm.updateMaps(); } +void WasmBinaryBuilder::readDataCount() { + if (debug) std::cerr << "== readDataCount" << std::endl; + hasDataCount = true; + dataCount = getU32LEB(); +} + void WasmBinaryBuilder::readDataSegments() { if (debug) std::cerr << "== readDataSegments" << std::endl; auto num = getU32LEB(); diff --git a/test/debugInfo.fromasm.clamp.map b/test/debugInfo.fromasm.clamp.map index e49a7309c..e922a9c4b 100644 --- a/test/debugInfo.fromasm.clamp.map +++ b/test/debugInfo.fromasm.clamp.map @@ -1 +1 @@ -{"version":3,"sources":["tests/hello_world.c","tests/other_file.cpp","return.cpp","even-opted.cpp","fib.c","/tmp/emscripten_test_binaryen2_28hnAe/src.c","(unknown)"],"names":[],"mappings":"qIC8ylTA,QC7vlTA,OAkDA,UCjGA,AADA,EADA,+BCEA,cAKA,QAJA,OADA,0BAKA,sECsi1DA,KCrvyDA"}
\ No newline at end of file +{"version":3,"sources":["tests/hello_world.c","tests/other_file.cpp","return.cpp","even-opted.cpp","fib.c","/tmp/emscripten_test_binaryen2_28hnAe/src.c","(unknown)"],"names":[],"mappings":"wIC8ylTA,QC7vlTA,OAkDA,UCjGA,AADA,EADA,+BCEA,cAKA,QAJA,OADA,0BAKA,sECsi1DA,KCrvyDA"}
\ No newline at end of file diff --git a/test/debugInfo.fromasm.map b/test/debugInfo.fromasm.map index e49a7309c..e922a9c4b 100644 --- a/test/debugInfo.fromasm.map +++ b/test/debugInfo.fromasm.map @@ -1 +1 @@ -{"version":3,"sources":["tests/hello_world.c","tests/other_file.cpp","return.cpp","even-opted.cpp","fib.c","/tmp/emscripten_test_binaryen2_28hnAe/src.c","(unknown)"],"names":[],"mappings":"qIC8ylTA,QC7vlTA,OAkDA,UCjGA,AADA,EADA,+BCEA,cAKA,QAJA,OADA,0BAKA,sECsi1DA,KCrvyDA"}
\ No newline at end of file +{"version":3,"sources":["tests/hello_world.c","tests/other_file.cpp","return.cpp","even-opted.cpp","fib.c","/tmp/emscripten_test_binaryen2_28hnAe/src.c","(unknown)"],"names":[],"mappings":"wIC8ylTA,QC7vlTA,OAkDA,UCjGA,AADA,EADA,+BCEA,cAKA,QAJA,OADA,0BAKA,sECsi1DA,KCrvyDA"}
\ No newline at end of file diff --git a/test/unit/input/bulkmem_bad_datacount.wasm b/test/unit/input/bulkmem_bad_datacount.wasm Binary files differnew file mode 100755 index 000000000..e7b6e4bb7 --- /dev/null +++ b/test/unit/input/bulkmem_bad_datacount.wasm diff --git a/test/unit/input/bulkmem_data.wasm b/test/unit/input/bulkmem_data.wasm Binary files differnew file mode 100755 index 000000000..aa9e535b5 --- /dev/null +++ b/test/unit/input/bulkmem_data.wasm diff --git a/test/unit/test_datacount.py b/test/unit/test_datacount.py new file mode 100644 index 000000000..87ddbd58d --- /dev/null +++ b/test/unit/test_datacount.py @@ -0,0 +1,16 @@ +import unittest +from scripts.test.shared import WASM_OPT, run_process +from utils import roundtrip, input_path + + +class DataCountTest(unittest.TestCase): + def test_datacount(self): + roundtrip(self, 'bulkmem_data.wasm') + + def test_bad_datacount(self): + path = input_path('bulkmem_bad_datacount.wasm') + p = run_process(WASM_OPT + ['-g', '-o', '-', path], check=False, + capture_output=True) + self.assertNotEqual(p.returncode, 0) + self.assertIn('Number of segments does not agree with DataCount section', + p.stderr) diff --git a/test/unit/test_features.py b/test/unit/test_features.py index f130e1408..1672b957a 100644 --- a/test/unit/test_features.py +++ b/test/unit/test_features.py @@ -1,6 +1,7 @@ import os import unittest -from scripts.test.shared import WASM_OPT, run_process, options +from scripts.test.shared import WASM_OPT, run_process +from utils import input_path, roundtrip class FeatureValidationTest(unittest.TestCase): @@ -117,50 +118,40 @@ class FeatureValidationTest(unittest.TestCase): class TargetFeaturesSectionTest(unittest.TestCase): def disassemble(self, filename): - path = os.path.join(options.binaryen_test, 'unit', 'input', filename) + path = input_path(filename) p = run_process(WASM_OPT + ['--print', '-o', os.devnull, path], check=False, capture_output=True) self.assertEqual(p.returncode, 0) self.assertEqual(p.stderr, '') return p.stdout - def roundtrip(self, filename): - path = os.path.join(options.binaryen_test, 'unit', 'input', filename) - p = run_process(WASM_OPT + ['-g', '-o', '-', path], check=False, - capture_output=True) - self.assertEqual(p.returncode, 0) - self.assertEqual(p.stderr, '') - with open(path, 'rb') as f: - self.assertEqual(str(p.stdout), str(f.read())) - def test_atomics(self): - self.roundtrip('atomics_target_feature.wasm') + roundtrip(self, 'atomics_target_feature.wasm') module = self.disassemble('atomics_target_feature.wasm') self.assertIn('i32.atomic.rmw.add', module) def test_bulk_memory(self): - self.roundtrip('bulkmem_target_feature.wasm') + roundtrip(self, 'bulkmem_target_feature.wasm') module = self.disassemble('bulkmem_target_feature.wasm') self.assertIn('memory.copy', module) def test_nontrapping_fptoint(self): - self.roundtrip('truncsat_target_feature.wasm') + roundtrip(self, 'truncsat_target_feature.wasm') module = self.disassemble('truncsat_target_feature.wasm') self.assertIn('i32.trunc_sat_f32_u', module) def test_sign_ext(self): - self.roundtrip('signext_target_feature.wasm') + roundtrip(self, 'signext_target_feature.wasm') module = self.disassemble('signext_target_feature.wasm') self.assertIn('i32.extend8_s', module) def test_simd(self): - self.roundtrip('simd_target_feature.wasm') + roundtrip(self, 'simd_target_feature.wasm') module = self.disassemble('simd_target_feature.wasm') self.assertIn('i32x4.splat', module) def test_incompatible_features(self): - path = os.path.join(options.binaryen_test, 'unit', 'input', - 'signext_target_feature.wasm') + path = input_path('signext_target_feature.wasm') p = run_process( WASM_OPT + ['--print', '-mvp', '--enable-simd', '-o', os.devnull, path], check=False, capture_output=True @@ -171,8 +162,7 @@ class TargetFeaturesSectionTest(unittest.TestCase): p.stderr) def test_incompatible_features_forced(self): - path = os.path.join(options.binaryen_test, 'unit', 'input', - 'signext_target_feature.wasm') + path = input_path('signext_target_feature.wasm') p = run_process( WASM_OPT + ['--print', '--detect-features', '-mvp', '--enable-simd', '-o', os.devnull, path], @@ -182,8 +172,7 @@ class TargetFeaturesSectionTest(unittest.TestCase): self.assertIn('all used features should be allowed', p.stderr) def test_explicit_detect_features(self): - path = os.path.join(options.binaryen_test, 'unit', 'input', - 'signext_target_feature.wasm') + path = input_path('signext_target_feature.wasm') p = run_process( WASM_OPT + ['--print', '-mvp', '--detect-features', '-o', os.devnull, path], diff --git a/test/unit/utils.py b/test/unit/utils.py new file mode 100644 index 000000000..eaeb29d42 --- /dev/null +++ b/test/unit/utils.py @@ -0,0 +1,16 @@ +import os +from scripts.test.shared import WASM_OPT, run_process, options + + +def input_path(filename): + return os.path.join(options.binaryen_test, 'unit', 'input', filename) + + +def roundtrip(testcase, filename, opts=[]): + path = input_path(filename) + p = run_process(WASM_OPT + ['-g', '-o', '-', path] + opts, check=False, + capture_output=True) + testcase.assertEqual(p.returncode, 0) + testcase.assertEqual(p.stderr, '') + with open(path, 'rb') as f: + testcase.assertEqual(str(p.stdout), str(f.read())) |