Changeset 209880 in webkit
- Timestamp:
- Dec 15, 2016 3:42:19 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r209874 r209880 1 2016-12-15 JF Bastien <jfbastien@apple.com> 2 3 WebAssembly: improve compilation error messages 4 https://bugs.webkit.org/show_bug.cgi?id=163919 5 6 Reviewed by Saam Barati. 7 8 Update error messages in these tests. 9 Use the assert.throws facility in many of them which weren't already. 10 11 * wasm/js-api/element.js: 12 (assert.throws.new.WebAssembly.Module.builder.WebAssembly): 13 (assert.throws): 14 * wasm/js-api/global-error.js: 15 (assert.throws.new.WebAssembly.Module.bin): 16 (assert.throws): 17 (new.Number): 18 * wasm/js-api/table.js: 19 (assert.throws.new.WebAssembly.Module.builder.WebAssembly): 20 (assert.throws): 21 (assertBadTableImport): 22 * wasm/js-api/test_Data.js: 23 (DataSectionWithoutMemory): 24 * wasm/js-api/test_Start.js: 25 (InvalidStartFunctionIndex): 26 * wasm/js-api/test_basic_api.js: 27 (const.c.in.constructorProperties.switch): 28 1 29 2016-12-15 JF Bastien <jfbastien@apple.com> 2 30 -
trunk/JSTests/wasm/js-api/element.js
r209785 r209880 1 1 import Builder from '../Builder.js'; 2 2 import * as assert from '../assert.js'; 3 4 function assertBadBinary(builder, str) {5 const bin = builder.WebAssembly().get();6 let threw = false;7 try {8 new WebAssembly.Module(bin);9 } catch(e) {10 threw = true;11 assert.truthy(e.toString().indexOf(str) !== -1);12 assert.truthy(e instanceof WebAssembly.CompileError);13 }14 assert.truthy(threw);15 }16 17 const badElementSectionString = "couldn't parse section Element";18 3 19 4 { … … 34 19 .End(); 35 20 36 assert BadBinary(builder, badElementSectionString);21 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 22 / 41: Element section expects a Table to be present (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 37 22 } 38 23 … … 57 42 .End(); 58 43 59 assert BadBinary(builder, badElementSectionString);44 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30 / 47: Element section can only have one Table for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 60 45 } 61 46 … … 80 65 .End(); 81 66 82 assert BadBinary(builder, badElementSectionString);67 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 35 / 49: Element section's 0th element writes to index 20 which exceeds the maximum 20 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 83 68 } 84 69 … … 103 88 .End(); 104 89 105 assert BadBinary(builder, badElementSectionString);90 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 35 / 48: Element section's 0th element writes to index 20 which exceeds the maximum 20 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 106 91 } 107 92 … … 126 111 .End(); 127 112 128 assert BadBinary(builder, badElementSectionString);113 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 38 / 50: Element section's 0th element's 2th index is 1 which exceeds the function index space size of 1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 129 114 } 130 115 -
trunk/JSTests/wasm/js-api/global-error.js
r209830 r209880 24 24 bin.trim(); 25 25 26 let passed = false; 27 try { 28 const module = new WebAssembly.Module(bin.get()); 29 } catch (e) { 30 if (e.message === "couldn't parse section Global: Global declarations (evaluating 'new WebAssembly.Module(bin.get())')") 31 passed = true; 32 } 33 assert.truthy(passed); 26 assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 26 / 59: get_global's index 0 exceeds the number of imports 0 (evaluating 'new WebAssembly.Module(bin.get())')"); 34 27 } 35 28 … … 60 53 bin.trim(); 61 54 62 let passed = false; 63 try { 64 const module = new WebAssembly.Module(bin.get()); 65 } catch (e) { 66 if (e.message === "couldn't parse section Import: Import declarations (evaluating 'new WebAssembly.Module(bin.get())')") 67 passed = true; 68 } 69 assert.truthy(passed); 55 assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 32 / 76: Mutable Globals aren't supported (evaluating 'new WebAssembly.Module(bin.get())')"); 70 56 } 71 57 … … 92 78 bin.trim(); 93 79 94 let passed = false; 95 try { 96 const module = new WebAssembly.Module(bin.get()); 97 } catch (e) { 98 if (e.message === "couldn't parse section Export: Exports (evaluating 'new WebAssembly.Module(bin.get())')") 99 passed = true; 100 } 101 assert.truthy(passed); 80 assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 51 / 59: 1th Export isn't immutable, named 'global' (evaluating 'new WebAssembly.Module(bin.get())')"); 102 81 } 103 82 … … 125 104 bin.trim(); 126 105 127 let passed = false; 128 try { 129 const module = new WebAssembly.Module(bin.get()); 130 } catch (e) { 131 if (e.message === "Attempt to store to immutable global. (evaluating 'new WebAssembly.Module(bin.get())')") 132 passed = true; 133 } 134 assert.truthy(passed); 106 assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: set_global 0 is immutable (evaluating 'new WebAssembly.Module(bin.get())')"); 135 107 } 136 108 … … 159 131 bin.trim(); 160 132 161 let passed = false; 162 try { 163 const module = new WebAssembly.Module(bin.get()); 164 } catch (e) { 165 if (e.message === "Attempt to use unknown global. (evaluating 'new WebAssembly.Module(bin.get())')") 166 passed = true; 167 } 168 assert.truthy(passed); 133 assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: set_global 1 of unknown global, limit is 1 (evaluating 'new WebAssembly.Module(bin.get())')"); 169 134 } 170 135 … … 192 157 bin.trim(); 193 158 194 let passed = false; 195 try { 196 const module = new WebAssembly.Module(bin.get()); 197 } catch (e) { 198 if (e.message === "Attempt to set global with type: F32 with a variable of type: I32 (evaluating 'new WebAssembly.Module(bin.get())')") 199 passed = true; 200 } 201 assert.truthy(passed); 159 assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: set_global 0 with type F32 with a variable of type I32 (evaluating 'new WebAssembly.Module(bin.get())')"); 202 160 } 203 161 … … 227 185 bin.trim(); 228 186 229 let passed = false;230 187 const module = new WebAssembly.Module(bin.get()); 231 try { 232 new WebAssembly.Instance(module, { imp: { global: imp } }); 233 } catch (e) { 234 if (e.message === "imported global must be a number (evaluating 'new WebAssembly.Instance(module, { imp: { global: imp } })')") 235 passed = true; 236 } 237 assert.truthy(passed); 188 assert.throws(() => new WebAssembly.Instance(module, { imp: { global: imp } }), TypeError, "imported global must be a number (evaluating 'new WebAssembly.Instance(module, { imp: { global: imp } })')"); 238 189 } -
trunk/JSTests/wasm/js-api/table.js
r209850 r209880 2 2 import * as assert from '../assert.js'; 3 3 4 const badTableString = "couldn't parse section Table: Indirect function table and other tables (evaluating 'new WebAssembly.Module(bin)')";5 const badImportString = "couldn't parse section Import: Import declarations (evaluating 'new WebAssembly.Module(bin)')";6 const badExportString = "couldn't parse section Export: Exports (evaluating 'new WebAssembly.Module(bin)')";7 8 function assertBadBinary(builder, str) {9 const bin = builder.WebAssembly().get();10 assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, str);11 }12 13 4 { 14 5 const builder = new Builder() … … 23 14 .Code() 24 15 .End(); 25 assert BadBinary(builder, badTableString);26 } 27 28 { 29 const builder = new Builder() 30 .Type().End() 31 .Function().End() 32 .Table() 33 .Table({initial: 20, maximum: 30, element: "anyfunc"}) 34 .Table({initial: 20, maximum: 30, element: "anyfunc"}) 35 .End() 36 .Code() 37 .End(); 38 assert BadBinary(builder, badTableString);16 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 34 / 41: Table section cannot exist if an Import has a table (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 17 } 18 19 { 20 const builder = new Builder() 21 .Type().End() 22 .Function().End() 23 .Table() 24 .Table({initial: 20, maximum: 30, element: "anyfunc"}) 25 .Table({initial: 20, maximum: 30, element: "anyfunc"}) 26 .End() 27 .Code() 28 .End(); 29 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 17 / 28: Table count of 2 is invalid, only 1 is allowed for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 39 30 } 40 31 … … 52 43 .End() 53 44 .End(); 54 assert BadBinary(builder, "call_indirect is only valid when a table is defined or imported (evaluating 'new WebAssembly.Module(bin)')");45 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 4 / 7: call_indirect is only valid when a table is defined or imported (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 55 46 } 56 47 … … 71 62 .End() 72 63 .End(); 73 assert BadBinary(builder, "call_indirect 'reserved' varuint1 must be 0x0 (evaluating 'new WebAssembly.Module(bin)')");64 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6 / 7: call_indirect's 'reserved' varuint1 must be 0x0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 74 65 } 75 66 … … 84 75 .Code() 85 76 .End(); 86 assert BadBinary(builder, badExportString);77 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 23 / 26: can't export a non-existent Table (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 87 78 } 88 79 … … 100 91 .Code() 101 92 .End(); 102 assert BadBinary(builder, badExportString);103 } 104 105 function assertBadTable(tableDescription ) {93 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30 / 33: can't export Table 1 only zero-index Table is currently supported (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 94 } 95 96 function assertBadTable(tableDescription, message) { 106 97 const builder = new Builder() 107 98 .Type().End() … … 112 103 .Code() 113 104 .End(); 114 assert BadBinary(builder, badTableString);115 } 116 117 function assertBadTableImport(tableDescription ) {105 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message); 106 } 107 108 function assertBadTableImport(tableDescription, message) { 118 109 const builder = new Builder() 119 110 .Type().End() … … 124 115 .Code() 125 116 .End(); 126 assert BadBinary(builder, badImportString);117 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message); 127 118 } 128 119 129 120 { 130 121 let badDescriptions = [ 131 {initial: 10, element: "i32"}, 132 {initial: 10, element: "f32"}, 133 {initial: 10, element: "f64"}, 134 {initial: 10, element: "i64"}, 135 {initial: 10, maximum: 20, element: "i32"}, 136 {initial: 10, maximum: 20, element: "f32"}, 137 {initial: 10, maximum: 20, element: "f64"}, 138 {initial: 10, maximum: 20, element: "i64"}, 139 140 {initial: 10, maximum: 9, element: "anyfunc"}, 141 {initial: 1, maximum: 0, element: "anyfunc"}, 142 {initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"}, 143 {initial: 2**31, element: "anyfunc"}, 122 [{initial: 10, element: "i32"}, 123 "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 124 "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 125 [{initial: 10, element: "f32"}, 126 "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 127 "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 128 [{initial: 10, element: "f64"}, 129 "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 130 "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 131 [{initial: 10, element: "i64"}, 132 "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 133 "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 134 [{initial: 10, maximum: 20, element: "i32"}, 135 "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 136 "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 137 [{initial: 10, maximum: 20, element: "f32"}, 138 "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 139 "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 140 [{initial: 10, maximum: 20, element: "f64"}, 141 "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 142 "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 143 [{initial: 10, maximum: 20, element: "i64"}, 144 "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 145 "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 146 147 [{initial: 10, maximum: 9, element: "anyfunc"}, 148 "WebAssembly.Module doesn't parse at byte 21 / 24: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 149 "WebAssembly.Module doesn't parse at byte 29 / 35: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 150 [{initial: 1, maximum: 0, element: "anyfunc"}, 151 "WebAssembly.Module doesn't parse at byte 21 / 24: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 152 "WebAssembly.Module doesn't parse at byte 29 / 35: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 153 [{initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"}, 154 "WebAssembly.Module doesn't parse at byte 29 / 32: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 155 "WebAssembly.Module doesn't parse at byte 37 / 43: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 156 [{initial: 2**31, element: "anyfunc"}, 157 "WebAssembly.Module doesn't parse at byte 24 / 27: Table's initial page count of 2147483648 is invalid (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", 158 "WebAssembly.Module doesn't parse at byte 32 / 38: Table's initial page count of 2147483648 is invalid (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], 144 159 ]; 145 160 146 161 for (const d of badDescriptions) { 147 assertBadTable(d );148 assertBadTableImport(d );162 assertBadTable(d[0], d[1]); 163 assertBadTableImport(d[0], d[2]); 149 164 } 150 165 } … … 160 175 .Code() 161 176 .End(); 162 assert BadBinary(builder, badImportString);177 assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 39 / 48: Table section cannot exist if an Import has a table (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); 163 178 } 164 179 … … 174 189 .Code() 175 190 .End(); 176 177 let threw = false;178 191 const module = new WebAssembly.Module(builder.WebAssembly().get()); 179 try { 180 new WebAssembly.Instance(module, {imp: {table}}); 181 } catch (e) { 182 assert.eq(e.toString(), message); 183 threw = true; 184 } 185 assert.truthy(threw); 192 assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), TypeError, message); 186 193 } 187 194 188 195 const badTables = [ 189 [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, element: "anyfunc"}), "T ypeError: Table import does not have a 'maximum' but the module requires that it does"],190 [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, maximum:101, element: "anyfunc"}), " TypeError:Imported Table's 'maximum' is larger than the module's expected 'maximum'"],191 [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "T ypeError: Table import provided an 'initial' that is too small"],192 [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "T ypeError: Table import provided an 'initial' that is too small"],196 [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, element: "anyfunc"}), "Table import does not have a 'maximum' but the module requires that it does"], 197 [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, maximum:101, element: "anyfunc"}), "Imported Table's 'maximum' is larger than the module's expected 'maximum'"], 198 [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "Table import provided an 'initial' that is too small"], 199 [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "Table import provided an 'initial' that is too small"], 193 200 ]; 194 201 for (const [d, t, m] of badTables) { -
trunk/JSTests/wasm/js-api/test_Data.js
r209874 r209880 53 53 .End(); 54 54 const bin = builder.WebAssembly().get(); 55 assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, ` couldn't parse section Data: Data segments(evaluating 'new WebAssembly.Module(bin)')`);55 assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 13 / 20: Data section cannot exist without a Memory section or Import (evaluating 'new WebAssembly.Module(bin)')`); 56 56 })(); 57 57 … … 63 63 .End(); 64 64 const bin = builder.WebAssembly().get(); 65 assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, ` couldn't parse section Data: Data segments(evaluating 'new WebAssembly.Module(bin)')`);65 assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 13 / 19: Data section cannot exist without a Memory section or Import (evaluating 'new WebAssembly.Module(bin)')`); 66 66 })(); 67 67 -
trunk/JSTests/wasm/js-api/test_Start.js
r209642 r209880 32 32 .Code().End(); 33 33 const bin = b.WebAssembly().get(); 34 assert.throws(() => new WebAssembly.Module(bin), Error, ` couldn't parse section Start: Start function declaration(evaluating 'new WebAssembly.Module(bin)')`);34 assert.throws(() => new WebAssembly.Module(bin), Error, `WebAssembly.Module doesn't parse at byte 17 / 20: Start index 0 exceeds function index space 0 (evaluating 'new WebAssembly.Module(bin)')`); 35 35 })(); -
trunk/JSTests/wasm/js-api/test_basic_api.js
r209771 r209880 56 56 for (const buffer of [new ArrayBuffer(), new DataView(new ArrayBuffer()), new Int8Array(), new Uint8Array(), new Uint8ClampedArray(), new Int16Array(), new Uint16Array(), new Int32Array(), new Uint32Array(), new Float32Array(), new Float64Array()]) 57 57 // FIXME the following should be WebAssembly.CompileError. https://bugs.webkit.org/show_bug.cgi?id=163768 58 assert.throws(() => new WebAssembly[c](buffer), Error, ` Module is 0 bytes, expectedat least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`);58 assert.throws(() => new WebAssembly[c](buffer), Error, `WebAssembly.Module doesn't parse at byte 0 / 0: expected a module of at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`); 59 59 assert.instanceof(new WebAssembly[c](emptyModuleArray), WebAssembly.Module); 60 60 // FIXME test neutered TypedArray and TypedArrayView. https://bugs.webkit.org/show_bug.cgi?id=163899 -
trunk/Source/JavaScriptCore/ChangeLog
r209874 r209880 1 2016-12-15 JF Bastien <jfbastien@apple.com> 2 3 WebAssembly: improve compilation error messages 4 https://bugs.webkit.org/show_bug.cgi?id=163919 5 6 Reviewed by Saam Barati. 7 8 The error handling messages were underwhelming because most 9 locations merely returned `false` on failure. This patch uses 10 std::expected to denote that failure isn't expected. Doing this 11 makes it almost impossible to mess up the code: either a function 12 returns a result (or a partial result for internal helpers) or an 13 error. We're not synchronizing the error string with the m_failed 14 bool anymore, and the caller will abort if they try to get a 15 result but the outcome was an error. 16 17 This also shortens the code significantly using macros, while also 18 judiciously preventing inlining of error handling code and biasing 19 towards success using UNLIKELY. This means that the generated code 20 should be more efficient (no string formatting on success, and 21 regalloc can avoid these unlikely paths). 22 23 The patch adds a few missing checks as well, especially related to 24 count limits and memory allocation failure. 25 26 As a follow-up I'd like to improve WTF::makeString further, so it 27 does coercions to string and understands ADL as I did in this 28 patch. 29 30 * wasm/WasmB3IRGenerator.cpp: 31 (JSC::Wasm::B3IRGenerator::fail): 32 (JSC::Wasm::parseAndCompile): 33 * wasm/WasmB3IRGenerator.h: 34 * wasm/WasmFormat.h: 35 (JSC::Wasm::isValidExternalKind): 36 (JSC::Wasm::makeString): 37 * wasm/WasmFunctionParser.h: 38 * wasm/WasmModuleParser.cpp: 39 * wasm/WasmModuleParser.h: 40 * wasm/WasmParser.h: 41 (JSC::Wasm::FailureHelper::makeString): 42 (JSC::Wasm::Parser::fail): 43 (JSC::Wasm::Parser<SuccessType>::Parser): 44 (JSC::Wasm::Parser<SuccessType>::consumeCharacter): 45 (JSC::Wasm::Parser<SuccessType>::consumeString): 46 (JSC::Wasm::Parser<SuccessType>::consumeUTF8String): 47 (JSC::Wasm::Parser<SuccessType>::parseVarUInt32): 48 (JSC::Wasm::Parser<SuccessType>::parseVarUInt64): 49 (JSC::Wasm::Parser<SuccessType>::parseVarInt32): 50 (JSC::Wasm::Parser<SuccessType>::parseVarInt64): 51 (JSC::Wasm::Parser<SuccessType>::parseUInt32): 52 (JSC::Wasm::Parser<SuccessType>::parseUInt64): 53 (JSC::Wasm::Parser<SuccessType>::parseUInt8): 54 (JSC::Wasm::Parser<SuccessType>::parseInt7): 55 (JSC::Wasm::Parser<SuccessType>::parseUInt7): 56 (JSC::Wasm::Parser<SuccessType>::parseVarUInt1): 57 (JSC::Wasm::Parser<SuccessType>::parseResultType): 58 (JSC::Wasm::Parser<SuccessType>::parseValueType): 59 (JSC::Wasm::Parser<SuccessType>::parseExternalKind): 60 * wasm/WasmPlan.cpp: 61 (JSC::Wasm::Plan::run): 62 * wasm/WasmSections.h: 63 (JSC::Wasm::isValidSection): 64 (JSC::Wasm::validateOrder): 65 (JSC::Wasm::makeString): 66 * wasm/WasmValidate.cpp: 67 (JSC::Wasm::Validate::fail): 68 (JSC::Wasm::Validate::addUnreachable): 69 (JSC::Wasm::validateFunction): 70 * wasm/WasmValidate.h: 71 * wasm/generateWasmB3IRGeneratorInlinesHeader.py: 72 * wasm/generateWasmOpsHeader.py: 73 * wasm/generateWasmValidateInlinesHeader.py: 74 (loadMacro): 75 (storeMacro): 76 * wasm/js/WebAssemblyInstanceConstructor.cpp: 77 (JSC::constructJSWebAssemblyInstance): 78 * wasm/js/WebAssemblyModuleRecord.cpp: 79 (JSC::WebAssemblyModuleRecord::link): 80 1 81 2016-12-15 JF Bastien <jfbastien@apple.com> 2 82 -
trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
r209850 r209880 138 138 static constexpr ExpressionType emptyExpression = nullptr; 139 139 140 typedef String ErrorType; 141 typedef UnexpectedType<ErrorType> UnexpectedResult; 142 typedef Expected<std::unique_ptr<WasmInternalFunction>, ErrorType> Result; 143 typedef Expected<void, ErrorType> PartialResult; 144 template <typename ...Args> 145 NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const 146 { 147 using namespace FailureHelper; // See ADL comment in WasmParser.h. 148 return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module failed compiling: "), makeString(args)...)); 149 } 150 #define WASM_COMPILE_FAIL_IF(condition, ...) do { \ 151 if (UNLIKELY(condition)) \ 152 return fail(__VA_ARGS__); \ 153 } while (0) 154 140 155 B3IRGenerator(VM&, const ModuleInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&); 141 156 142 boolWARN_UNUSED_RETURN addArguments(const Vector<Type>&);143 boolWARN_UNUSED_RETURN addLocal(Type, uint32_t);157 PartialResult WARN_UNUSED_RETURN addArguments(const Vector<Type>&); 158 PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t); 144 159 ExpressionType addConstant(Type, uint64_t); 145 160 146 161 // Locals 147 boolWARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);148 boolWARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);162 PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result); 163 PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value); 149 164 150 165 // Globals 151 boolWARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);152 boolWARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);166 PartialResult WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result); 167 PartialResult WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value); 153 168 154 169 // Memory 155 boolWARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);156 boolWARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);170 PartialResult WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset); 171 PartialResult WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset); 157 172 158 173 // Basic operators 159 174 template<OpType> 160 boolWARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);175 PartialResult WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result); 161 176 template<OpType> 162 boolWARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);163 boolWARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);177 PartialResult WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result); 178 PartialResult WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result); 164 179 165 180 // Control flow 166 181 ControlData WARN_UNUSED_RETURN addBlock(Type signature); 167 182 ControlData WARN_UNUSED_RETURN addLoop(Type signature); 168 boolWARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);169 boolWARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);170 boolWARN_UNUSED_RETURN addElseToUnreachable(ControlData&);171 172 boolWARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);173 boolWARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues);174 boolWARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTargets, const ExpressionList& expressionStack);175 boolWARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);176 boolWARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);183 PartialResult WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result); 184 PartialResult WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&); 185 PartialResult WARN_UNUSED_RETURN addElseToUnreachable(ControlData&); 186 187 PartialResult WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues); 188 PartialResult WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues); 189 PartialResult WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTargets, const ExpressionList& expressionStack); 190 PartialResult WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack); 191 PartialResult WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&); 177 192 178 193 // Calls 179 boolWARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature*, Vector<ExpressionType>& args, ExpressionType& result);180 boolWARN_UNUSED_RETURN addCallIndirect(const Signature*, Vector<ExpressionType>& args, ExpressionType& result);181 voidaddUnreachable();194 PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature*, Vector<ExpressionType>& args, ExpressionType& result); 195 PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature*, Vector<ExpressionType>& args, ExpressionType& result); 196 PartialResult WARN_UNUSED_RETURN addUnreachable(); 182 197 183 198 void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack); 184 185 void setErrorMessage(String&&) { UNREACHABLE_FOR_PLATFORM(); }186 199 187 200 private: … … 292 305 } 293 306 294 bool B3IRGenerator::addLocal(Type type, uint32_t count) 295 { 296 if (!m_locals.tryReserveCapacity(m_locals.size() + count)) 297 return false; 307 auto B3IRGenerator::addLocal(Type type, uint32_t count) -> PartialResult 308 { 309 WASM_COMPILE_FAIL_IF(!m_locals.tryReserveCapacity(m_locals.size() + count), "can't allocate memory for ", m_locals.size() + count, " locals"); 298 310 299 311 for (uint32_t i = 0; i < count; ++i) { … … 302 314 m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), local, zeroForType(type)); 303 315 } 304 return true;305 } 306 307 bool B3IRGenerator::addArguments(const Vector<Type>& types) 316 return { }; 317 } 318 319 auto B3IRGenerator::addArguments(const Vector<Type>& types) -> PartialResult 308 320 { 309 321 ASSERT(!m_locals.size()); 310 if (!m_locals.tryReserveCapacity(types.size())) 311 return false; 322 WASM_COMPILE_FAIL_IF(!m_locals.tryReserveCapacity(types.size()), "can't allocate memory for ", types.size(), " arguments"); 312 323 313 324 m_locals.grow(types.size()); … … 318 329 m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), argumentVariable, argument); 319 330 }); 320 return true;321 } 322 323 bool B3IRGenerator::getLocal(uint32_t index, ExpressionType& result) 331 return { }; 332 } 333 334 auto B3IRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult 324 335 { 325 336 ASSERT(m_locals[index]); 326 337 result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), m_locals[index]); 327 return true;328 } 329 330 void B3IRGenerator::addUnreachable() 338 return { }; 339 } 340 341 auto B3IRGenerator::addUnreachable() -> PartialResult 331 342 { 332 343 B3::PatchpointValue* unreachable = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin()); … … 335 346 }); 336 347 unreachable->effects.terminal = true; 337 } 338 339 bool B3IRGenerator::setLocal(uint32_t index, ExpressionType value) 348 return { }; 349 } 350 351 auto B3IRGenerator::setLocal(uint32_t index, ExpressionType value) -> PartialResult 340 352 { 341 353 ASSERT(m_locals[index]); 342 354 m_currentBlock->appendNew<VariableValue>(m_proc, B3::Set, Origin(), m_locals[index], value); 343 return true;344 } 345 346 bool B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result) 355 return { }; 356 } 357 358 auto B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result) -> PartialResult 347 359 { 348 360 Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals()); 349 361 result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), Origin(), globalsArray, index * sizeof(Register)); 350 return true;351 } 352 353 bool B3IRGenerator::setGlobal(uint32_t index, ExpressionType value) 362 return { }; 363 } 364 365 auto B3IRGenerator::setGlobal(uint32_t index, ExpressionType value) -> PartialResult 354 366 { 355 367 ASSERT(toB3Type(m_info.globals[index].type) == value->type()); 356 368 Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals()); 357 369 m_currentBlock->appendNew<MemoryValue>(m_proc, Store, Origin(), value, globalsArray, index * sizeof(Register)); 358 return true;370 return { }; 359 371 } 360 372 … … 466 478 } 467 479 468 bool B3IRGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset) 480 auto B3IRGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset) -> PartialResult 469 481 { 470 482 ASSERT(pointer->type() == Int32); 471 483 472 484 result = emitLoadOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfLoadOp(op)), offset); 473 return true;485 return { }; 474 486 } 475 487 … … 528 540 } 529 541 530 bool B3IRGenerator::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset) 542 auto B3IRGenerator::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset) -> PartialResult 531 543 { 532 544 ASSERT(pointer->type() == Int32); 533 545 534 546 emitStoreOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfStoreOp(op)), value, offset); 535 return true;536 } 537 538 bool B3IRGenerator::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) 547 return { }; 548 } 549 550 auto B3IRGenerator::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> PartialResult 539 551 { 540 552 result = m_currentBlock->appendNew<Value>(m_proc, B3::Select, Origin(), condition, nonZero, zero); 541 return true;553 return { }; 542 554 } 543 555 … … 577 589 } 578 590 579 bool B3IRGenerator::addIf(ExpressionType condition, Type signature, ControlType& result) 591 auto B3IRGenerator::addIf(ExpressionType condition, Type signature, ControlType& result) -> PartialResult 580 592 { 581 593 // FIXME: This needs to do some kind of stack passing. … … 592 604 m_currentBlock = taken; 593 605 result = ControlData(m_proc, signature, BlockType::If, continuation, notTaken); 594 return true;595 } 596 597 bool B3IRGenerator::addElse(ControlData& data, const ExpressionList& currentStack) 606 return { }; 607 } 608 609 auto B3IRGenerator::addElse(ControlData& data, const ExpressionList& currentStack) -> PartialResult 598 610 { 599 611 unifyValuesWithBlock(currentStack, data.result); … … 602 614 } 603 615 604 bool B3IRGenerator::addElseToUnreachable(ControlData& data) 616 auto B3IRGenerator::addElseToUnreachable(ControlData& data) -> PartialResult 605 617 { 606 618 ASSERT(data.type() == BlockType::If); 607 619 m_currentBlock = data.special; 608 620 data.convertIfToBlock(); 609 return true;610 } 611 612 bool B3IRGenerator::addReturn(const ExpressionList& returnValues) 621 return { }; 622 } 623 624 auto B3IRGenerator::addReturn(const ExpressionList& returnValues) -> PartialResult 613 625 { 614 626 ASSERT(returnValues.size() <= 1); … … 617 629 else 618 630 m_currentBlock->appendNewControlValue(m_proc, B3::Return, Origin()); 619 return true;620 } 621 622 bool B3IRGenerator::addBranch(ControlData& data, ExpressionType condition, const ExpressionList& returnValues) 631 return { }; 632 } 633 634 auto B3IRGenerator::addBranch(ControlData& data, ExpressionType condition, const ExpressionList& returnValues) -> PartialResult 623 635 { 624 636 if (data.type() != BlockType::Loop) … … 638 650 } 639 651 640 return true;641 } 642 643 bool B3IRGenerator::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) 652 return { }; 653 } 654 655 auto B3IRGenerator::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) -> PartialResult 644 656 { 645 657 for (size_t i = 0; i < targets.size(); ++i) … … 652 664 switchValue->appendCase(SwitchCase(i, FrequentedBlock(targets[i]->targetBlockForBranch()))); 653 665 654 return true;655 } 656 657 bool B3IRGenerator::endBlock(ControlEntry& entry, ExpressionList& expressionStack) 666 return { }; 667 } 668 669 auto B3IRGenerator::endBlock(ControlEntry& entry, ExpressionList& expressionStack) -> PartialResult 658 670 { 659 671 ControlData& data = entry.controlData; … … 667 679 668 680 669 bool B3IRGenerator::addEndToUnreachable(ControlEntry& entry) 681 auto B3IRGenerator::addEndToUnreachable(ControlEntry& entry) -> PartialResult 670 682 { 671 683 ControlData& data = entry.controlData; … … 680 692 entry.enclosedExpressionStack.append(m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), result)); 681 693 682 return true;683 } 684 685 bool B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) 694 return { }; 695 } 696 697 auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult 686 698 { 687 699 ASSERT(signature->arguments.size() == args.size()); … … 706 718 }); 707 719 }); 708 return true;709 } 710 711 bool B3IRGenerator::addCallIndirect(const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) 720 return { }; 721 } 722 723 auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult 712 724 { 713 725 ExpressionType calleeIndex = args.takeLast(); … … 780 792 }); 781 793 782 return true;794 return { }; 783 795 } 784 796 … … 908 920 } 909 921 910 std::unique_ptr<WasmInternalFunction> parseAndCompile(VM& vm, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info, unsigned optLevel)922 Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info, unsigned optLevel) 911 923 { 912 924 auto result = std::make_unique<WasmInternalFunction>(); … … 915 927 B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace); 916 928 FunctionParser<B3IRGenerator> parser(context, functionStart, functionLength, signature, functionIndexSpace, info); 917 if (!parser.parse()) 918 RELEASE_ASSERT_NOT_REACHED(); 929 WASM_FAIL_IF_HELPER_FAILS(parser.parse()); 919 930 920 931 procedure.resetReachability(); … … 930 941 result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters(); 931 942 result->jsToWasmEntrypoint.compilation = createJSToWasmWrapper(vm, *result, signature, result->wasmEntrypoint.compilation->code(), info.memory); 932 return result;943 return WTFMove(result); 933 944 } 934 945 … … 936 947 937 948 template<> 938 bool B3IRGenerator::addOp<OpType::I32Ctz>(ExpressionType arg, ExpressionType& result) 949 auto B3IRGenerator::addOp<OpType::I32Ctz>(ExpressionType arg, ExpressionType& result) -> PartialResult 939 950 { 940 951 PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin()); … … 945 956 patchpoint->effects = Effects::none(); 946 957 result = patchpoint; 947 return true;948 } 949 950 template<> 951 bool B3IRGenerator::addOp<OpType::I64Ctz>(ExpressionType arg, ExpressionType& result) 958 return { }; 959 } 960 961 template<> 962 auto B3IRGenerator::addOp<OpType::I64Ctz>(ExpressionType arg, ExpressionType& result) -> PartialResult 952 963 { 953 964 PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin()); … … 958 969 patchpoint->effects = Effects::none(); 959 970 result = patchpoint; 960 return true;961 } 962 963 template<> 964 bool B3IRGenerator::addOp<OpType::I32Popcnt>(ExpressionType arg, ExpressionType& result) 971 return { }; 972 } 973 974 template<> 975 auto B3IRGenerator::addOp<OpType::I32Popcnt>(ExpressionType arg, ExpressionType& result) -> PartialResult 965 976 { 966 977 // FIXME: This should use the popcnt instruction if SSE4 is available but we don't have code to detect SSE4 yet. … … 969 980 Value* funcAddress = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<void*>(popcount)); 970 981 result = m_currentBlock->appendNew<CCallValue>(m_proc, Int32, Origin(), Effects::none(), funcAddress, arg); 971 return true;972 } 973 974 template<> 975 bool B3IRGenerator::addOp<OpType::I64Popcnt>(ExpressionType arg, ExpressionType& result) 982 return { }; 983 } 984 985 template<> 986 auto B3IRGenerator::addOp<OpType::I64Popcnt>(ExpressionType arg, ExpressionType& result) -> PartialResult 976 987 { 977 988 // FIXME: This should use the popcnt instruction if SSE4 is available but we don't have code to detect SSE4 yet. … … 980 991 Value* funcAddress = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<void*>(popcount)); 981 992 result = m_currentBlock->appendNew<CCallValue>(m_proc, Int64, Origin(), Effects::none(), funcAddress, arg); 982 return true;983 } 984 985 template<> 986 bool B3IRGenerator::addOp<F64ConvertUI64>(ExpressionType arg, ExpressionType& result) 993 return { }; 994 } 995 996 template<> 997 auto B3IRGenerator::addOp<F64ConvertUI64>(ExpressionType arg, ExpressionType& result) -> PartialResult 987 998 { 988 999 PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin()); … … 1000 1011 patchpoint->effects = Effects::none(); 1001 1012 result = patchpoint; 1002 return true;1003 } 1004 1005 template<> 1006 bool B3IRGenerator::addOp<OpType::F32ConvertUI64>(ExpressionType arg, ExpressionType& result) 1013 return { }; 1014 } 1015 1016 template<> 1017 auto B3IRGenerator::addOp<OpType::F32ConvertUI64>(ExpressionType arg, ExpressionType& result) -> PartialResult 1007 1018 { 1008 1019 PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin()); … … 1020 1031 patchpoint->effects = Effects::none(); 1021 1032 result = patchpoint; 1022 return true;1023 } 1024 1025 template<> 1026 bool B3IRGenerator::addOp<OpType::F64Nearest>(ExpressionType arg, ExpressionType& result) 1033 return { }; 1034 } 1035 1036 template<> 1037 auto B3IRGenerator::addOp<OpType::F64Nearest>(ExpressionType arg, ExpressionType& result) -> PartialResult 1027 1038 { 1028 1039 PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin()); … … 1033 1044 patchpoint->effects = Effects::none(); 1034 1045 result = patchpoint; 1035 return true;1036 } 1037 1038 template<> 1039 bool B3IRGenerator::addOp<OpType::F32Nearest>(ExpressionType arg, ExpressionType& result) 1046 return { }; 1047 } 1048 1049 template<> 1050 auto B3IRGenerator::addOp<OpType::F32Nearest>(ExpressionType arg, ExpressionType& result) -> PartialResult 1040 1051 { 1041 1052 PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin()); … … 1046 1057 patchpoint->effects = Effects::none(); 1047 1058 result = patchpoint; 1048 return true;1049 } 1050 1051 template<> 1052 bool B3IRGenerator::addOp<OpType::F64Trunc>(ExpressionType arg, ExpressionType& result) 1059 return { }; 1060 } 1061 1062 template<> 1063 auto B3IRGenerator::addOp<OpType::F64Trunc>(ExpressionType arg, ExpressionType& result) -> PartialResult 1053 1064 { 1054 1065 PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin()); … … 1059 1070 patchpoint->effects = Effects::none(); 1060 1071 result = patchpoint; 1061 return true;1062 } 1063 1064 template<> 1065 bool B3IRGenerator::addOp<OpType::F32Trunc>(ExpressionType arg, ExpressionType& result) 1072 return { }; 1073 } 1074 1075 template<> 1076 auto B3IRGenerator::addOp<OpType::F32Trunc>(ExpressionType arg, ExpressionType& result) -> PartialResult 1066 1077 { 1067 1078 PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin()); … … 1072 1083 patchpoint->effects = Effects::none(); 1073 1084 result = patchpoint; 1074 return true;1075 } 1076 1077 template<> 1078 bool B3IRGenerator::addOp<OpType::I32TruncSF64>(ExpressionType arg, ExpressionType& result) 1085 return { }; 1086 } 1087 1088 template<> 1089 auto B3IRGenerator::addOp<OpType::I32TruncSF64>(ExpressionType arg, ExpressionType& result) -> PartialResult 1079 1090 { 1080 1091 Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -static_cast<double>(std::numeric_limits<int32_t>::min())); … … 1095 1106 patchpoint->effects = Effects::none(); 1096 1107 result = patchpoint; 1097 return true;1098 } 1099 1100 template<> 1101 bool B3IRGenerator::addOp<OpType::I32TruncSF32>(ExpressionType arg, ExpressionType& result) 1108 return { }; 1109 } 1110 1111 template<> 1112 auto B3IRGenerator::addOp<OpType::I32TruncSF32>(ExpressionType arg, ExpressionType& result) -> PartialResult 1102 1113 { 1103 1114 Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -static_cast<float>(std::numeric_limits<int32_t>::min())); … … 1118 1129 patchpoint->effects = Effects::none(); 1119 1130 result = patchpoint; 1120 return true;1121 } 1122 1123 1124 template<> 1125 bool B3IRGenerator::addOp<OpType::I32TruncUF64>(ExpressionType arg, ExpressionType& result) 1131 return { }; 1132 } 1133 1134 1135 template<> 1136 auto B3IRGenerator::addOp<OpType::I32TruncUF64>(ExpressionType arg, ExpressionType& result) -> PartialResult 1126 1137 { 1127 1138 Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int32_t>::min()) * -2.0); … … 1142 1153 patchpoint->effects = Effects::none(); 1143 1154 result = patchpoint; 1144 return true;1145 } 1146 1147 template<> 1148 bool B3IRGenerator::addOp<OpType::I32TruncUF32>(ExpressionType arg, ExpressionType& result) 1155 return { }; 1156 } 1157 1158 template<> 1159 auto B3IRGenerator::addOp<OpType::I32TruncUF32>(ExpressionType arg, ExpressionType& result) -> PartialResult 1149 1160 { 1150 1161 Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int32_t>::min()) * -2.0); … … 1165 1176 patchpoint->effects = Effects::none(); 1166 1177 result = patchpoint; 1167 return true;1168 } 1169 1170 template<> 1171 bool B3IRGenerator::addOp<OpType::I64TruncSF64>(ExpressionType arg, ExpressionType& result) 1178 return { }; 1179 } 1180 1181 template<> 1182 auto B3IRGenerator::addOp<OpType::I64TruncSF64>(ExpressionType arg, ExpressionType& result) -> PartialResult 1172 1183 { 1173 1184 Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -static_cast<double>(std::numeric_limits<int64_t>::min())); … … 1188 1199 patchpoint->effects = Effects::none(); 1189 1200 result = patchpoint; 1190 return true;1191 } 1192 1193 template<> 1194 bool B3IRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionType& result) 1201 return { }; 1202 } 1203 1204 template<> 1205 auto B3IRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionType& result) -> PartialResult 1195 1206 { 1196 1207 Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int64_t>::min()) * -2.0); … … 1230 1241 patchpoint->effects = Effects::none(); 1231 1242 result = patchpoint; 1232 return true;1233 } 1234 1235 template<> 1236 bool B3IRGenerator::addOp<OpType::I64TruncSF32>(ExpressionType arg, ExpressionType& result) 1243 return { }; 1244 } 1245 1246 template<> 1247 auto B3IRGenerator::addOp<OpType::I64TruncSF32>(ExpressionType arg, ExpressionType& result) -> PartialResult 1237 1248 { 1238 1249 Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -static_cast<float>(std::numeric_limits<int64_t>::min())); … … 1253 1264 patchpoint->effects = Effects::none(); 1254 1265 result = patchpoint; 1255 return true;1256 } 1257 1258 template<> 1259 bool B3IRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionType& result) 1266 return { }; 1267 } 1268 1269 template<> 1270 auto B3IRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionType& result) -> PartialResult 1260 1271 { 1261 1272 Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int64_t>::min()) * -2.0); … … 1295 1306 patchpoint->effects = Effects::none(); 1296 1307 result = patchpoint; 1297 return true;1308 return { }; 1298 1309 } 1299 1310 -
trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h
r209652 r209880 31 31 #include "VM.h" 32 32 #include "WasmFormat.h" 33 #include <wtf/Expected.h> 33 34 34 35 extern "C" void dumpProcedure(void*); … … 38 39 class MemoryInformation; 39 40 40 std::unique_ptr<WasmInternalFunction> parseAndCompile(VM&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1);41 Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1); 41 42 42 43 } } // namespace JSC::Wasm -
trunk/Source/JavaScriptCore/wasm/WasmFormat.h
r209830 r209880 62 62 } 63 63 64 struct External { 65 enum Kind : uint8_t { 66 // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231 67 Function = 0, 68 Table = 1, 69 Memory = 2, 70 Global = 3, 71 }; 72 template<typename Int> 73 static bool isValid(Int val) 74 { 75 switch (val) { 76 case Function: 77 case Table: 78 case Memory: 79 case Global: 80 return true; 81 default: 82 return false; 83 } 84 } 85 86 static_assert(Function == 0, "Wasm needs Function to have the value 0"); 87 static_assert(Table == 1, "Wasm needs Table to have the value 1"); 88 static_assert(Memory == 2, "Wasm needs Memory to have the value 2"); 89 static_assert(Global == 3, "Wasm needs Global to have the value 3"); 90 }; 64 enum class ExternalKind : uint8_t { 65 // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231 66 Function = 0, 67 Table = 1, 68 Memory = 2, 69 Global = 3, 70 }; 71 72 template<typename Int> 73 static bool isValidExternalKind(Int val) 74 { 75 switch (val) { 76 case static_cast<Int>(ExternalKind::Function): 77 case static_cast<Int>(ExternalKind::Table): 78 case static_cast<Int>(ExternalKind::Memory): 79 case static_cast<Int>(ExternalKind::Global): 80 return true; 81 default: 82 return false; 83 } 84 } 85 86 static_assert(static_cast<int>(ExternalKind::Function) == 0, "Wasm needs Function to have the value 0"); 87 static_assert(static_cast<int>(ExternalKind::Table) == 1, "Wasm needs Table to have the value 1"); 88 static_assert(static_cast<int>(ExternalKind::Memory) == 2, "Wasm needs Memory to have the value 2"); 89 static_assert(static_cast<int>(ExternalKind::Global) == 3, "Wasm needs Global to have the value 3"); 90 91 static inline const char* makeString(ExternalKind kind) 92 { 93 switch (kind) { 94 case ExternalKind::Function: return "Function"; 95 case ExternalKind::Table: return "Table"; 96 case ExternalKind::Memory: return "Memory"; 97 case ExternalKind::Global: return "Global"; 98 } 99 RELEASE_ASSERT_NOT_REACHED(); 100 return "?"; 101 } 91 102 92 103 struct Signature { … … 98 109 Identifier module; 99 110 Identifier field; 100 External ::Kind kind;111 ExternalKind kind; 101 112 unsigned kindIndex; // Index in the vector of the corresponding kind. 102 113 }; … … 104 115 struct Export { 105 116 Identifier field; 106 External ::Kind kind;117 ExternalKind kind; 107 118 unsigned kindIndex; // Index in the vector of the corresponding kind. 108 119 }; -
trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h
r209852 r209880 40 40 41 41 template<typename Context> 42 class FunctionParser : public Parser {42 class FunctionParser : public Parser<void> { 43 43 public: 44 44 typedef typename Context::ExpressionType ExpressionType; … … 48 48 FunctionParser(Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&); 49 49 50 boolWARN_UNUSED_RETURN parse();50 Result WARN_UNUSED_RETURN parse(); 51 51 52 52 struct ControlEntry { … … 58 58 static const bool verbose = false; 59 59 60 bool WARN_UNUSED_RETURN parseBody(); 61 bool WARN_UNUSED_RETURN parseExpression(OpType); 62 bool WARN_UNUSED_RETURN parseUnreachableExpression(OpType); 63 bool WARN_UNUSED_RETURN addReturn(); 64 bool WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level); 65 66 bool WARN_UNUSED_RETURN popExpressionStack(ExpressionType& result); 60 PartialResult WARN_UNUSED_RETURN parseBody(); 61 PartialResult WARN_UNUSED_RETURN parseExpression(OpType); 62 PartialResult WARN_UNUSED_RETURN parseUnreachableExpression(OpType); 63 PartialResult WARN_UNUSED_RETURN addReturn(); 64 PartialResult WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level); 65 66 #define WASM_TRY_POP_EXPRESSION_STACK_INTO(result, what) do { \ 67 WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't pop empty stack in " what); \ 68 result = m_expressionStack.takeLast(); \ 69 } while (0) 67 70 68 71 template<OpType> 69 boolWARN_UNUSED_RETURN unaryCase();72 PartialResult WARN_UNUSED_RETURN unaryCase(); 70 73 71 74 template<OpType> 72 bool WARN_UNUSED_RETURN binaryCase(); 73 74 bool setErrorMessage(String&& message) 75 { 76 m_context.setErrorMessage(WTFMove(message)); 77 return false; 78 } 75 PartialResult WARN_UNUSED_RETURN binaryCase(); 76 77 #define WASM_TRY_ADD_TO_CONTEXT(add_expression) WASM_FAIL_IF_HELPER_FAILS(m_context.add_expression) 78 79 // FIXME add a macro as above for WASM_TRY_APPEND_TO_CONTROL_STACK https://bugs.webkit.org/show_bug.cgi?id=165862 79 80 80 81 Context& m_context; … … 100 101 101 102 template<typename Context> 102 bool FunctionParser<Context>::parse() 103 { 104 if (!m_context.addArguments(m_signature->arguments)) 105 return false; 106 103 auto FunctionParser<Context>::parse() -> Result 104 { 107 105 uint32_t localCount; 108 if (!parseVarUInt32(localCount)) 109 return false; 106 107 WASM_PARSER_FAIL_IF(!m_context.addArguments(m_signature->arguments), "can't add ", m_signature->arguments.size(), " arguments to Function"); 108 WASM_PARSER_FAIL_IF(!parseVarUInt32(localCount), "can't get local count"); 109 WASM_PARSER_FAIL_IF(localCount == std::numeric_limits<uint32_t>::max(), "Function section's local count is too big ", localCount); 110 110 111 111 for (uint32_t i = 0; i < localCount; ++i) { 112 112 uint32_t numberOfLocals; 113 if (!parseVarUInt32(numberOfLocals))114 return false;115 116 113 Type typeOfLocal; 117 if (!parseValueType(typeOfLocal)) 118 return false; 119 120 if (!m_context.addLocal(typeOfLocal, numberOfLocals)) 121 return false; 122 } 123 124 return parseBody(); 125 } 126 127 template<typename Context> 128 bool FunctionParser<Context>::parseBody() 114 115 WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfLocals), "can't get Function's number of locals in group ", i); 116 WASM_PARSER_FAIL_IF(numberOfLocals == std::numeric_limits<uint32_t>::max(), "Function section's ", i, "th local group count is too big ", numberOfLocals); 117 WASM_PARSER_FAIL_IF(!parseValueType(typeOfLocal), "can't get Function local's type in group ", i); 118 WASM_PARSER_FAIL_IF(!m_context.addLocal(typeOfLocal, numberOfLocals), "can't add ", numberOfLocals, " Function locals from group ", i); 119 } 120 121 WASM_FAIL_IF_HELPER_FAILS(parseBody()); 122 123 return { }; 124 } 125 126 template<typename Context> 127 auto FunctionParser<Context>::parseBody() -> PartialResult 129 128 { 130 129 while (true) { 131 130 uint8_t op; 132 if (!parseUInt8(op) || !isValidOpType(op)) { 133 if (verbose) 134 WTF::dataLogLn("attempted to decode invalid op: ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset))); 135 return false; 136 } 131 WASM_PARSER_FAIL_IF(!parseUInt8(op), "can't decode opcode"); 132 WASM_PARSER_FAIL_IF(!isValidOpType(op), "invalid opcode ", op); 137 133 138 134 if (verbose) { … … 141 137 } 142 138 143 if (op == OpType::End && !m_controlStack.size()) 144 return m_unreachableBlocks ? true : addReturn(); 145 146 if (m_unreachableBlocks) { 147 if (!parseUnreachableExpression(static_cast<OpType>(op))) { 148 if (verbose) 149 dataLogLn("failed to process unreachable op:", op); 150 return false; 151 } 152 } else if (!parseExpression(static_cast<OpType>(op))) { 153 if (verbose) 154 dataLogLn("failed to process op:", op); 155 return false; 139 if (op == OpType::End && !m_controlStack.size()) { 140 if (m_unreachableBlocks) 141 return { }; 142 return addReturn(); 156 143 } 157 144 145 if (m_unreachableBlocks) 146 WASM_FAIL_IF_HELPER_FAILS(parseUnreachableExpression(static_cast<OpType>(op))); 147 else 148 WASM_FAIL_IF_HELPER_FAILS(parseExpression(static_cast<OpType>(op))); 158 149 } 159 150 … … 162 153 163 154 template<typename Context> 164 bool FunctionParser<Context>::addReturn() 155 auto FunctionParser<Context>::addReturn() -> PartialResult 165 156 { 166 157 ExpressionList returnValues; 167 158 if (m_signature->returnType != Void) { 168 159 ExpressionType returnValue; 169 if (!popExpressionStack(returnValue)) 170 return false; 160 WASM_TRY_POP_EXPRESSION_STACK_INTO(returnValue, "return"); 171 161 returnValues.append(returnValue); 172 162 } 173 163 174 164 m_unreachableBlocks = 1; 175 return m_context.addReturn(returnValues); 165 WASM_TRY_ADD_TO_CONTEXT(addReturn(returnValues)); 166 return { }; 176 167 } 177 168 178 169 template<typename Context> 179 170 template<OpType op> 180 bool FunctionParser<Context>::binaryCase() 171 auto FunctionParser<Context>::binaryCase() -> PartialResult 181 172 { 182 173 ExpressionType right; 183 if (!popExpressionStack(right))184 return false;185 186 174 ExpressionType left; 187 if (!popExpressionStack(left))188 return false;189 190 175 ExpressionType result; 191 if (!m_context.template addOp<op>(left, right, result)) 192 return false; 176 177 WASM_TRY_POP_EXPRESSION_STACK_INTO(right, "binary right"); 178 WASM_TRY_POP_EXPRESSION_STACK_INTO(left, "binary left"); 179 WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(left, right, result)); 180 193 181 m_expressionStack.append(result); 194 return true;182 return { }; 195 183 } 196 184 197 185 template<typename Context> 198 186 template<OpType op> 199 bool FunctionParser<Context>::unaryCase() 187 auto FunctionParser<Context>::unaryCase() -> PartialResult 200 188 { 201 189 ExpressionType value; 202 if (!popExpressionStack(value))203 return false;204 205 190 ExpressionType result; 206 if (!m_context.template addOp<op>(value, result)) 207 return false; 191 192 WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "unary"); 193 WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(value, result)); 194 208 195 m_expressionStack.append(result); 209 return true;210 } 211 212 template<typename Context> 213 bool FunctionParser<Context>::parseExpression(OpType op) 196 return { }; 197 } 198 199 template<typename Context> 200 auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult 214 201 { 215 202 switch (op) { … … 242 229 case OpType::Select: { 243 230 ExpressionType condition; 244 if (!popExpressionStack(condition))245 return false;246 247 231 ExpressionType zero; 248 if (!popExpressionStack(zero))249 return false;250 251 232 ExpressionType nonZero; 252 if (!popExpressionStack(nonZero)) 253 return false; 233 234 WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "select condition"); 235 WASM_TRY_POP_EXPRESSION_STACK_INTO(zero, "select zero"); 236 WASM_TRY_POP_EXPRESSION_STACK_INTO(nonZero, "select non-zero"); 254 237 255 238 ExpressionType result; 256 if (!m_context.addSelect(condition, nonZero, zero, result)) 257 return false; 239 WASM_TRY_ADD_TO_CONTEXT(addSelect(condition, nonZero, zero, result)); 258 240 259 241 m_expressionStack.append(result); 260 return true;242 return { }; 261 243 } 262 244 … … 264 246 FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) { 265 247 uint32_t alignment; 266 if (!parseVarUInt32(alignment))267 return false;268 269 248 uint32_t offset; 270 if (!parseVarUInt32(offset))271 return false;272 273 249 ExpressionType pointer; 274 if (!popExpressionStack(pointer))275 return false;276 277 250 ExpressionType result; 278 if (!m_context.load(static_cast<LoadOpType>(op), pointer, result, offset)) 279 return false; 251 WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get load alignment"); 252 WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get load offset"); 253 WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "load pointer"); 254 WASM_TRY_ADD_TO_CONTEXT(load(static_cast<LoadOpType>(op), pointer, result, offset)); 280 255 m_expressionStack.append(result); 281 return true;256 return { }; 282 257 } 283 258 284 259 FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) { 285 260 uint32_t alignment; 286 if (!parseVarUInt32(alignment))287 return false;288 289 261 uint32_t offset; 290 if (!parseVarUInt32(offset))291 return false;292 293 262 ExpressionType value; 294 if (!popExpressionStack(value))295 return false;296 297 263 ExpressionType pointer; 298 if (!popExpressionStack(pointer)) 299 return false; 300 301 return m_context.store(static_cast<StoreOpType>(op), pointer, value, offset); 264 WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get store alignment"); 265 WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get store offset"); 266 WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "store value"); 267 WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "store pointer"); 268 WASM_TRY_ADD_TO_CONTEXT(store(static_cast<StoreOpType>(op), pointer, value, offset)); 269 return { }; 302 270 } 303 271 #undef CREATE_CASE … … 305 273 case OpType::F32Const: { 306 274 uint32_t constant; 307 if (!parseUInt32(constant)) 308 return false; 275 WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't parse 32-bit floating-point constant"); 309 276 m_expressionStack.append(m_context.addConstant(F32, constant)); 310 return true;277 return { }; 311 278 } 312 279 313 280 case OpType::I32Const: { 314 281 int32_t constant; 315 if (!parseVarInt32(constant)) 316 return false; 282 WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't parse 32-bit constant"); 317 283 m_expressionStack.append(m_context.addConstant(I32, constant)); 318 return true;284 return { }; 319 285 } 320 286 321 287 case OpType::F64Const: { 322 288 uint64_t constant; 323 if (!parseUInt64(constant)) 324 return false; 289 WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't parse 64-bit floating-point constant"); 325 290 m_expressionStack.append(m_context.addConstant(F64, constant)); 326 return true;291 return { }; 327 292 } 328 293 329 294 case OpType::I64Const: { 330 295 int64_t constant; 331 if (!parseVarInt64(constant)) 332 return false; 296 WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't parse 64-bit constant"); 333 297 m_expressionStack.append(m_context.addConstant(I64, constant)); 334 return true;298 return { }; 335 299 } 336 300 337 301 case OpType::GetLocal: { 338 302 uint32_t index; 339 if (!parseVarUInt32(index))340 return false;341 303 ExpressionType result; 342 if (!m_context.getLocal(index, result)) 343 return false; 344 304 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for get_local"); 305 WASM_PARSER_FAIL_IF(!m_context.getLocal(index, result), "can't get_local at index", index); 345 306 m_expressionStack.append(result); 346 return true;307 return { }; 347 308 } 348 309 349 310 case OpType::SetLocal: { 350 311 uint32_t index; 351 if (!parseVarUInt32(index))352 return false;353 312 ExpressionType value; 354 if (!popExpressionStack(value)) 355 return false; 356 return m_context.setLocal(index, value); 313 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for set_local"); 314 WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_local"); 315 WASM_TRY_ADD_TO_CONTEXT(setLocal(index, value)); 316 return { }; 357 317 } 358 318 359 319 case OpType::TeeLocal: { 360 320 uint32_t index; 361 if (!parseVarUInt32(index)) 362 return false; 363 if (!m_expressionStack.size()) 364 return false; 365 return m_context.setLocal(index, m_expressionStack.last()); 321 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for tee_local"); 322 WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't tee_local on empty expression stack"); 323 WASM_TRY_ADD_TO_CONTEXT(setLocal(index, m_expressionStack.last())); 324 return { }; 366 325 } 367 326 368 327 case OpType::GetGlobal: { 369 328 uint32_t index; 370 if (!parseVarUInt32(index))371 return false;372 329 ExpressionType result; 373 if (!m_context.getGlobal(index, result)) 374 return false; 375 330 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index"); 331 WASM_TRY_ADD_TO_CONTEXT(getGlobal(index, result)); 376 332 m_expressionStack.append(result); 377 return true;333 return { }; 378 334 } 379 335 380 336 case OpType::SetGlobal: { 381 337 uint32_t index; 382 if (!parseVarUInt32(index))383 return false;384 338 ExpressionType value; 385 if (!popExpressionStack(value)) 386 return false; 339 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get set_global's index"); 340 WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_global value"); 341 WASM_TRY_ADD_TO_CONTEXT(setGlobal(index, value)); 387 342 return m_context.setGlobal(index, value); 388 343 } … … 390 345 case OpType::Call: { 391 346 uint32_t functionIndex; 392 if (!parseVarUInt32(functionIndex)) 393 return false; 394 395 if (functionIndex >= m_functionIndexSpace.size) 396 return false; 347 WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't parse call's function index"); 348 WASM_PARSER_FAIL_IF(functionIndex >= m_functionIndexSpace.size, "call function index ", functionIndex, " exceeds function index space ", m_functionIndexSpace.size); 397 349 398 350 const Signature* calleeSignature = m_functionIndexSpace.buffer.get()[functionIndex].signature; 399 400 if (calleeSignature->arguments.size() > m_expressionStack.size()) 401 return false; 351 WASM_PARSER_FAIL_IF(calleeSignature->arguments.size() > m_expressionStack.size(), "call function index ", functionIndex, " has ", calleeSignature->arguments.size(), " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values"); 402 352 403 353 size_t firstArgumentIndex = m_expressionStack.size() - calleeSignature->arguments.size(); 404 354 Vector<ExpressionType> args; 405 args.reserveInitialCapacity(calleeSignature->arguments.size());406 for ( unsignedi = firstArgumentIndex; i < m_expressionStack.size(); ++i)407 args. append(m_expressionStack[i]);355 WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature->arguments.size()), "can't allocate enough memory for call's ", calleeSignature->arguments.size(), " arguments"); 356 for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) 357 args.uncheckedAppend(m_expressionStack[i]); 408 358 m_expressionStack.shrink(firstArgumentIndex); 409 359 410 360 ExpressionType result = Context::emptyExpression; 411 if (!m_context.addCall(functionIndex, calleeSignature, args, result)) 412 return false; 361 WASM_TRY_ADD_TO_CONTEXT(addCall(functionIndex, calleeSignature, args, result)); 413 362 414 363 if (result != Context::emptyExpression) 415 364 m_expressionStack.append(result); 416 365 417 return true;366 return { }; 418 367 } 419 368 420 369 case OpType::CallIndirect: { 421 if (!m_info.tableInformation)422 return setErrorMessage("call_indirect is only valid when a table is defined or imported");423 370 uint32_t signatureIndex; 424 if (!parseVarUInt32(signatureIndex))425 return false;426 427 371 uint8_t reserved; 428 if (!parseVarUInt1(reserved)) 429 return false; 430 431 if (reserved != 0) 432 return setErrorMessage("call_indirect 'reserved' varuint1 must be 0x0"); 433 434 if (m_info.signatures.size() <= signatureIndex) 435 return setErrorMessage("Tried to use a signature outside the range of valid signatures"); 372 WASM_PARSER_FAIL_IF(!m_info.tableInformation, "call_indirect is only valid when a table is defined or imported"); 373 WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index"); 374 WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte"); 375 WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0"); 376 WASM_PARSER_FAIL_IF(m_info.signatures.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.signatures.size()); 436 377 437 378 const Signature* calleeSignature = &m_info.signatures[signatureIndex]; 438 379 size_t argumentCount = calleeSignature->arguments.size() + 1; // Add the callee's index. 439 if (argumentCount > m_expressionStack.size()) 440 return setErrorMessage("Not enough values on the stack for call_indirect"); 380 WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values"); 441 381 442 382 Vector<ExpressionType> args; 443 if (!args.tryReserveCapacity(argumentCount)) 444 return setErrorMessage("Out of memory"); 445 383 WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount), "can't allocate enough memory for ", argumentCount, " call_indirect arguments"); 446 384 size_t firstArgumentIndex = m_expressionStack.size() - argumentCount; 447 for ( unsignedi = firstArgumentIndex; i < m_expressionStack.size(); ++i)385 for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) 448 386 args.uncheckedAppend(m_expressionStack[i]); 449 387 m_expressionStack.shrink(firstArgumentIndex); 450 388 451 389 ExpressionType result = Context::emptyExpression; 452 if (!m_context.addCallIndirect(calleeSignature, args, result)) 453 return false; 390 WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, args, result)); 454 391 455 392 if (result != Context::emptyExpression) 456 393 m_expressionStack.append(result); 457 394 458 return true;395 return { }; 459 396 } 460 397 461 398 case OpType::Block: { 462 399 Type inlineSignature; 463 if (!parseResultType(inlineSignature)) 464 return false; 465 400 WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get block's inline signature"); 466 401 m_controlStack.append({ WTFMove(m_expressionStack), m_context.addBlock(inlineSignature) }); 467 402 m_expressionStack = ExpressionList(); 468 return true;403 return { }; 469 404 } 470 405 471 406 case OpType::Loop: { 472 407 Type inlineSignature; 473 if (!parseResultType(inlineSignature)) 474 return false; 475 408 WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get loop's inline signature"); 476 409 m_controlStack.append({ WTFMove(m_expressionStack), m_context.addLoop(inlineSignature) }); 477 410 m_expressionStack = ExpressionList(); 478 return true;411 return { }; 479 412 } 480 413 481 414 case OpType::If: { 482 415 Type inlineSignature; 483 if (!parseResultType(inlineSignature))484 return false;485 486 416 ExpressionType condition; 487 if (!popExpressionStack(condition))488 return false;489 490 417 ControlType control; 491 if (!m_context.addIf(condition, inlineSignature, control))492 return false;493 418 WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get if's inline signature"); 419 WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "if condition"); 420 WASM_TRY_ADD_TO_CONTEXT(addIf(condition, inlineSignature, control)); 494 421 m_controlStack.append({ WTFMove(m_expressionStack), control }); 495 422 m_expressionStack = ExpressionList(); 496 return true;423 return { }; 497 424 } 498 425 499 426 case OpType::Else: { 500 if (!m_controlStack.size()) { 501 setErrorMessage("Attempted to use else block at the top-level of a function"); 502 return false; 503 } 504 505 if (!m_context.addElse(m_controlStack.last().controlData, m_expressionStack)) 506 return false; 427 WASM_PARSER_FAIL_IF(m_controlStack.isEmpty(), "can't use else block at the top-level of a function"); 428 WASM_TRY_ADD_TO_CONTEXT(addElse(m_controlStack.last().controlData, m_expressionStack)); 507 429 m_expressionStack.shrink(0); 508 return true;430 return { }; 509 431 } 510 432 … … 512 434 case OpType::BrIf: { 513 435 uint32_t target; 514 if (!parseVarUInt32(target) || target >= m_controlStack.size())515 return false;516 517 436 ExpressionType condition = Context::emptyExpression; 518 if (op == OpType::BrIf) { 519 if (!popExpressionStack(condition)) 520 return false; 521 } else 437 WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get br / br_if's target"); 438 WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br / br_if's target ", target, " exceeds control stack size ", m_controlStack.size()); 439 if (op == OpType::BrIf) 440 WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br / br_if condition"); 441 else 522 442 m_unreachableBlocks = 1; 523 443 524 444 ControlType& data = m_controlStack[m_controlStack.size() - 1 - target].controlData; 525 445 526 return m_context.addBranch(data, condition, m_expressionStack); 446 WASM_TRY_ADD_TO_CONTEXT(addBranch(data, condition, m_expressionStack)); 447 return { }; 527 448 } 528 449 529 450 case OpType::BrTable: { 530 451 uint32_t numberOfTargets; 531 if (!parseVarUInt32(numberOfTargets)) 532 return false; 452 ExpressionType condition; 453 uint32_t defaultTarget; 454 WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table"); 455 WASM_PARSER_FAIL_IF(numberOfTargets == std::numeric_limits<uint32_t>::max(), "br_table's number of targets is too big ", numberOfTargets); 533 456 534 457 Vector<ControlType*> targets; 535 if (!targets.tryReserveCapacity(numberOfTargets)) 536 return false; 537 458 WASM_PARSER_FAIL_IF(!targets.tryReserveCapacity(numberOfTargets), "can't allocate memory for ", numberOfTargets, " br_table targets"); 538 459 for (uint32_t i = 0; i < numberOfTargets; ++i) { 539 460 uint32_t target; 540 if (!parseVarUInt32(target)) 541 return false; 542 543 if (target >= m_controlStack.size()) 544 return false; 545 461 WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get ", i, "th target for br_table"); 462 WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br_table's ", i, "th target ", target, " exceeds control stack size ", m_controlStack.size()); 546 463 targets.uncheckedAppend(&m_controlStack[m_controlStack.size() - 1 - target].controlData); 547 464 } 548 465 549 uint32_t defaultTarget; 550 if (!parseVarUInt32(defaultTarget)) 551 return false; 552 553 if (defaultTarget >= m_controlStack.size()) 554 return false; 555 556 ExpressionType condition; 557 if (!popExpressionStack(condition)) 558 return false; 559 560 if (!m_context.addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack)) 561 return false; 466 WASM_PARSER_FAIL_IF(!parseVarUInt32(defaultTarget), "can't get default target for br_table"); 467 WASM_PARSER_FAIL_IF(defaultTarget >= m_controlStack.size(), "br_table's default target ", defaultTarget, " exceeds control stack size ", m_controlStack.size()); 468 WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br_table condition"); 469 WASM_TRY_ADD_TO_CONTEXT(addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack)); 562 470 563 471 m_unreachableBlocks = 1; 564 return true;472 return { }; 565 473 } 566 474 … … 574 482 // That's a little too effectful for me but I don't have a better API right now. 575 483 // see: https://bugs.webkit.org/show_bug.cgi?id=164353 576 if (!m_context.endBlock(data, m_expressionStack)) 577 return false; 484 WASM_TRY_ADD_TO_CONTEXT(endBlock(data, m_expressionStack)); 578 485 m_expressionStack.swap(data.enclosedExpressionStack); 579 return true;486 return { }; 580 487 } 581 488 582 489 case OpType::Unreachable: { 583 m_context.addUnreachable();490 WASM_TRY_ADD_TO_CONTEXT(addUnreachable()); 584 491 m_unreachableBlocks = 1; 585 return true;492 return { }; 586 493 } 587 494 588 495 case OpType::Drop: { 589 if (!m_expressionStack.size()) { 590 setErrorMessage("Attempted to drop an expression from an empty stack."); 591 return false; 592 } 496 WASM_PARSER_FAIL_IF(!m_expressionStack.size(), "can't drop on empty stack"); 593 497 m_expressionStack.takeLast(); 594 return true;498 return { }; 595 499 } 596 500 597 501 case OpType::Nop: { 598 return true;502 return { }; 599 503 } 600 504 601 505 case OpType::GrowMemory: 506 return fail("not yet implemented: grow_memory"); // FIXME: Not yet implemented. 507 602 508 case OpType::CurrentMemory: 603 // FIXME: Not yet implemented.604 return false; 509 return fail("not yet implemented: current_memory"); // FIXME: Not yet implemented. 510 605 511 } 606 512 … … 609 515 610 516 template<typename Context> 611 bool FunctionParser<Context>::parseUnreachableExpression(OpType op) 517 auto FunctionParser<Context>::parseUnreachableExpression(OpType op) -> PartialResult 612 518 { 613 519 ASSERT(m_unreachableBlocks); … … 615 521 case OpType::Else: { 616 522 if (m_unreachableBlocks > 1) 617 return true;523 return { }; 618 524 619 525 ControlEntry& data = m_controlStack.last(); 620 526 m_unreachableBlocks = 0; 621 if (!m_context.addElseToUnreachable(data.controlData)) 622 return false; 527 WASM_TRY_ADD_TO_CONTEXT(addElseToUnreachable(data.controlData)); 623 528 m_expressionStack.shrink(0); 624 return true;529 return { }; 625 530 } 626 531 … … 628 533 if (m_unreachableBlocks == 1) { 629 534 ControlEntry data = m_controlStack.takeLast(); 630 if (!m_context.addEndToUnreachable(data)) 631 return false; 535 WASM_TRY_ADD_TO_CONTEXT(addEndToUnreachable(data)); 632 536 m_expressionStack.swap(data.enclosedExpressionStack); 633 537 } 634 538 m_unreachableBlocks--; 635 return true;539 return { }; 636 540 } 637 541 … … 640 544 case OpType::Block: { 641 545 m_unreachableBlocks++; 642 return true;546 return { }; 643 547 } 644 548 … … 647 551 case OpType::BrIf: { 648 552 uint32_t unused; 649 if (!parseVarUInt32(unused))650 return false;651 return parseVarUInt32(unused);553 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get br / br_if in unreachable context"); 554 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get br / br_if in unreachable context"); 555 return { }; 652 556 } 653 557 … … 660 564 case OpType::GetLocal: { 661 565 uint32_t unused; 662 return parseVarUInt32(unused); 566 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get const / local in unreachable context"); 567 return { }; 663 568 } 664 569 … … 666 571 break; 667 572 } 668 return true; 669 } 670 671 template<typename Context> 672 bool FunctionParser<Context>::popExpressionStack(ExpressionType& result) 673 { 674 if (m_expressionStack.size()) { 675 result = m_expressionStack.takeLast(); 676 return true; 677 } 678 679 setErrorMessage("Attempted to use a stack value when none existed"); 680 return false; 573 return { }; 681 574 } 682 575 -
trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp
r209874 r209880 40 40 namespace JSC { namespace Wasm { 41 41 42 static const bool verbose = false; 43 44 bool ModuleParser::parse() 45 { 46 m_module = std::make_unique<ModuleInformation>(); 47 42 auto ModuleParser::parse() -> Result 43 { 44 m_result.module = std::make_unique<ModuleInformation>(); 48 45 const size_t minSize = 8; 49 if (length() < minSize) {50 m_errorMessage = "Module is " + String::number(length()) + " bytes, expected at least " + String::number(minSize) + " bytes";51 return false;52 }53 if (!consumeCharacter(0) || !consumeString("asm")) {54 m_errorMessage = "Modules doesn't start with '\\0asm'";55 return false;56 }57 58 46 uint32_t versionNumber; 59 if (!parseUInt32(versionNumber)) { 60 // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919 61 m_errorMessage = "couldn't parse version number"; 62 return false; 63 } 64 65 if (versionNumber != expectedVersionNumber) { 66 // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919 67 m_errorMessage = "unexpected version number"; 68 return false; 69 } 70 71 72 if (verbose) 73 dataLogLn("Passed processing header."); 74 75 Sections::Section previousSection = Sections::Unknown; 47 48 WASM_PARSER_FAIL_IF(length() < minSize, "expected a module of at least ", minSize, " bytes"); 49 WASM_PARSER_FAIL_IF(!consumeCharacter(0) || !consumeString("asm"), "modules doesn't start with '\\0asm'"); 50 WASM_PARSER_FAIL_IF(!parseUInt32(versionNumber), "can't parse version number"); 51 WASM_PARSER_FAIL_IF(versionNumber != expectedVersionNumber, "unexpected version number ", versionNumber, " expected ", expectedVersionNumber); 52 53 Section previousSection = Section::Unknown; 76 54 while (m_offset < length()) { 77 if (verbose)78 dataLogLn("Starting to parse next section at offset: ", m_offset);79 80 55 uint8_t sectionByte; 81 if (!parseUInt7(sectionByte)) { 82 // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919 83 m_errorMessage = "couldn't get section byte"; 84 return false; 85 } 86 87 if (verbose) 88 dataLogLn("Section byte: ", sectionByte); 89 90 Sections::Section section = Sections::Unknown; 56 57 WASM_PARSER_FAIL_IF(!parseUInt7(sectionByte), "can't get section byte"); 58 59 Section section = Section::Unknown; 91 60 if (sectionByte) { 92 if (sectionByte < Sections::Unknown) 93 section = static_cast<Sections::Section>(sectionByte); 94 } 95 96 if (!Sections::validateOrder(previousSection, section)) { 97 // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919 98 m_errorMessage = "invalid section order"; 99 return false; 61 if (isValidSection(sectionByte)) 62 section = static_cast<Section>(sectionByte); 100 63 } 101 64 102 65 uint32_t sectionLength; 103 if (!parseVarUInt32(sectionLength)) { 104 // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919 105 m_errorMessage = "couldn't get section length"; 106 return false; 107 } 108 109 if (sectionLength > length() - m_offset) { 110 // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919 111 m_errorMessage = "section content would overflow Module's size"; 112 return false; 113 } 66 WASM_PARSER_FAIL_IF(!validateOrder(previousSection, section), "invalid section order, ", previousSection, " followed by ", section); 67 WASM_PARSER_FAIL_IF(!parseVarUInt32(sectionLength), "can't get ", section, " section's length"); 68 WASM_PARSER_FAIL_IF(sectionLength > length() - m_offset, section, "section of size ", sectionLength, " would overflow Module's size"); 114 69 115 70 auto end = m_offset + sectionLength; 116 71 117 72 switch (section) { 118 // FIXME improve error message in macro below https://bugs.webkit.org/show_bug.cgi?id=163919 119 #define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \ 120 case Sections::NAME: { \ 121 if (verbose) \ 122 dataLogLn("Parsing " DESCRIPTION); \ 123 if (!parse ## NAME()) { \ 124 m_errorMessage = "couldn't parse section " #NAME ": " DESCRIPTION; \ 125 return false; \ 126 } \ 127 break; \ 73 #define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \ 74 case Section::NAME: { \ 75 WASM_FAIL_IF_HELPER_FAILS(parse ## NAME()); \ 76 break; \ 128 77 } 129 78 FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE) 130 79 #undef WASM_SECTION_PARSE 131 80 132 case Sections::Unknown: { 133 if (verbose) 134 dataLogLn("Unknown section, skipping."); 81 case Section::Unknown: { 135 82 // Ignore section's name LEB and bytes: they're already included in sectionLength. 136 83 m_offset += sectionLength; … … 139 86 } 140 87 141 if (verbose) 142 dataLogLn("Finished parsing section."); 143 144 if (end != m_offset) { 145 // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919 146 m_errorMessage = "parsing ended before the end of the section"; 147 return false; 148 } 88 WASM_PARSER_FAIL_IF(end != m_offset, "parsing ended before the end of ", section, " section"); 149 89 150 90 previousSection = section; 151 91 } 152 92 153 // TODO 154 m_failed = false; 155 return true; 156 } 157 158 bool ModuleParser::parseType() 93 return WTFMove(m_result); 94 } 95 96 auto ModuleParser::parseType() -> PartialResult 159 97 { 160 98 uint32_t count; 161 if (!parseVarUInt32(count) 162 || count == std::numeric_limits<uint32_t>::max() 163 || !m_module->signatures.tryReserveCapacity(count)) 164 return false; 165 if (verbose) 166 dataLogLn(" count: ", count); 99 100 WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Type section's count"); 101 WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Type section's count is too big ", count); 102 WASM_PARSER_FAIL_IF(!m_result.module->signatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries"); 167 103 168 104 for (uint32_t i = 0; i < count; ++i) { 169 105 int8_t type; 170 if (!parseInt7(type))171 return false;172 if (type != Func)173 return false;174 175 if (verbose)176 dataLogLn("Got function type.");177 178 106 uint32_t argumentCount; 179 107 Vector<Type> argumentTypes; 180 if (!parseVarUInt32(argumentCount) 181 || argumentCount == std::numeric_limits<uint32_t>::max()182 || !argumentTypes.tryReserveCapacity(argumentCount))183 return false;184 if (verbose)185 dataLogLn(" argument count: ", argumentCount);108 109 WASM_PARSER_FAIL_IF(!parseInt7(type), "can't get ", i, "th Type's type"); 110 WASM_PARSER_FAIL_IF(type != Func, i, "th Type is non-Func ", type); 111 WASM_PARSER_FAIL_IF(!parseVarUInt32(argumentCount), "can't get ", i, "th Type's argument count"); 112 WASM_PARSER_FAIL_IF(argumentCount == std::numeric_limits<uint32_t>::max(), i, "th argument count is too big ", argumentCount); 113 WASM_PARSER_FAIL_IF(!argumentTypes.tryReserveCapacity(argumentCount), "can't allocate enough memory for Type section's ", i, "th ", argumentCount, " arguments"); 186 114 187 115 for (unsigned i = 0; i < argumentCount; ++i) { 188 116 Type argumentType; 189 if (!parseResultType(argumentType)) 190 return false; 117 WASM_PARSER_FAIL_IF(!parseResultType(argumentType), "can't get ", i, "th argument Type"); 191 118 argumentTypes.uncheckedAppend(argumentType); 192 119 } 193 120 194 121 uint8_t returnCount; 195 if (!parseVarUInt1(returnCount)) 196 return false; 122 WASM_PARSER_FAIL_IF(!parseVarUInt1(returnCount), "can't get ", i, "th Type's return count"); 197 123 Type returnType; 198 199 if (verbose)200 dataLogLn(returnCount);201 124 202 125 if (returnCount) { 203 126 Type value; 204 if (!parseValueType(value)) 205 return false; 127 WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value"); 206 128 returnType = static_cast<Type>(value); 207 129 } else 208 130 returnType = Type::Void; 209 131 210 m_ module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });211 } 212 return true;213 } 214 215 bool ModuleParser::parseImport() 132 m_result.module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) }); 133 } 134 return { }; 135 } 136 137 auto ModuleParser::parseImport() -> PartialResult 216 138 { 217 139 uint32_t importCount; 218 if (!parseVarUInt32(importCount) 219 || importCount == std::numeric_limits<uint32_t>::max() 220 || !m_module->globals.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below. 221 || !m_module->imports.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below. 222 || !m_module->importFunctions.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below. 223 || !m_functionIndexSpace.tryReserveCapacity(importCount)) // FIXME this over-allocates when we fix the FIXMEs below. We'll allocate some more here when we know how many functions to expect. 224 return false; 140 WASM_PARSER_FAIL_IF(!parseVarUInt32(importCount), "can't get Import section's count"); 141 WASM_PARSER_FAIL_IF(importCount == std::numeric_limits<uint32_t>::max(), "Import section's count is too big ", importCount); 142 WASM_PARSER_FAIL_IF(!m_result.module->globals.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " globals"); // FIXME this over-allocates when we fix the FIXMEs below. 143 WASM_PARSER_FAIL_IF(!m_result.module->imports.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " imports"); // FIXME this over-allocates when we fix the FIXMEs below. 144 WASM_PARSER_FAIL_IF(!m_result.module->importFunctions.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " import functions"); // FIXME this over-allocates when we fix the FIXMEs below. 145 WASM_PARSER_FAIL_IF(!m_result.functionIndexSpace.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " functions in the index space"); // FIXME this over-allocates when we fix the FIXMEs below. We'll allocate some more here when we know how many functions to expect. 225 146 226 147 for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) { … … 230 151 String moduleString; 231 152 String fieldString; 232 if (!parseVarUInt32(moduleLen) 233 || !consumeUTF8String(moduleString, moduleLen))234 return false;153 154 WASM_PARSER_FAIL_IF(!parseVarUInt32(moduleLen), "can't get ", importNumber, "th Import's module name length"); 155 WASM_PARSER_FAIL_IF(!consumeUTF8String(moduleString, moduleLen), "can't get ", importNumber, "th Import's module name of length ", moduleLen); 235 156 imp.module = Identifier::fromString(m_vm, moduleString); 236 if (!parseVarUInt32(fieldLen) 237 || !consumeUTF8String(fieldString, fieldLen))238 return false;157 158 WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", importNumber, "th Import's field name length in module '", moduleString, "'"); 159 WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", importNumber, "th Import's field name of length ", moduleLen, " in module '", moduleString, "'"); 239 160 imp.field = Identifier::fromString(m_vm, fieldString); 240 if (!parseExternalKind(imp.kind)) 241 return false;161 162 WASM_PARSER_FAIL_IF(!parseExternalKind(imp.kind), "can't get ", importNumber, "th Import's kind in module '", moduleString, "' field '", fieldString, "'"); 242 163 switch (imp.kind) { 243 case External ::Function: {164 case ExternalKind::Function: { 244 165 uint32_t functionSignatureIndex; 245 if (!parseVarUInt32(functionSignatureIndex) 246 || functionSignatureIndex >= m_module->signatures.size()) 247 return false; 248 imp.kindIndex = m_module->importFunctions.size(); 249 Signature* signature = &m_module->signatures[functionSignatureIndex]; 250 m_module->importFunctions.uncheckedAppend(signature); 251 m_functionIndexSpace.uncheckedAppend(signature); 252 break; 253 } 254 case External::Table: { 166 WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSignatureIndex), "can't get ", importNumber, "th Import's function signature in module '", moduleString, "' field '", fieldString, "'"); 167 WASM_PARSER_FAIL_IF(functionSignatureIndex >= m_result.module->signatures.size(), "invalid function signature for ", importNumber, "th Import, ", functionSignatureIndex, " is out of range of ", m_result.module->signatures.size(), " in module '", moduleString, "' field '", fieldString, "'"); 168 imp.kindIndex = m_result.module->importFunctions.size(); 169 Signature* signature = &m_result.module->signatures[functionSignatureIndex]; 170 m_result.module->importFunctions.uncheckedAppend(signature); 171 m_result.functionIndexSpace.uncheckedAppend(signature); 172 break; 173 } 174 case ExternalKind::Table: { 255 175 bool isImport = true; 256 if (!parseTableHelper(isImport)) 257 return false; 258 break; 259 } 260 case External::Memory: { 176 PartialResult result = parseTableHelper(isImport); 177 if (UNLIKELY(!result)) 178 return result.getUnexpected(); 179 break; 180 } 181 case ExternalKind::Memory: { 261 182 bool isImport = true; 262 if (!parseMemoryHelper(isImport)) 263 return false; 264 break; 265 } 266 case External::Global: { 183 PartialResult result = parseMemoryHelper(isImport); 184 if (UNLIKELY(!result)) 185 return result.getUnexpected(); 186 break; 187 } 188 case ExternalKind::Global: { 267 189 Global global; 268 if (!parseGlobalType(global)) 269 return false; 270 271 if (global.mutability == Global::Mutable) 272 return false; 273 274 imp.kindIndex = m_module->globals.size(); 275 m_module->globals.uncheckedAppend(WTFMove(global)); 276 break; 277 } 278 } 279 280 m_module->imports.uncheckedAppend(imp); 281 } 282 283 m_module->firstInternalGlobal = m_module->globals.size(); 284 return true; 285 } 286 287 bool ModuleParser::parseFunction() 190 WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global)); 191 WASM_PARSER_FAIL_IF(global.mutability == Global::Mutable, "Mutable Globals aren't supported"); 192 193 imp.kindIndex = m_result.module->globals.size(); 194 m_result.module->globals.uncheckedAppend(WTFMove(global)); 195 break; 196 } 197 } 198 199 m_result.module->imports.uncheckedAppend(imp); 200 } 201 202 m_result.module->firstInternalGlobal = m_result.module->globals.size(); 203 return { }; 204 } 205 206 auto ModuleParser::parseFunction() -> PartialResult 288 207 { 289 208 uint32_t count; 290 if (!parseVarUInt32(count) 291 || count == std::numeric_limits<uint32_t>::max() 292 || !m_module->internalFunctionSignatures.tryReserveCapacity(count) 293 || !m_functionLocationInBinary.tryReserveCapacity(count) 294 || !m_functionIndexSpace.tryReserveCapacity(m_functionIndexSpace.size() + count)) 295 return false; 209 WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Function section's count"); 210 WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Function section's count is too big ", count); 211 WASM_PARSER_FAIL_IF(!m_result.module->internalFunctionSignatures.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures"); 212 WASM_PARSER_FAIL_IF(!m_result.functionLocationInBinary.tryReserveCapacity(count), "can't allocate enough memory for ", count, "Function locations"); 213 WASM_PARSER_FAIL_IF(!m_result.functionIndexSpace.tryReserveCapacity(m_result.functionIndexSpace.size() + count), "can't allocate enough memory for ", count, " more functions in the function index space"); 296 214 297 215 for (uint32_t i = 0; i < count; ++i) { 298 216 uint32_t typeNumber; 299 if (!parseVarUInt32(typeNumber) 300 || typeNumber >= m_module->signatures.size()) 301 return false; 302 303 Signature* signature = &m_module->signatures[typeNumber]; 217 WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", i, "th Function's type number"); 218 WASM_PARSER_FAIL_IF(typeNumber >= m_result.module->signatures.size(), i, "th Function type number is invalid ", typeNumber); 219 220 Signature* signature = &m_result.module->signatures[typeNumber]; 304 221 // The Code section fixes up start and end. 305 222 size_t start = 0; 306 223 size_t end = 0; 307 m_ module->internalFunctionSignatures.uncheckedAppend(signature);308 m_ functionLocationInBinary.uncheckedAppend({ start, end });309 m_ functionIndexSpace.uncheckedAppend(signature);310 } 311 312 return true;313 } 314 315 bool ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum) 224 m_result.module->internalFunctionSignatures.uncheckedAppend(signature); 225 m_result.functionLocationInBinary.uncheckedAppend({ start, end }); 226 m_result.functionIndexSpace.uncheckedAppend(signature); 227 } 228 229 return { }; 230 } 231 232 auto ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum) -> PartialResult 316 233 { 317 234 ASSERT(!maximum); 318 235 319 236 uint8_t flags; 320 if (!parseVarUInt1(flags)) 321 return false; 322 323 if (!parseVarUInt32(initial)) 324 return false; 237 WASM_PARSER_FAIL_IF(!parseVarUInt1(flags), "can't parse resizable limits flags"); 238 WASM_PARSER_FAIL_IF(!parseVarUInt32(initial), "can't parse resizable limits initial page count"); 325 239 326 240 if (flags) { 327 241 uint32_t maximumInt; 328 if (!parseVarUInt32(maximumInt)) 329 return false; 330 331 if (initial > maximumInt) 332 return false; 333 242 WASM_PARSER_FAIL_IF(!parseVarUInt32(maximumInt), "can't parse resizable limits maximum page count"); 243 WASM_PARSER_FAIL_IF(initial > maximumInt, "resizable limits has a initial page count of ", initial, " which is greater than its maximum ", maximumInt); 334 244 maximum = maximumInt; 335 245 } 336 246 337 return true; 338 } 339 340 bool ModuleParser::parseTableHelper(bool isImport) 341 { 342 // We're only allowed a total of one Table import or definition. 343 if (m_hasTable) 344 return false; 247 return { }; 248 } 249 250 auto ModuleParser::parseTableHelper(bool isImport) -> PartialResult 251 { 252 WASM_PARSER_FAIL_IF(m_hasTable, "Table section cannot exist if an Import has a table"); 345 253 346 254 m_hasTable = true; 347 255 348 256 int8_t type; 349 if (!parseInt7(type)) 350 return false; 351 if (type != Wasm::Anyfunc) 352 return false; 257 WASM_PARSER_FAIL_IF(!parseInt7(type), "can't parse Table type"); 258 WASM_PARSER_FAIL_IF(type != Wasm::Anyfunc, "Table type should be anyfunc, got ", type); 353 259 354 260 uint32_t initial; 355 261 std::optional<uint32_t> maximum; 356 if (!parseResizableLimits(initial, maximum)) 357 return false; 358 359 if (!JSWebAssemblyTable::isValidSize(initial)) 360 return false; 262 PartialResult limits = parseResizableLimits(initial, maximum); 263 if (UNLIKELY(!limits)) 264 return limits.getUnexpected(); 265 WASM_PARSER_FAIL_IF(!JSWebAssemblyTable::isValidSize(initial), "Table's initial page count of ", initial, " is invalid"); 361 266 362 267 ASSERT(!maximum || *maximum >= initial); 363 268 364 m_ module->tableInformation = TableInformation(initial, maximum, isImport);365 366 return true;367 } 368 369 bool ModuleParser::parseTable() 269 m_result.module->tableInformation = TableInformation(initial, maximum, isImport); 270 271 return { }; 272 } 273 274 auto ModuleParser::parseTable() -> PartialResult 370 275 { 371 276 uint32_t count; 372 if (!parseVarUInt32(count)) 373 return false; 374 375 // We only allow one table for now. 376 if (count != 1) 377 return false; 277 WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Table's count"); 278 WASM_PARSER_FAIL_IF(count != 1, "Table count of ", count, " is invalid, only 1 is allowed for now"); 378 279 379 280 bool isImport = false; 380 return parseTableHelper(isImport); 381 } 382 383 bool ModuleParser::parseMemoryHelper(bool isImport) 384 { 385 // We don't allow redeclaring memory. Either via import or definition. 386 if (m_module->memory) 387 return false; 281 PartialResult result = parseTableHelper(isImport); 282 if (UNLIKELY(!result)) 283 return result.getUnexpected(); 284 285 return { }; 286 } 287 288 auto ModuleParser::parseMemoryHelper(bool isImport) -> PartialResult 289 { 290 WASM_PARSER_FAIL_IF(m_result.module->memory, "Memory section cannot exist if an Import has a memory"); 388 291 389 292 PageCount initialPageCount; … … 392 295 uint32_t initial; 393 296 std::optional<uint32_t> maximum; 394 if (!parseResizableLimits(initial, maximum)) 395 return false; 297 PartialResult limits = parseResizableLimits(initial, maximum); 298 if (UNLIKELY(!limits)) 299 return limits.getUnexpected(); 396 300 ASSERT(!maximum || *maximum >= initial); 397 if (!PageCount::isValid(initial)) 398 return false; 301 WASM_PARSER_FAIL_IF(!PageCount::isValid(initial), "Memory's initial page count of ", initial, " is invalid"); 399 302 400 303 initialPageCount = PageCount(initial); 401 304 402 305 if (maximum) { 403 if (!PageCount::isValid(*maximum)) 404 return false; 306 WASM_PARSER_FAIL_IF(!PageCount::isValid(*maximum), "Memory's maximum page count of ", *maximum, " is invalid"); 405 307 maximumPageCount = PageCount(*maximum); 406 308 } … … 410 312 411 313 Vector<unsigned> pinnedSizes = { 0 }; 412 m_ module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport);413 return true;414 } 415 416 bool ModuleParser::parseMemory() 314 m_result.module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport); 315 return { }; 316 } 317 318 auto ModuleParser::parseMemory() -> PartialResult 417 319 { 418 320 uint8_t count; 419 if (!parseVarUInt1(count)) 420 return false; 321 WASM_PARSER_FAIL_IF(!parseVarUInt1(count), "can't parse Memory section's count"); 421 322 422 323 if (!count) 423 return true; 424 425 // We only allow one memory for now. 426 if (count != 1) 427 return false; 324 return { }; 325 326 WASM_PARSER_FAIL_IF(count != 1, "Memory section has more than one memory, WebAssembly currently only allows zero or one"); 428 327 429 328 bool isImport = false; … … 431 330 } 432 331 433 bool ModuleParser::parseGlobal() 332 auto ModuleParser::parseGlobal() -> PartialResult 434 333 { 435 334 uint32_t globalCount; 436 if (!parseVarUInt32(globalCount)) 437 return false; 438 if (!m_module->globals.tryReserveCapacity(globalCount + m_module->firstInternalGlobal)) 439 return false; 335 WASM_PARSER_FAIL_IF(!parseVarUInt32(globalCount), "can't get Global section's count"); 336 WASM_PARSER_FAIL_IF(!m_result.module->globals.tryReserveCapacity(globalCount + m_result.module->firstInternalGlobal), "can't allocate memory for ", globalCount + m_result.module->firstInternalGlobal, " globals"); 440 337 441 338 for (uint32_t globalIndex = 0; globalIndex < globalCount; ++globalIndex) { 442 339 Global global; 443 if (!parseGlobalType(global))444 return false;445 446 340 uint8_t initOpcode; 447 if (!parseInitExpr(initOpcode, global.initialBitsOrImportNumber)) 448 return false; 341 342 WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global)); 343 WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber)); 449 344 450 345 global.initializationType = Global::FromExpression; … … 464 359 break; 465 360 case GetGlobal: 466 if (global.initialBitsOrImportNumber >= m_module->firstInternalGlobal) 467 return false; 468 typeForInitOpcode = m_module->globals[global.initialBitsOrImportNumber].type; 361 WASM_PARSER_FAIL_IF(global.initialBitsOrImportNumber >= m_result.module->firstInternalGlobal, globalIndex, "th Global uses get_global ", global.initialBitsOrImportNumber, " which exceeds the first internal global ", m_result.module->firstInternalGlobal); 362 typeForInitOpcode = m_result.module->globals[global.initialBitsOrImportNumber].type; 469 363 global.initializationType = Global::FromGlobalImport; 470 364 break; … … 473 367 } 474 368 475 if (typeForInitOpcode != global.type) 476 return false; 477 478 m_module->globals.uncheckedAppend(WTFMove(global)); 479 } 480 481 return true; 482 } 483 484 bool ModuleParser::parseExport() 369 WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type); 370 371 m_result.module->globals.uncheckedAppend(WTFMove(global)); 372 } 373 374 return { }; 375 } 376 377 auto ModuleParser::parseExport() -> PartialResult 485 378 { 486 379 uint32_t exportCount; 487 if (!parseVarUInt32(exportCount) 488 || exportCount == std::numeric_limits<uint32_t>::max() 489 || !m_module->exports.tryReserveCapacity(exportCount)) 490 return false; 380 WASM_PARSER_FAIL_IF(!parseVarUInt32(exportCount), "can't get Export section's count"); 381 WASM_PARSER_FAIL_IF(exportCount == std::numeric_limits<uint32_t>::max(), "Export section's count is too big ", exportCount); 382 WASM_PARSER_FAIL_IF(!m_result.module->exports.tryReserveCapacity(exportCount), "can't allocate enough memory for ", exportCount, " exports"); 491 383 492 384 for (uint32_t exportNumber = 0; exportNumber < exportCount; ++exportNumber) { … … 494 386 uint32_t fieldLen; 495 387 String fieldString; 496 if (!parseVarUInt32(fieldLen) 497 || !consumeUTF8String(fieldString, fieldLen))498 return false;388 389 WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", exportNumber, "th Export's field name length"); 390 WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", exportNumber, "th Export's field name of length ", fieldLen); 499 391 exp.field = Identifier::fromString(m_vm, fieldString); 500 392 501 if (!parseExternalKind(exp.kind)) 502 return false; 503 504 if (!parseVarUInt32(exp.kindIndex)) 505 return false; 506 393 WASM_PARSER_FAIL_IF(!parseExternalKind(exp.kind), "can't get ", exportNumber, "th Export's kind, named '", fieldString, "'"); 394 WASM_PARSER_FAIL_IF(!parseVarUInt32(exp.kindIndex), "can't get ", exportNumber, "th Export's kind index, named '", fieldString, "'"); 507 395 switch (exp.kind) { 508 case External::Function: { 509 if (exp.kindIndex >= m_functionIndexSpace.size()) 510 return false; 511 break; 512 } 513 case External::Table: { 514 if (!m_hasTable) 515 return false; 516 if (exp.kindIndex != 0) 517 return false; 518 break; 519 } 520 case External::Memory: { 521 if (!m_module->memory) 522 return false; 523 if (exp.kindIndex != 0) 524 return false; 525 break; 526 } 527 case External::Global: { 528 if (exp.kindIndex >= m_module->globals.size()) 529 return false; 530 531 if (m_module->globals[exp.kindIndex].mutability != Global::Immutable) 532 return false; 533 break; 534 } 535 } 536 537 m_module->exports.uncheckedAppend(exp); 538 } 539 540 return true; 541 } 542 543 bool ModuleParser::parseStart() 396 case ExternalKind::Function: { 397 WASM_PARSER_FAIL_IF(exp.kindIndex >= m_result.functionIndexSpace.size(), exportNumber, "th Export has invalid function number ", exp.kindIndex, " it exceeds the function index space ", m_result.functionIndexSpace.size(), ", named '", fieldString, "'"); 398 break; 399 } 400 case ExternalKind::Table: { 401 WASM_PARSER_FAIL_IF(!m_hasTable, "can't export a non-existent Table"); 402 WASM_PARSER_FAIL_IF(exp.kindIndex, "can't export Table ", exp.kindIndex, " only zero-index Table is currently supported"); 403 break; 404 } 405 case ExternalKind::Memory: { 406 WASM_PARSER_FAIL_IF(!m_result.module->memory, "can't export a non-existent Memory"); 407 WASM_PARSER_FAIL_IF(exp.kindIndex, "can't export Memory ", exp.kindIndex, " only one Table is currently supported"); 408 break; 409 } 410 case ExternalKind::Global: { 411 WASM_PARSER_FAIL_IF(exp.kindIndex >= m_result.module->globals.size(), exportNumber, "th Export has invalid global number ", exp.kindIndex, " it exceeds the globals count ", m_result.module->globals.size(), ", named '", fieldString, "'"); 412 WASM_PARSER_FAIL_IF(m_result.module->globals[exp.kindIndex].mutability != Global::Immutable, exportNumber, "th Export isn't immutable, named '", fieldString, "'"); 413 break; 414 } 415 } 416 417 m_result.module->exports.uncheckedAppend(exp); 418 } 419 420 return { }; 421 } 422 423 auto ModuleParser::parseStart() -> PartialResult 544 424 { 545 425 uint32_t startFunctionIndex; 546 if (!parseVarUInt32(startFunctionIndex) 547 || startFunctionIndex >= m_functionIndexSpace.size()) 548 return false; 549 Signature* signature = m_functionIndexSpace[startFunctionIndex].signature; 550 if (signature->arguments.size() != 0 551 || signature->returnType != Void) 552 return false; 553 m_module->startFunctionIndexSpace = startFunctionIndex; 554 return true; 555 } 556 557 bool ModuleParser::parseElement() 558 { 559 if (!m_hasTable) 560 return false; 426 WASM_PARSER_FAIL_IF(!parseVarUInt32(startFunctionIndex), "can't get Start index"); 427 WASM_PARSER_FAIL_IF(startFunctionIndex >= m_result.functionIndexSpace.size(), "Start index ", startFunctionIndex, " exceeds function index space ", m_result.functionIndexSpace.size()); 428 Signature* signature = m_result.functionIndexSpace[startFunctionIndex].signature; 429 WASM_PARSER_FAIL_IF(!signature->arguments.isEmpty(), "Start function can't have arguments"); 430 WASM_PARSER_FAIL_IF(signature->returnType != Void, "Start function can't return a value"); 431 m_result.module->startFunctionIndexSpace = startFunctionIndex; 432 return { }; 433 } 434 435 auto ModuleParser::parseElement() -> PartialResult 436 { 437 WASM_PARSER_FAIL_IF(!m_hasTable, "Element section expects a Table to be present"); 561 438 562 439 uint32_t elementCount; 563 if (!parseVarUInt32(elementCount)) 564 return false; 565 if (!m_module->elements.tryReserveCapacity(elementCount)) 566 return false; 567 568 for (unsigned i = 0; i < elementCount; ++i) { 440 WASM_PARSER_FAIL_IF(!parseVarUInt32(elementCount), "can't get Element section's count"); 441 WASM_PARSER_FAIL_IF(elementCount == std::numeric_limits<uint32_t>::max(), "Element section's count is too big ", elementCount); 442 WASM_PARSER_FAIL_IF(!m_result.module->elements.tryReserveCapacity(elementCount), "can't allocate memory for ", elementCount, " Elements"); 443 for (unsigned elementNum = 0; elementNum < elementCount; ++elementNum) { 569 444 uint32_t tableIndex; 570 if (!parseVarUInt32(tableIndex))571 return false;572 // We only support one table for now.573 if (tableIndex != 0)574 return false;575 576 445 uint64_t offset; 577 446 uint8_t initOpcode; 578 if (!parseInitExpr(initOpcode, offset))579 return false;580 581 if (initOpcode != OpType::I32Const)582 return false;583 584 447 uint32_t indexCount; 585 if (!parseVarUInt32(indexCount)) 586 return false; 587 588 ASSERT(!!m_module->tableInformation); 589 if (std::optional<uint32_t> maximum = m_module->tableInformation.maximum()) { 448 449 WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index"); 450 WASM_PARSER_FAIL_IF(tableIndex, "Element section can only have one Table for now"); 451 WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset)); 452 WASM_PARSER_FAIL_IF(initOpcode != OpType::I32Const, "Element section doesn't support non-i32 init_expr opcode for now, got ", initOpcode); 453 WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section"); 454 WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount); 455 456 ASSERT(!!m_result.module->tableInformation); 457 if (std::optional<uint32_t> maximum = m_result.module->tableInformation.maximum()) { 590 458 // FIXME: should indexCount being zero be a validation error? 591 459 // https://bugs.webkit.org/show_bug.cgi?id=165826 … … 595 463 // https://bugs.webkit.org/show_bug.cgi?id=165827 596 464 uint64_t lastWrittenIndex = static_cast<uint64_t>(indexCount) + static_cast<uint64_t>(offset) - 1; 597 if (lastWrittenIndex >= static_cast<uint64_t>(*maximum)) 598 return false; 465 WASM_PARSER_FAIL_IF(lastWrittenIndex >= static_cast<uint64_t>(*maximum), "Element section's ", elementNum, "th element writes to index ", lastWrittenIndex, " which exceeds the maximum ", *maximum); 599 466 } 600 467 } 601 468 602 469 Element element; 603 if (!element.functionIndices.tryReserveCapacity(indexCount)) 604 return false; 470 WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices"); 605 471 606 472 element.offset = offset; 607 473 608 for (unsigned i = 0; i < indexCount; ++i) {474 for (unsigned index = 0; index < indexCount; ++index) { 609 475 uint32_t functionIndex; 610 if (!parseVarUInt32(functionIndex)) 611 return false; 612 613 if (functionIndex >= m_functionIndexSpace.size()) 614 return false; 476 WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index"); 477 WASM_PARSER_FAIL_IF(functionIndex >= m_result.functionIndexSpace.size(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_result.functionIndexSpace.size()); 615 478 616 479 element.functionIndices.uncheckedAppend(functionIndex); 617 480 } 618 481 619 m_ module->elements.uncheckedAppend(WTFMove(element));620 } 621 622 return true;623 } 624 625 bool ModuleParser::parseCode() 482 m_result.module->elements.uncheckedAppend(WTFMove(element)); 483 } 484 485 return { }; 486 } 487 488 auto ModuleParser::parseCode() -> PartialResult 626 489 { 627 490 uint32_t count; 628 if (!parseVarUInt32(count) 629 || count == std::numeric_limits<uint32_t>::max() 630 || count != m_functionLocationInBinary.size()) 631 return false; 491 WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Code section's count"); 492 WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", count); 493 WASM_PARSER_FAIL_IF(count != m_result.functionLocationInBinary.size(), "Code section count ", count, " exceeds the declared number of functions ", m_result.functionLocationInBinary.size()); 632 494 633 495 for (uint32_t i = 0; i < count; ++i) { 634 496 uint32_t functionSize; 635 if (!parseVarUInt32(functionSize) 636 || functionSize > length() 637 || functionSize > length() - m_offset) 638 return false; 639 640 m_functionLocationInBinary[i].start = m_offset; 641 m_functionLocationInBinary[i].end = m_offset + functionSize; 642 m_offset = m_functionLocationInBinary[i].end; 643 } 644 645 return true; 646 } 647 648 bool ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber) 649 { 650 if (!parseUInt8(opcode)) 651 return false; 497 WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSize), "can't get ", i, "th Code function's size"); 498 WASM_PARSER_FAIL_IF(functionSize > length(), "Code function's size ", functionSize, " exceeds the module's size ", length()); 499 WASM_PARSER_FAIL_IF(functionSize > length() - m_offset, "Code function's size ", functionSize, " exceeds the module's remaining size", length() - m_offset); 500 501 m_result.functionLocationInBinary[i].start = m_offset; 502 m_result.functionLocationInBinary[i].end = m_offset + functionSize; 503 m_offset = m_result.functionLocationInBinary[i].end; 504 } 505 506 return { }; 507 } 508 509 auto ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber) -> PartialResult 510 { 511 WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get init_expr's opcode"); 652 512 653 513 switch (opcode) { 654 514 case I32Const: { 655 515 int32_t constant; 656 if (!parseVarInt32(constant)) 657 return false; 516 WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't get constant value for init_expr's i32.const"); 658 517 bitsOrImportNumber = static_cast<uint64_t>(constant); 659 518 break; … … 662 521 case I64Const: { 663 522 int64_t constant; 664 if (!parseVarInt64(constant)) 665 return false; 523 WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't get constant value for init_expr's i64.const"); 666 524 bitsOrImportNumber = constant; 667 525 break; … … 670 528 case F32Const: { 671 529 uint32_t constant; 672 if (!parseUInt32(constant)) 673 return false; 530 WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't get constant value for init_expr's f32.const"); 674 531 bitsOrImportNumber = constant; 675 532 break; … … 678 535 case F64Const: { 679 536 uint64_t constant; 680 if (!parseUInt64(constant)) 681 return false; 537 WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't get constant value for init_expr's f64.const"); 682 538 bitsOrImportNumber = constant; 683 539 break; … … 686 542 case GetGlobal: { 687 543 uint32_t index; 688 if (!parseVarUInt32(index)) 689 return false; 690 691 if (index >= m_module->imports.size()) 692 return false; 693 const Import& import = m_module->imports[index]; 694 if (m_module->imports[index].kind != External::Global 695 || import.kindIndex >= m_module->firstInternalGlobal) 696 return false; 697 698 ASSERT(m_module->globals[import.kindIndex].mutability == Global::Immutable); 544 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index"); 545 WASM_PARSER_FAIL_IF(index >= m_result.module->imports.size(), "get_global's index ", index, " exceeds the number of imports ", m_result.module->imports.size()); 546 const Import& import = m_result.module->imports[index]; 547 WASM_PARSER_FAIL_IF(m_result.module->imports[index].kind != ExternalKind::Global, "get_global's import kind is ", m_result.module->imports[index].kind, " should be global"); 548 WASM_PARSER_FAIL_IF(import.kindIndex >= m_result.module->firstInternalGlobal, "get_global import kind index ", import.kindIndex, " exceeds the first internal global ", m_result.module->firstInternalGlobal); 549 550 ASSERT(m_result.module->globals[import.kindIndex].mutability == Global::Immutable); 699 551 700 552 bitsOrImportNumber = index; … … 703 555 704 556 default: 705 return false;557 WASM_PARSER_FAIL_IF(false, "unknown init_expr opcode ", opcode); 706 558 } 707 559 708 560 uint8_t endOpcode; 709 if (!parseUInt8(endOpcode) || endOpcode != OpType::End)710 return false;711 712 return true;713 } 714 715 bool ModuleParser::parseGlobalType(Global& global) 561 WASM_PARSER_FAIL_IF(!parseUInt8(endOpcode), "can't get init_expr's end opcode"); 562 WASM_PARSER_FAIL_IF(endOpcode != OpType::End, "init_expr should end with end, ended with ", endOpcode); 563 564 return { }; 565 } 566 567 auto ModuleParser::parseGlobalType(Global& global) -> PartialResult 716 568 { 717 569 uint8_t mutability; 718 if (!parseValueType(global.type) || !parseVarUInt1(mutability))719 return false;570 WASM_PARSER_FAIL_IF(!parseValueType(global.type), "can't get Global's value type"); 571 WASM_PARSER_FAIL_IF(!parseVarUInt1(mutability), "can't get Global type's mutability"); 720 572 global.mutability = static_cast<Global::Mutability>(mutability); 721 return true;722 } 723 724 bool ModuleParser::parseData() 573 return { }; 574 } 575 576 auto ModuleParser::parseData() -> PartialResult 725 577 { 726 578 uint32_t segmentCount; 727 if (!m_module->memory) 728 return false; 729 if (!parseVarUInt32(segmentCount) 730 || segmentCount == std::numeric_limits<uint32_t>::max() 731 || !m_module->data.tryReserveCapacity(segmentCount)) 732 return false; 733 if (verbose) 734 dataLogLn(" segments: ", segmentCount); 579 WASM_PARSER_FAIL_IF(!m_result.module->memory, "Data section cannot exist without a Memory section or Import"); 580 WASM_PARSER_FAIL_IF(!parseVarUInt32(segmentCount), "can't get Data section's count"); 581 WASM_PARSER_FAIL_IF(segmentCount == std::numeric_limits<uint32_t>::max(), "Data section's count is too big ", segmentCount); 582 WASM_PARSER_FAIL_IF(!m_result.module->data.tryReserveCapacity(segmentCount), "can't allocate enough memory for Data section's ", segmentCount, " segments"); 735 583 736 584 for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) { 737 if (verbose)738 dataLogLn(" segment #", segmentNumber);739 585 uint32_t index; 740 586 uint64_t offset; 741 587 uint8_t initOpcode; 742 588 uint32_t dataByteLength; 743 if (!parseVarUInt32(index) 744 || index) 745 return false; 746 747 if (!parseInitExpr(initOpcode, offset)) 748 return false; 749 750 if (initOpcode != OpType::I32Const) 751 return false; 752 753 if (verbose) 754 dataLogLn(" offset: ", offset); 755 756 if (!parseVarUInt32(dataByteLength) 757 || dataByteLength == std::numeric_limits<uint32_t>::max()) 758 return false; 759 if (verbose) 760 dataLogLn(" data bytes: ", dataByteLength); 589 590 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ", segmentNumber, "th Data segment's index"); 591 WASM_PARSER_FAIL_IF(index, segmentNumber, "th Data segment has non-zero index ", index); 592 WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset)); 593 WASM_PARSER_FAIL_IF(initOpcode != OpType::I32Const, segmentNumber, "th Data segment has opcode ", initOpcode, " expected i32.const"); 594 WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length"); 595 WASM_PARSER_FAIL_IF(dataByteLength == std::numeric_limits<uint32_t>::max(), segmentNumber, "th Data segment's data byte length is too big ", dataByteLength); 761 596 762 597 Segment* segment = Segment::make(offset, dataByteLength); 763 if (!segment) 764 return false; 765 m_module->data.uncheckedAppend(Segment::makePtr(segment)); 598 WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength); 599 m_result.module->data.uncheckedAppend(Segment::makePtr(segment)); 766 600 for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) { 767 601 uint8_t byte; 768 if (!parseUInt8(byte)) 769 return false; 602 WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment"); 770 603 segment->byte(dataByte) = byte; 771 if (verbose) 772 dataLogLn(" [", dataByte, "] = ", segment->byte(dataByte)); 773 } 774 } 775 return true; 604 } 605 } 606 return { }; 776 607 } 777 608 -
trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h
r209830 r209880 35 35 namespace JSC { namespace Wasm { 36 36 37 class ModuleParser : public Parser { 37 struct ModuleParserResult { 38 std::unique_ptr<ModuleInformation> module; 39 FunctionIndexSpace functionIndexSpace; 40 Vector<FunctionLocationInBinary> functionLocationInBinary; 41 }; 42 43 class ModuleParser : public Parser<ModuleParserResult> { 38 44 public: 39 45 … … 48 54 } 49 55 50 bool WARN_UNUSED_RETURN parse(); 51 bool WARN_UNUSED_RETURN failed() const { return m_failed; } 52 const String& errorMessage() const 53 { 54 RELEASE_ASSERT(failed()); 55 return m_errorMessage; 56 } 57 58 std::unique_ptr<ModuleInformation>& moduleInformation() 59 { 60 RELEASE_ASSERT(!failed()); 61 return m_module; 62 } 63 64 FunctionIndexSpace& functionIndexSpace() 65 { 66 RELEASE_ASSERT(!failed()); 67 return m_functionIndexSpace; 68 } 69 70 Vector<FunctionLocationInBinary>& functionLocationInBinary() 71 { 72 RELEASE_ASSERT(!failed()); 73 return m_functionLocationInBinary; 74 } 56 Result WARN_UNUSED_RETURN parse(); 75 57 76 58 private: 77 bool parseGlobalType(Global&);78 59 79 #define WASM_SECTION_DECLARE_PARSER(NAME, ID, DESCRIPTION) boolWARN_UNUSED_RETURN parse ## NAME();60 #define WASM_SECTION_DECLARE_PARSER(NAME, ID, DESCRIPTION) PartialResult WARN_UNUSED_RETURN parse ## NAME(); 80 61 FOR_EACH_WASM_SECTION(WASM_SECTION_DECLARE_PARSER) 81 62 #undef WASM_SECTION_DECLARE_PARSER 82 63 83 bool WARN_UNUSED_RETURN parseMemoryHelper(bool isImport); 84 bool WARN_UNUSED_RETURN parseTableHelper(bool isImport); 85 bool WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum); 86 bool WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&); 64 PartialResult WARN_UNUSED_RETURN parseGlobalType(Global&); 65 PartialResult WARN_UNUSED_RETURN parseMemoryHelper(bool isImport); 66 PartialResult WARN_UNUSED_RETURN parseTableHelper(bool isImport); 67 PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum); 68 PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&); 87 69 88 70 VM* m_vm; 89 std::unique_ptr<ModuleInformation> m_module; 90 FunctionIndexSpace m_functionIndexSpace; 91 Vector<FunctionLocationInBinary> m_functionLocationInBinary; 92 bool m_failed { true }; 71 ModuleParserResult m_result; 93 72 bool m_hasTable { false }; 94 String m_errorMessage;95 73 }; 96 74 -
trunk/Source/JavaScriptCore/wasm/WasmParser.h
r209830 r209880 33 33 #include "WasmOps.h" 34 34 #include "WasmSections.h" 35 #include <type_traits> 36 #include <wtf/Expected.h> 35 37 #include <wtf/LEBDecoder.h> 36 38 #include <wtf/StdLibExtras.h> … … 39 41 namespace JSC { namespace Wasm { 40 42 43 namespace FailureHelper { 44 // FIXME We should move this to makeString. It's in its own namespace to enable C++ Argument Dependent Lookup à la std::swap: user code can deblare its own "boxFailure" and the fail() helper will find it. 45 static inline auto makeString(const char *failure) { return ASCIILiteral(failure); } 46 template <typename Int, typename = typename std::enable_if<std::is_integral<Int>::value>::type> 47 static inline auto makeString(Int failure) { return String::number(failure); } 48 } 49 50 template<typename SuccessType> 41 51 class Parser { 52 public: 53 typedef String ErrorType; 54 typedef UnexpectedType<ErrorType> UnexpectedResult; 55 typedef Expected<void, ErrorType> PartialResult; 56 typedef Expected<SuccessType, ErrorType> Result; 57 42 58 protected: 43 59 Parser(const uint8_t*, size_t); … … 61 77 bool WARN_UNUSED_RETURN parseResultType(Type&); 62 78 bool WARN_UNUSED_RETURN parseValueType(Type&); 63 bool WARN_UNUSED_RETURN parseExternalKind(External ::Kind&);79 bool WARN_UNUSED_RETURN parseExternalKind(ExternalKind&); 64 80 65 81 const uint8_t* source() const { return m_source; } … … 67 83 68 84 size_t m_offset = 0; 85 86 template <typename ...Args> 87 NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const 88 { 89 using namespace FailureHelper; // See ADL comment in namespace above. 90 return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module doesn't parse at byte "), String::number(m_offset), ASCIILiteral(" / "), String::number(m_sourceLength), ASCIILiteral(": "), makeString(args)...)); 91 } 92 #define WASM_PARSER_FAIL_IF(condition, ...) do { \ 93 if (UNLIKELY(condition)) \ 94 return fail(__VA_ARGS__); \ 95 } while (0) 96 97 #define WASM_FAIL_IF_HELPER_FAILS(helper) do { \ 98 auto helperResult = helper; \ 99 if (UNLIKELY(!helperResult)) \ 100 return helperResult.getUnexpected(); \ 101 } while (0) 69 102 70 103 private: … … 73 106 }; 74 107 75 ALWAYS_INLINE Parser::Parser(const uint8_t* sourceBuffer, size_t sourceLength) 108 template<typename SuccessType> 109 ALWAYS_INLINE Parser<SuccessType>::Parser(const uint8_t* sourceBuffer, size_t sourceLength) 76 110 : m_source(sourceBuffer) 77 111 , m_sourceLength(sourceLength) … … 79 113 } 80 114 81 ALWAYS_INLINE bool Parser::consumeCharacter(char c) 115 template<typename SuccessType> 116 ALWAYS_INLINE bool Parser<SuccessType>::consumeCharacter(char c) 82 117 { 83 118 if (m_offset >= length()) … … 90 125 } 91 126 92 ALWAYS_INLINE bool Parser::consumeString(const char* str) 127 template<typename SuccessType> 128 ALWAYS_INLINE bool Parser<SuccessType>::consumeString(const char* str) 93 129 { 94 130 unsigned start = m_offset; … … 104 140 } 105 141 106 ALWAYS_INLINE bool Parser::consumeUTF8String(String& result, size_t stringLength) 142 template<typename SuccessType> 143 ALWAYS_INLINE bool Parser<SuccessType>::consumeUTF8String(String& result, size_t stringLength) 107 144 { 108 145 if (stringLength == 0) { … … 119 156 } 120 157 121 ALWAYS_INLINE bool Parser::parseVarUInt32(uint32_t& result) 158 template<typename SuccessType> 159 ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt32(uint32_t& result) 122 160 { 123 161 return WTF::LEBDecoder::decodeUInt32(m_source, m_sourceLength, m_offset, result); 124 162 } 125 163 126 ALWAYS_INLINE bool Parser::parseVarUInt64(uint64_t& result) 164 template<typename SuccessType> 165 ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt64(uint64_t& result) 127 166 { 128 167 return WTF::LEBDecoder::decodeUInt64(m_source, m_sourceLength, m_offset, result); 129 168 } 130 169 131 ALWAYS_INLINE bool Parser::parseVarInt32(int32_t& result) 170 template<typename SuccessType> 171 ALWAYS_INLINE bool Parser<SuccessType>::parseVarInt32(int32_t& result) 132 172 { 133 173 return WTF::LEBDecoder::decodeInt32(m_source, m_sourceLength, m_offset, result); 134 174 } 135 175 136 ALWAYS_INLINE bool Parser::parseVarInt64(int64_t& result) 176 template<typename SuccessType> 177 ALWAYS_INLINE bool Parser<SuccessType>::parseVarInt64(int64_t& result) 137 178 { 138 179 return WTF::LEBDecoder::decodeInt64(m_source, m_sourceLength, m_offset, result); 139 180 } 140 181 141 ALWAYS_INLINE bool Parser::parseUInt32(uint32_t& result) 182 template<typename SuccessType> 183 ALWAYS_INLINE bool Parser<SuccessType>::parseUInt32(uint32_t& result) 142 184 { 143 185 if (length() < 4 || m_offset > length() - 4) … … 148 190 } 149 191 150 ALWAYS_INLINE bool Parser::parseUInt64(uint64_t& result) 192 template<typename SuccessType> 193 ALWAYS_INLINE bool Parser<SuccessType>::parseUInt64(uint64_t& result) 151 194 { 152 195 if (length() < 8 || m_offset > length() - 8) … … 157 200 } 158 201 159 ALWAYS_INLINE bool Parser::parseUInt8(uint8_t& result) 202 template<typename SuccessType> 203 ALWAYS_INLINE bool Parser<SuccessType>::parseUInt8(uint8_t& result) 160 204 { 161 205 if (m_offset >= length()) … … 165 209 } 166 210 167 ALWAYS_INLINE bool Parser::parseInt7(int8_t& result) 211 template<typename SuccessType> 212 ALWAYS_INLINE bool Parser<SuccessType>::parseInt7(int8_t& result) 168 213 { 169 214 if (m_offset >= length()) … … 174 219 } 175 220 176 ALWAYS_INLINE bool Parser::parseUInt7(uint8_t& result) 221 template<typename SuccessType> 222 ALWAYS_INLINE bool Parser<SuccessType>::parseUInt7(uint8_t& result) 177 223 { 178 224 if (m_offset >= length()) … … 182 228 } 183 229 184 ALWAYS_INLINE bool Parser::parseVarUInt1(uint8_t& result) 230 template<typename SuccessType> 231 ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt1(uint8_t& result) 185 232 { 186 233 uint32_t temp; … … 191 238 } 192 239 193 ALWAYS_INLINE bool Parser::parseResultType(Type& result) 240 template<typename SuccessType> 241 ALWAYS_INLINE bool Parser<SuccessType>::parseResultType(Type& result) 194 242 { 195 243 int8_t value; … … 202 250 } 203 251 204 ALWAYS_INLINE bool Parser::parseValueType(Type& result) 252 template<typename SuccessType> 253 ALWAYS_INLINE bool Parser<SuccessType>::parseValueType(Type& result) 205 254 { 206 255 return parseResultType(result) && isValueType(result); 207 256 } 208 209 ALWAYS_INLINE bool Parser::parseExternalKind(External::Kind& result) 257 258 template<typename SuccessType> 259 ALWAYS_INLINE bool Parser<SuccessType>::parseExternalKind(ExternalKind& result) 210 260 { 211 261 uint8_t value; 212 262 if (!parseUInt7(value)) 213 263 return false; 214 if (! External::isValid(value))215 return false; 216 result = static_cast<External ::Kind>(value);264 if (!isValidExternalKind(value)) 265 return false; 266 result = static_cast<ExternalKind>(value); 217 267 return true; 218 268 } -
trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp
r209696 r209880 61 61 void Plan::run() 62 62 { 63 if (verbose)64 dataLogLn("Starting plan.");65 63 { 66 64 ModuleParser moduleParser(m_vm, m_source, m_sourceLength); 67 if (!moduleParser.parse()) { 68 if (verbose) 69 dataLogLn("Parsing module failed: ", moduleParser.errorMessage()); 70 m_errorMessage = moduleParser.errorMessage(); 71 return; 65 auto parseResult = moduleParser.parse(); 66 if (!parseResult) { 67 m_errorMessage = parseResult.error(); 68 return; // FIXME return an Expected. 72 69 } 73 m_moduleInformation = WTFMove( moduleParser.moduleInformation());74 m_functionLocationInBinary = WTFMove( moduleParser.functionLocationInBinary());75 m_functionIndexSpace.size = moduleParser.functionIndexSpace().size();76 m_functionIndexSpace.buffer = moduleParser.functionIndexSpace().releaseBuffer();70 m_moduleInformation = WTFMove(parseResult->module); 71 m_functionLocationInBinary = WTFMove(parseResult->functionLocationInBinary); 72 m_functionIndexSpace.size = parseResult->functionIndexSpace.size(); 73 m_functionIndexSpace.buffer = parseResult->functionIndexSpace.releaseBuffer(); 77 74 } 78 if (verbose)79 dataLogLn("Parsed module.");80 75 81 76 auto tryReserveCapacity = [this] (auto& vector, size_t size, const char* what) { … … 98 93 for (unsigned importIndex = 0; importIndex < m_moduleInformation->imports.size(); ++importIndex) { 99 94 Import* import = &m_moduleInformation->imports[importIndex]; 100 if (import->kind != External ::Function)95 if (import->kind != ExternalKind::Function) 101 96 continue; 102 97 unsigned importFunctionIndex = m_wasmToJSStubs.size(); … … 118 113 ASSERT(m_functionIndexSpace.buffer.get()[functionIndexSpace].signature == signature); 119 114 120 String error= validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);121 if (! error.isNull()) {115 auto validateResult = validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation); 116 if (!validateResult) { 122 117 if (verbose) { 123 118 for (unsigned i = 0; i < functionLength; ++i) … … 125 120 dataLogLn(); 126 121 } 127 m_errorMessage = error;122 m_errorMessage = validateResult.error(); // FIXME make this an Expected. 128 123 return; 129 124 } 130 125 131 126 unlinkedWasmToWasmCalls.uncheckedAppend(Vector<UnlinkedWasmToWasmCall>()); 132 m_wasmInternalFunctions.uncheckedAppend(parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation)); 127 auto parseAndCompileResult = parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation); 128 if (UNLIKELY(!parseAndCompileResult)) { 129 m_errorMessage = parseAndCompileResult.error(); 130 return; // FIXME make this an Expected. 131 } 132 m_wasmInternalFunctions.uncheckedAppend(WTFMove(*parseAndCompileResult)); 133 133 m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress(); 134 134 } -
trunk/Source/JavaScriptCore/wasm/WasmSections.h
r208401 r209880 43 43 macro(Data, 11, "Data segments") 44 44 45 struct Sections { 46 enum Section : uint8_t { 45 enum class Section : uint8_t { 47 46 #define DEFINE_WASM_SECTION_ENUM(NAME, ID, DESCRIPTION) NAME = ID, 48 47 FOR_EACH_WASM_SECTION(DEFINE_WASM_SECTION_ENUM) 49 48 #undef DEFINE_WASM_SECTION_ENUM 50 Unknown 51 }; 52 static bool validateOrder(Section previous, Section next) 53 { 54 if (previous == Unknown) 55 return true; 56 return previous < next; 49 Unknown 50 }; 51 52 template<typename Int> 53 static inline bool isValidSection(Int section) 54 { 55 switch (section) { 56 #define VALIDATE_SECTION(NAME, ID, DESCRIPTION) case static_cast<Int>(Section::NAME): return true; 57 FOR_EACH_WASM_SECTION(VALIDATE_SECTION) 58 #undef VALIDATE_SECTION 59 default: 60 return false; 57 61 } 58 }; 62 } 63 64 static inline bool validateOrder(Section previous, Section next) 65 { 66 if (previous == Section::Unknown) 67 return true; 68 return static_cast<uint8_t>(previous) < static_cast<uint8_t>(next); 69 } 70 71 static inline const char* makeString(Section section) 72 { 73 switch (section) { 74 #define STRINGIFY_SECTION_NAME(NAME, ID, DESCRIPTION) case Section::NAME: return #NAME; 75 FOR_EACH_WASM_SECTION(STRINGIFY_SECTION_NAME) 76 #undef STRINGIFY_SECTION_NAME 77 default: 78 RELEASE_ASSERT_NOT_REACHED(); 79 return "?"; 80 } 81 } 59 82 60 83 } } // namespace JSC::Wasm -
trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp
r209850 r209880 72 72 Type m_signature; 73 73 }; 74 typedef String ErrorType; 75 typedef UnexpectedType<ErrorType> UnexpectedResult; 76 typedef Expected<void, ErrorType> Result; 74 77 typedef Type ExpressionType; 75 78 typedef ControlData ControlType; … … 79 82 static const ExpressionType emptyExpression = Void; 80 83 81 bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&); 82 bool WARN_UNUSED_RETURN addLocal(Type, uint32_t); 84 template <typename ...Args> 85 NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const 86 { 87 using namespace FailureHelper; // See ADL comment in WasmParser.h. 88 return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module doesn't validate: "), makeString(args)...)); 89 } 90 #define WASM_VALIDATOR_FAIL_IF(condition, ...) do { \ 91 if (UNLIKELY(condition)) \ 92 return fail(__VA_ARGS__); \ 93 } while (0) 94 95 Result WARN_UNUSED_RETURN addArguments(const Vector<Type>&); 96 Result WARN_UNUSED_RETURN addLocal(Type, uint32_t); 83 97 ExpressionType addConstant(Type type, uint64_t) { return type; } 84 98 85 99 // Locals 86 boolWARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);87 boolWARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);100 Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result); 101 Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value); 88 102 89 103 // Globals 90 boolWARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);91 boolWARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);104 Result WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result); 105 Result WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value); 92 106 93 107 // Memory 94 boolWARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);95 boolWARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);108 Result WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset); 109 Result WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset); 96 110 97 111 // Basic operators 98 112 template<OpType> 99 boolWARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);113 Result WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result); 100 114 template<OpType> 101 boolWARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);102 boolWARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);115 Result WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result); 116 Result WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result); 103 117 104 118 // Control flow 105 119 ControlData WARN_UNUSED_RETURN addBlock(Type signature); 106 120 ControlData WARN_UNUSED_RETURN addLoop(Type signature); 107 boolWARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);108 boolWARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);109 boolWARN_UNUSED_RETURN addElseToUnreachable(ControlData&);110 111 boolWARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);112 boolWARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& expressionStack);113 boolWARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack);114 boolWARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);115 boolWARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);116 117 void addUnreachable() {}121 Result WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result); 122 Result WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&); 123 Result WARN_UNUSED_RETURN addElseToUnreachable(ControlData&); 124 125 Result WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues); 126 Result WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& expressionStack); 127 Result WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack); 128 Result WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack); 129 Result WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&); 130 131 Result WARN_UNUSED_RETURN addUnreachable() { return { }; } 118 132 119 133 // Calls 120 bool WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature*, const Vector<ExpressionType>& args, ExpressionType& result); 121 bool WARN_UNUSED_RETURN addCallIndirect(const Signature*, const Vector<ExpressionType>& args, ExpressionType& result); 122 123 void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack); 134 Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature*, const Vector<ExpressionType>& args, ExpressionType& result); 135 Result WARN_UNUSED_RETURN addCallIndirect(const Signature*, const Vector<ExpressionType>& args, ExpressionType& result); 124 136 125 137 bool hasMemory() const { return !!m_module.memory; } 126 138 127 void setErrorMessage(String&& message) { ASSERT(m_errorMessage.isNull()); m_errorMessage = WTFMove(message); }128 String errorMessage() const { return m_errorMessage; }129 139 Validate(ExpressionType returnType, const ModuleInformation& module) 130 140 : m_returnType(returnType) … … 133 143 } 134 144 145 void dump(const Vector<ControlEntry>&, const ExpressionList&); 146 135 147 private: 136 boolunify(Type, Type);137 boolunify(const ExpressionList&, const ControlData&);138 139 boolcheckBranchTarget(ControlData& target, const ExpressionList& expressionStack);148 Result unify(Type, Type); 149 Result unify(const ExpressionList&, const ControlData&); 150 151 Result checkBranchTarget(ControlData& target, const ExpressionList& expressionStack); 140 152 141 153 ExpressionType m_returnType; 142 154 Vector<Type> m_locals; 143 String m_errorMessage;144 155 const ModuleInformation& m_module; 145 156 }; 146 157 147 bool Validate::addArguments(const Vector<Type>& args) 148 { 149 for (Type arg : args) { 150 if (!addLocal(arg, 1)) 151 return false; 152 } 153 return true; 154 } 155 156 bool Validate::addLocal(Type type, uint32_t count) 157 { 158 if (!m_locals.tryReserveCapacity(m_locals.size() + count)) 159 return false; 158 auto Validate::addArguments(const Vector<Type>& args) -> Result 159 { 160 for (Type arg : args) 161 WASM_FAIL_IF_HELPER_FAILS(addLocal(arg, 1)); 162 return { }; 163 } 164 165 auto Validate::addLocal(Type type, uint32_t count) -> Result 166 { 167 size_t size = m_locals.size() + count; 168 WASM_VALIDATOR_FAIL_IF(!m_locals.tryReserveCapacity(size), "can't allocate memory for ", size, " locals"); 160 169 161 170 for (uint32_t i = 0; i < count; ++i) 162 171 m_locals.uncheckedAppend(type); 163 return true; 164 } 165 166 bool Validate::getLocal(uint32_t index, ExpressionType& result) 167 { 168 if (index < m_locals.size()) { 169 result = m_locals[index]; 170 return true; 171 } 172 m_errorMessage = ASCIILiteral("Attempt to use unknown local."); 173 return false; 174 } 175 176 bool Validate::setLocal(uint32_t index, ExpressionType value) 172 return { }; 173 } 174 175 auto Validate::getLocal(uint32_t index, ExpressionType& result) -> Result 176 { 177 WASM_VALIDATOR_FAIL_IF(index >= m_locals.size(), "attempt to use unknown local ", index, " last one is ", m_locals.size()); 178 result = m_locals[index]; 179 return { }; 180 } 181 182 auto Validate::setLocal(uint32_t index, ExpressionType value) -> Result 177 183 { 178 184 ExpressionType localType; 179 if (!getLocal(index, localType)) 180 return false; 181 182 if (localType == value) 183 return true; 184 185 m_errorMessage = makeString("Attempt to set local with type: ", toString(localType), " with a variable of type: ", toString(value)); 186 return false; 187 } 188 189 bool Validate::getGlobal(uint32_t index, ExpressionType& result) 190 { 191 if (index < m_module.globals.size()) { 192 result = m_module.globals[index].type; 193 ASSERT(isValueType(result)); 194 return true; 195 } 196 m_errorMessage = ASCIILiteral("Attempt to use unknown global."); 197 return false; 198 } 199 200 bool Validate::setGlobal(uint32_t index, ExpressionType value) 201 { 202 if (index >= m_module.globals.size()) { 203 m_errorMessage = ASCIILiteral("Attempt to use unknown global."); 204 return false; 205 } 206 207 if (m_module.globals[index].mutability == Global::Immutable) { 208 m_errorMessage = ASCIILiteral("Attempt to store to immutable global."); 209 return false; 210 } 185 WASM_FAIL_IF_HELPER_FAILS(getLocal(index, localType)); 186 WASM_VALIDATOR_FAIL_IF(localType != value, "set_local to type ", value, " expected ", localType); 187 return { }; 188 } 189 190 auto Validate::getGlobal(uint32_t index, ExpressionType& result) -> Result 191 { 192 WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "get_global ", index, " of unknown global, limit is ", m_module.globals.size()); 193 result = m_module.globals[index].type; 194 ASSERT(isValueType(result)); 195 return { }; 196 } 197 198 auto Validate::setGlobal(uint32_t index, ExpressionType value) -> Result 199 { 200 WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "set_global ", index, " of unknown global, limit is ", m_module.globals.size()); 201 WASM_VALIDATOR_FAIL_IF(m_module.globals[index].mutability == Global::Immutable, "set_global ", index, " is immutable"); 211 202 212 203 ExpressionType globalType = m_module.globals[index].type; 213 204 ASSERT(isValueType(globalType)); 214 if (globalType == value) 215 return true; 216 217 m_errorMessage = makeString("Attempt to set global with type: ", toString(globalType), " with a variable of type: ", toString(value)); 218 return false; 205 WASM_VALIDATOR_FAIL_IF(globalType != value, "set_global ", index, " with type ", globalType, " with a variable of type ", value); 206 return { }; 219 207 } 220 208 … … 229 217 } 230 218 231 bool Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) 232 { 233 if (condition != I32) { 234 m_errorMessage = makeString("Attempting to use ", toString(condition), " as the condition for select"); 235 return false; 236 } 237 238 if (nonZero != zero) { 239 m_errorMessage = makeString("Result types of select don't match. Got: ", toString(nonZero), " and ", toString(zero)); 240 return false; 241 } 242 219 auto Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> Result 220 { 221 WASM_VALIDATOR_FAIL_IF(condition != I32, "select condition must be i32, got ", condition); 222 WASM_VALIDATOR_FAIL_IF(nonZero != zero, "select result types must match, got ", nonZero, " and ", zero); 243 223 result = zero; 244 return true; 245 } 246 247 bool Validate::addIf(ExpressionType condition, Type signature, ControlType& result) 248 { 249 if (condition != I32) { 250 m_errorMessage = makeString("Attempting to use ", toString(condition), " as the condition for an if block"); 251 return false; 252 } 224 return { }; 225 } 226 227 auto Validate::addIf(ExpressionType condition, Type signature, ControlType& result) -> Result 228 { 229 WASM_VALIDATOR_FAIL_IF(condition != I32, "if condition must be i32, got ", condition); 253 230 result = ControlData(BlockType::If, signature); 254 return true; 255 } 256 257 bool Validate::addElse(ControlType& current, const ExpressionList& values) 258 { 259 if (!unify(values, current)) { 260 ASSERT(errorMessage()); 261 return false; 262 } 263 231 return { }; 232 } 233 234 auto Validate::addElse(ControlType& current, const ExpressionList& values) -> Result 235 { 236 WASM_FAIL_IF_HELPER_FAILS(unify(values, current)); 264 237 return addElseToUnreachable(current); 265 238 } 266 239 267 bool Validate::addElseToUnreachable(ControlType& current) 268 { 269 if (current.type() != BlockType::If) { 270 m_errorMessage = makeString("Attempting to add else block to something other than an if"); 271 return false; 272 } 273 240 auto Validate::addElseToUnreachable(ControlType& current) -> Result 241 { 242 WASM_VALIDATOR_FAIL_IF(current.type() != BlockType::If, "else block isn't associated to an if"); 274 243 current = ControlData(BlockType::Block, current.signature()); 275 return true;276 } 277 278 bool Validate::addReturn(const ExpressionList& returnValues) 244 return { }; 245 } 246 247 auto Validate::addReturn(const ExpressionList& returnValues) -> Result 279 248 { 280 249 if (m_returnType == Void) 281 return true;250 return { }; 282 251 ASSERT(returnValues.size() == 1); 283 284 if (m_returnType == returnValues[0]) 285 return true; 286 287 m_errorMessage = makeString("Attempting to add return with type: ", toString(returnValues[0]), " but function expects return with type: ", toString(m_returnType)); 288 return false; 289 } 290 291 bool Validate::checkBranchTarget(ControlType& target, const ExpressionList& expressionStack) 252 WASM_VALIDATOR_FAIL_IF(m_returnType != returnValues[0], "return type ", returnValues[0], " doesn't match function's return type ", m_returnType); 253 return { }; 254 } 255 256 auto Validate::checkBranchTarget(ControlType& target, const ExpressionList& expressionStack) -> Result 292 257 { 293 258 if (target.type() == BlockType::Loop) 294 return true;259 return { }; 295 260 296 261 if (target.signature() == Void) 297 return true; 298 299 if (!expressionStack.size()) { 300 m_errorMessage = makeString("Attempting to branch to block with expected type: ", toString(target.signature()), " but the stack was empty"); 301 return false; 302 } 303 304 if (target.signature() == expressionStack.last()) 305 return true; 306 307 m_errorMessage = makeString("Attempting to branch to block with expected type: ", toString(target.signature()), " but stack has type: ", toString(target.signature())); 308 return false; 262 return { }; 263 264 WASM_VALIDATOR_FAIL_IF(expressionStack.isEmpty(), "branch to block on empty expression stack"); 265 WASM_VALIDATOR_FAIL_IF(target.signature() != expressionStack.last(), "branch's stack type doesn't match block's type"); 266 267 return { }; 309 268 } 310 269 311 bool Validate::addBranch(ControlType& target, ExpressionType condition, const ExpressionList& stack) 270 auto Validate::addBranch(ControlType& target, ExpressionType condition, const ExpressionList& stack) -> Result 312 271 { 313 272 // Void means this is an unconditional branch. 314 if (condition != Void && condition != I32) { 315 m_errorMessage = makeString("Attempting to add a conditional branch with condition type: ", toString(condition), " but expected i32."); 316 return false; 317 } 318 273 WASM_VALIDATOR_FAIL_IF(condition != Void && condition != I32, "conditional branch with non-i32 condition ", condition); 319 274 return checkBranchTarget(target, stack); 320 275 } 321 276 322 bool Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) 323 { 324 if (condition != I32) { 325 m_errorMessage = makeString("Attempting to add a br_table with condition type: ", toString(condition), " but expected i32."); 326 return false; 327 } 328 329 for (auto target : targets) { 330 if (defaultTarget.signature() != target->signature()) { 331 m_errorMessage = makeString("Attempting to add a br_table with different expected types. Default target has type: ", toString(defaultTarget.signature()), " but case has type: ", toString(target->signature())); 332 return false; 333 } 334 } 277 auto Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) -> Result 278 { 279 WASM_VALIDATOR_FAIL_IF(condition != I32, "br_table with non-i32 condition ", condition); 280 281 for (auto target : targets) 282 WASM_VALIDATOR_FAIL_IF(defaultTarget.signature() != target->signature(), "br_table target type mismatch"); 335 283 336 284 return checkBranchTarget(defaultTarget, expressionStack); 337 285 } 338 286 339 bool Validate::endBlock(ControlEntry& entry, ExpressionList& stack) 287 auto Validate::endBlock(ControlEntry& entry, ExpressionList& stack) -> Result 340 288 { 341 289 ControlData& block = entry.controlData; 342 290 if (block.signature() == Void) 343 return true; 344 345 if (!stack.size()) { 346 m_errorMessage = makeString("Block fallthough expected type: ", toString(block.signature()), " but the stack was empty"); 347 return false; 348 } 349 350 if (block.signature() == stack.last()) { 351 entry.enclosedExpressionStack.append(block.signature()); 352 return true; 353 } 354 355 m_errorMessage = makeString("Block fallthrough has expected type: ", toString(block.signature()), " but produced type: ", toString(block.signature())); 356 return false; 357 } 358 359 bool Validate::addEndToUnreachable(ControlEntry& entry) 291 return { }; 292 293 WASM_VALIDATOR_FAIL_IF(stack.isEmpty(), "typed block falls through on empty stack"); 294 WASM_VALIDATOR_FAIL_IF(block.signature() != stack.last(), "block fallthrough doesn't match its declared type"); 295 296 entry.enclosedExpressionStack.append(block.signature()); 297 return { }; 298 } 299 300 auto Validate::addEndToUnreachable(ControlEntry& entry) -> Result 360 301 { 361 302 if (entry.controlData.signature() != Void) 362 303 entry.enclosedExpressionStack.append(entry.controlData.signature()); 363 return true; 364 } 365 366 bool Validate::addCall(unsigned, const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) 367 { 368 if (signature->arguments.size() != args.size()) { 369 StringBuilder builder; 370 builder.append("Arity mismatch in call, expected: "); 371 builder.appendNumber(signature->arguments.size()); 372 builder.append(" but got: "); 373 builder.appendNumber(args.size()); 374 m_errorMessage = builder.toString(); 375 return false; 376 } 377 378 for (unsigned i = 0; i < args.size(); ++i) { 379 if (args[i] != signature->arguments[i]) { 380 m_errorMessage = makeString("Expected argument type: ", toString(signature->arguments[i]), " does not match passed argument type: ", toString(args[i])); 381 return false; 382 } 383 } 304 return { }; 305 } 306 307 auto Validate::addCall(unsigned, const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result 308 { 309 WASM_VALIDATOR_FAIL_IF(signature->arguments.size() != args.size(), "arity mismatch in call, got ", args.size(), " arguments, expected ", signature->arguments.size()); 310 311 for (unsigned i = 0; i < args.size(); ++i) 312 WASM_VALIDATOR_FAIL_IF(args[i] != signature->arguments[i], "argument type mismatch in call, got ", args[i], ", expected ", signature->arguments[i]); 384 313 385 314 result = signature->returnType; 386 return true;387 } 388 389 bool Validate::addCallIndirect(const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) 315 return { }; 316 } 317 318 auto Validate::addCallIndirect(const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result 390 319 { 391 320 const auto argumentCount = signature->arguments.size(); 392 if (argumentCount != args.size() - 1) { 393 StringBuilder builder; 394 builder.append("Arity mismatch in call_indirect, expected: "); 395 builder.appendNumber(signature->arguments.size()); 396 builder.append(" but got: "); 397 builder.appendNumber(args.size()); 398 m_errorMessage = builder.toString(); 399 return false; 400 } 401 402 for (unsigned i = 0; i < argumentCount; ++i) { 403 if (args[i] != signature->arguments[i]) { 404 m_errorMessage = makeString("Expected argument type: ", toString(signature->arguments[i]), " does not match passed argument type: ", toString(args[i])); 405 return false; 406 } 407 } 408 409 if (args.last() != I32) { 410 m_errorMessage = makeString("Expected call_indirect target index to have type: i32 but got type: ", toString(args.last())); 411 return false; 412 } 413 321 WASM_VALIDATOR_FAIL_IF(argumentCount != args.size() - 1, "arity mismatch in call_indirect, got ", args.size() - 1, " arguments, expected ", argumentCount); 322 323 for (unsigned i = 0; i < argumentCount; ++i) 324 WASM_VALIDATOR_FAIL_IF(args[i] != signature->arguments[i], "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature->arguments[i]); 325 326 WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last()); 327 414 328 result = signature->returnType; 415 return true;416 } 417 418 bool Validate::unify(const ExpressionList& values, const ControlType& block) 329 return { }; 330 } 331 332 auto Validate::unify(const ExpressionList& values, const ControlType& block) -> Result 419 333 { 420 334 ASSERT(values.size() <= 1); 421 335 if (block.signature() == Void) 422 return true; 423 424 if (!values.size()) { 425 m_errorMessage = makeString("Block has non-void signature but has no stack entries on exit"); 426 return false; 427 } 428 429 if (values[0] == block.signature()) 430 return true; 431 432 m_errorMessage = makeString("Expected control flow to return value with type: ", toString(block.signature()), " but got value with type: ", toString(values[0])); 433 return false; 336 return { }; 337 338 WASM_VALIDATOR_FAIL_IF(values.isEmpty(), "non-void block ends with an empty stack"); 339 WASM_VALIDATOR_FAIL_IF(values[0] != block.signature(), "control flow returns with unexpected type"); 340 341 return { }; 434 342 } 435 343 … … 440 348 } 441 349 442 StringvalidateFunction(const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module)350 Expected<void, String> validateFunction(const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module) 443 351 { 444 352 Validate context(signature->returnType, module); 445 353 FunctionParser<Validate> validator(context, source, length, signature, functionIndexSpace, module); 446 447 if (!validator.parse()) { 448 // FIXME: add better location information here. see: https://bugs.webkit.org/show_bug.cgi?id=164288 449 // FIXME: We should never not have an error message if we return false. 450 // see: https://bugs.webkit.org/show_bug.cgi?id=164354 451 if (context.errorMessage().isNull()) 452 return "Unknown error"; 453 return context.errorMessage(); 454 } 455 456 return String(); 354 WASM_FAIL_IF_HELPER_FAILS(validator.parse()); 355 return { }; 457 356 } 458 357 -
trunk/Source/JavaScriptCore/wasm/WasmValidate.h
r209652 r209880 29 29 30 30 #include "WasmFormat.h" 31 #include <wtf/Expected.h> 31 32 32 33 namespace JSC { namespace Wasm { 33 34 34 StringvalidateFunction(const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);35 Expected<void, String> validateFunction(const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&); 35 36 36 37 } } // namespace JSC::Wasm -
trunk/Source/JavaScriptCore/wasm/generateWasmB3IRGeneratorInlinesHeader.py
r209301 r209880 190 190 args.append("ExpressionType& result") 191 191 return """ 192 template<> bool B3IRGenerator::addOp<OpType::""" + wasm.toCpp(op["name"]) + ">(" + ", ".join(args) + """)192 template<> auto B3IRGenerator::addOp<OpType::""" + wasm.toCpp(op["name"]) + ">(" + ", ".join(args) + """) -> PartialResult 193 193 { 194 194 """ + generateB3Code(opcode, b3op) + """; 195 return true;195 return { }; 196 196 } 197 197 """ -
trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py
r209830 r209880 152 152 153 153 #define CREATE_CASE(name, id, b3type, inc) case name: return #name; 154 inline const char* toString(Type type)154 inline const char* makeString(Type type) 155 155 { 156 156 switch (type) { -
trunk/Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py
r209630 r209880 61 61 op = opcodes[name] 62 62 return """ 63 template<> bool Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType value, ExpressionType& result)63 template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType value, ExpressionType& result) -> Result 64 64 { 65 if (value != """ + cppType(op["parameter"][0]) + """) { 66 m_errorMessage = makeString(\"""" + name + """ expects the value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(value)); 67 return false; 68 } 65 if (UNLIKELY(value != """ + cppType(op["parameter"][0]) + """)) 66 return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ value type mismatch"); 69 67 70 68 result = """ + cppType(op["return"][0]) + """; 71 return true;69 return { }; 72 70 } 73 71 """ … … 77 75 op = opcodes[name] 78 76 return """ 79 template<> bool Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType left, ExpressionType right, ExpressionType& result)77 template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType left, ExpressionType right, ExpressionType& result) -> Result 80 78 { 81 if (left != """ + cppType(op["parameter"][0]) + """) { 82 m_errorMessage = makeString(\"""" + name + """ expects the left value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(left)); 83 return false; 84 } 79 if (UNLIKELY(left != """ + cppType(op["parameter"][0]) + """)) 80 return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ left value type mismatch"); 85 81 86 if (right != """ + cppType(op["parameter"][1]) + """) { 87 m_errorMessage = makeString(\"""" + name + """ expects the right value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(right)); 88 return false; 89 } 82 if (UNLIKELY(right != """ + cppType(op["parameter"][1]) + """)) 83 return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ right value type mismatch"); 90 84 91 85 result = """ + cppType(op["return"][0]) + """; 92 return true;86 return { }; 93 87 } 94 88 """ … … 98 92 return """ 99 93 case LoadOpType::""" + toCpp(name) + """: { 100 if (pointer != """ + cppType(op["parameter"][0]) + """) { 101 m_errorMessage = makeString(\"""" + name + """ expects the pointer to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(pointer)); 102 return false; 103 } 94 if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """)) 95 return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch"); 104 96 105 97 result = """ + cppType(op["return"][0]) + """; 106 return true;98 return { }; 107 99 }""" 108 100 … … 112 104 return """ 113 105 case StoreOpType::""" + toCpp(name) + """: { 114 if (pointer != """ + cppType(op["parameter"][0]) + """) { 115 m_errorMessage = makeString(\"""" + name + """ expects the pointer to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(pointer)); 116 return false; 117 } 106 if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """)) 107 return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch"); 118 108 119 if (value != """ + cppType(op["parameter"][1]) + """) { 120 m_errorMessage = makeString(\"""" + name + """ expects the value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(value)); 121 return false; 122 } 109 if (UNLIKELY(value != """ + cppType(op["parameter"][1]) + """)) 110 return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ value type mismatch"); 123 111 124 return true;112 return { }; 125 113 }""" 126 114 … … 142 130 """ + unarySpecializations + binarySpecializations + """ 143 131 144 bool Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t) 132 auto Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t) -> Result 145 133 { 146 if ( !hasMemory())147 return false;134 if (UNLIKELY(!hasMemory())) 135 return UnexpectedType<Result::ErrorType>("validation failed: load instruction without memory"); 148 136 149 137 switch (op) { … … 152 140 } 153 141 154 bool Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t) 142 auto Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t) -> Result 155 143 { 156 if ( !hasMemory())157 return false;144 if (UNLIKELY(!hasMemory())) 145 return UnexpectedType<Result::ErrorType>("validation failed: store instruction without memory"); 158 146 159 147 switch (op) { -
trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp
r209850 r209880 107 107 108 108 switch (import.kind) { 109 case Wasm::External ::Function: {109 case Wasm::ExternalKind::Function: { 110 110 // 4. If i is a function import: 111 111 // i. If IsCallable(v) is false, throw a TypeError. … … 130 130 break; 131 131 } 132 case Wasm::External ::Table: {132 case Wasm::ExternalKind::Table: { 133 133 RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure. 134 134 // 7. Otherwise (i is a table import): … … 161 161 break; 162 162 } 163 case Wasm::External ::Memory: {163 case Wasm::ExternalKind::Memory: { 164 164 // 6. If i is a memory import: 165 165 RELEASE_ASSERT(!hasMemoryImport); // This should be guaranteed by a validation failure. … … 193 193 break; 194 194 } 195 case Wasm::External ::Global: {195 case Wasm::ExternalKind::Global: { 196 196 // 5. If i is a global import: 197 197 // i. If i is not an immutable global, throw a TypeError. -
trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
r209874 r209880 106 106 JSValue exportedValue; 107 107 switch (exp.kind) { 108 case Wasm::External ::Function: {108 case Wasm::ExternalKind::Function: { 109 109 // 1. If e is a closure c: 110 110 // i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func. … … 127 127 break; 128 128 } 129 case Wasm::External ::Table: {129 case Wasm::ExternalKind::Table: { 130 130 // This should be guaranteed by module verification. 131 131 RELEASE_ASSERT(instance->table()); … … 135 135 break; 136 136 } 137 case Wasm::External ::Memory: {137 case Wasm::ExternalKind::Memory: { 138 138 // This should be guaranteed by module verification. 139 139 RELEASE_ASSERT(instance->memory()); … … 143 143 break; 144 144 } 145 case Wasm::External ::Global: {145 case Wasm::ExternalKind::Global: { 146 146 // Assert: the global is immutable by MVP validation constraint. 147 147 const Wasm::Global& global = moduleInformation.globals[exp.kindIndex];
Note: See TracChangeset
for help on using the changeset viewer.