22// META: script=/wasm/jsapi/wasm-module-builder.js
33
44function ToPromising ( wasm_export ) {
5- let sig = WebAssembly . Function . type ( wasm_export ) ;
5+ let sig = wasm_export . type ( ) ;
66 assert_true ( sig . parameters . length > 0 ) ;
77 assert_equals ( 'externref' , sig . parameters [ 0 ] ) ;
88 let wrapper_sig = {
@@ -55,16 +55,16 @@ test(() => {
5555 { promising : 'first' } ) ) ;
5656
5757 // Check the wrapper signatures.
58- let export_sig = WebAssembly . Function . type ( export_wrapper ) ;
58+ let export_sig = export_wrapper . type ( ) ;
5959 assert_array_equals ( [ 'i32' ] , export_sig . parameters ) ;
6060 assert_array_equals ( [ 'externref' ] , export_sig . results ) ;
6161
62- let import_sig = WebAssembly . Function . type ( import_wrapper ) ;
62+ let import_sig = import_wrapper . type ( ) ;
6363 assert_array_equals ( [ 'externref' , 'i32' ] , import_sig . parameters ) ;
6464 assert_array_equals ( [ ] , import_sig . results ) ;
6565
6666 let void_export_wrapper = ToPromising ( instance . exports . void_export ) ;
67- let void_export_sig = WebAssembly . Function . type ( void_export_wrapper ) ;
67+ let void_export_sig = void_export_wrapper . type ( ) ;
6868 assert_array_equals ( [ ] , void_export_sig . parameters ) ;
6969 assert_array_equals ( [ 'externref' ] , void_export_sig . results ) ;
7070} , "Test import and export type checking" ) ;
@@ -134,11 +134,14 @@ promise_test(async () => {
134134
135135test ( ( ) => {
136136 let builder = new WasmModuleBuilder ( ) ;
137+ builder . addGlobal ( kWasmI32 , true ) . exportAs ( 'g' ) ;
137138 import_index = builder . addImport ( 'm' , 'import' , kSig_i_r ) ;
138139 builder . addFunction ( "test" , kSig_i_r )
139140 . addBody ( [
140141 kExprLocalGet , 0 ,
141- kExprCallFunction , import_index , // suspend
142+ kExprCallFunction , import_index ,
143+ kExprGlobalSet , 0 ,
144+ kExprGlobalGet , 0 ,
142145 ] ) . exportFunc ( ) ;
143146 function js_import ( ) {
144147 return 42
@@ -149,19 +152,21 @@ test(() => {
149152 { suspending : 'first' } ) ;
150153 let instance = builder . instantiate ( { m : { import : wasm_js_import } } ) ;
151154 let wrapped_export = ToPromising ( instance . exports . test ) ;
152- assert_equals ( 42 , wrapped_export ( ) ) ;
155+ wrapped_export ( ) ;
156+ // The global was updated synchronously.
157+ assert_equals ( 42 , instance . exports . g . value ) ;
153158} , "Do not suspend if the import's return value is not a Promise" ) ;
154159
155160test ( t => {
156161 let tag = new WebAssembly . Tag ( { parameters : [ ] } ) ;
157162 let builder = new WasmModuleBuilder ( ) ;
158163 import_index = builder . addImport ( 'm' , 'import' , kSig_i_r ) ;
159- tag_index = builder . addImportedException ( 'm' , 'tag ' , kSig_v_v ) ;
164+ js_throw_index = builder . addImport ( 'm' , 'js_throw ' , kSig_v_v ) ;
160165 builder . addFunction ( "test" , kSig_i_r )
161166 . addBody ( [
162167 kExprLocalGet , 0 ,
163168 kExprCallFunction , import_index ,
164- kExprThrow , tag_index
169+ kExprCallFunction , js_throw_index ,
165170 ] ) . exportFunc ( ) ;
166171 function js_import ( ) {
167172 return Promise . resolve ( ) ;
@@ -170,29 +175,30 @@ test(t => {
170175 { parameters : [ 'externref' ] , results : [ 'i32' ] } ,
171176 js_import ,
172177 { suspending : 'first' } ) ;
178+ function js_throw ( ) {
179+ throw new Error ( ) ;
180+ }
173181
174- let instance = builder . instantiate ( { m : { import : wasm_js_import , tag : tag } } ) ;
182+ let instance = builder . instantiate ( { m : { import : wasm_js_import , js_throw } } ) ;
175183 let wrapped_export = ToPromising ( instance . exports . test ) ;
176184 let export_promise = wrapped_export ( ) ;
177185 assert_true ( export_promise instanceof Promise ) ;
178- promise_rejects ( t , new WebAssembly . Exception ( tag , [ ] ) , export_promise ) ;
186+ promise_rejects ( t , new Error ( ) , export_promise ) ;
179187} , "Throw after the first suspension" ) ;
180188
181- promise_test ( async ( ) => {
189+ // TODO: Use wasm exception handling to check that the exception can be caught in wasm.
190+
191+ test ( t => {
182192 let tag = new WebAssembly . Tag ( { parameters : [ 'i32' ] } ) ;
183193 let builder = new WasmModuleBuilder ( ) ;
184194 import_index = builder . addImport ( 'm' , 'import' , kSig_i_r ) ;
185- tag_index = builder . addImportedException ( 'm' , 'tag' , kSig_v_i ) ;
186195 builder . addFunction ( "test" , kSig_i_r )
187196 . addBody ( [
188- kExprTry , kWasmI32 ,
189197 kExprLocalGet , 0 ,
190198 kExprCallFunction , import_index ,
191- kExprCatch , tag_index ,
192- kExprEnd ,
193199 ] ) . exportFunc ( ) ;
194200 function js_import ( ) {
195- return Promise . reject ( new WebAssembly . Exception ( tag , [ 42 ] ) ) ;
201+ return Promise . reject ( new Error ( ) ) ;
196202 } ;
197203 let wasm_js_import = new WebAssembly . Function (
198204 { parameters : [ 'externref' ] , results : [ 'i32' ] } ,
@@ -203,7 +209,7 @@ promise_test(async () => {
203209 let wrapped_export = ToPromising ( instance . exports . test ) ;
204210 let export_promise = wrapped_export ( ) ;
205211 assert_true ( export_promise instanceof Promise ) ;
206- assert_equals ( 42 , await export_promise ) ;
212+ promise_rejects ( t , new Error ( ) , export_promise ) ;
207213} , "Rejecting promise" ) ;
208214
209215async function TestNestedSuspenders ( suspend ) {
@@ -214,8 +220,8 @@ async function TestNestedSuspenders(suspend) {
214220 // the outer wasm function, which returns a Promise. The inner Promise
215221 // resolves first, which resumes the inner continuation. Then the outer
216222 // promise resolves which resumes the outer continuation.
217- // If 'suspend' is false, the inner JS function returns a regular value and
218- // no computation is suspended.
223+ // If 'suspend' is false, the inner and outer JS functions return a regular
224+ // value and no computation is suspended.
219225 let builder = new WasmModuleBuilder ( ) ;
220226 inner_index = builder . addImport ( 'm' , 'inner' , kSig_i_r ) ;
221227 outer_index = builder . addImport ( 'm' , 'outer' , kSig_i_r ) ;
@@ -238,19 +244,15 @@ async function TestNestedSuspenders(suspend) {
238244 let export_inner ;
239245 let outer = new WebAssembly . Function (
240246 { parameters : [ 'externref' ] , results : [ 'i32' ] } ,
241- ( ) => export_inner ( ) ,
247+ ( ) => suspend ? export_inner ( ) : 42 ,
242248 { suspending : 'first' } ) ;
243249
244250 let instance = builder . instantiate ( { m : { inner, outer} } ) ;
245251 export_inner = ToPromising ( instance . exports . inner ) ;
246252 let export_outer = ToPromising ( instance . exports . outer ) ;
247253 let result = export_outer ( ) ;
248- if ( suspend ) {
249- assert_true ( result instanceof Promise ) ;
250- assert_equals ( 42 , await result ) ;
251- } else {
252- assert_equals ( 43 , result ) ;
253- }
254+ assert_true ( result instanceof Promise ) ;
255+ assert_equals ( 42 , await result ) ;
254256}
255257
256258test ( ( ) => {
@@ -283,3 +285,103 @@ test(() => {
283285 assert_throws ( WebAssembly . RuntimeError , ( ) => instance . exports . test ( s ) ) ;
284286 }
285287} , "Call import with an invalid suspender" ) ;
288+
289+ test ( t => {
290+ let builder = new WasmModuleBuilder ( ) ;
291+ builder . addFunction ( "test" , kSig_i_r )
292+ . addBody ( [
293+ kExprLocalGet , 0 ,
294+ kExprCallFunction , 0
295+ ] ) . exportFunc ( ) ;
296+ let instance = builder . instantiate ( ) ;
297+ let wrapper = ToPromising ( instance . exports . test ) ;
298+ promise_rejects ( t , new RangeError ( ) , wrapper ( ) ) ;
299+ } , "Stack overflow" ) ;
300+
301+ test ( ( ) => {
302+ let builder = new WasmModuleBuilder ( ) ;
303+ let import_index = builder . addImport ( 'm' , 'import' , kSig_i_r ) ;
304+ builder . addFunction ( "test" , kSig_i_r )
305+ . addBody ( [
306+ kExprLocalGet , 0 ,
307+ kExprCallFunction , import_index , // suspend
308+ ] ) . exportFunc ( ) ;
309+ builder . addFunction ( "return_suspender" , kSig_r_r )
310+ . addBody ( [
311+ kExprLocalGet , 0
312+ ] ) . exportFunc ( ) ;
313+ let js_import = new WebAssembly . Function (
314+ { parameters : [ 'externref' ] , results : [ 'i32' ] } ,
315+ ( ) => Promise . resolve ( 42 ) ,
316+ { suspending : 'first' } ) ;
317+ let instance = builder . instantiate ( { m : { import : js_import } } ) ;
318+ let suspender = ToPromising ( instance . exports . return_suspender ) ( ) ;
319+ for ( s of [ suspender , null , undefined , { } ] ) {
320+ assert_throws ( WebAssembly . RuntimeError , ( ) => instance . exports . test ( s ) ) ;
321+ }
322+ } , "Pass an invalid suspender" ) ;
323+
324+ // TODO: Test suspension with funcref.
325+
326+ test ( t => {
327+ // The call stack of this test looks like:
328+ // export1 -> import1 -> export2 -> import2
329+ // Where export1 is "promising" and import2 is "suspending". Returning a
330+ // promise from import2 should trap because of the JS import in the middle.
331+ let builder = new WasmModuleBuilder ( ) ;
332+ let import1_index = builder . addImport ( "m" , "import1" , kSig_i_v ) ;
333+ let import2_index = builder . addImport ( "m" , "import2" , kSig_i_r ) ;
334+ builder . addGlobal ( kWasmAnyRef , true ) ;
335+ builder . addFunction ( "export1" , kSig_i_r )
336+ . addBody ( [
337+ // export1 -> import1 (unwrapped)
338+ kExprLocalGet , 0 ,
339+ kExprGlobalSet , 0 ,
340+ kExprCallFunction , import1_index ,
341+ ] ) . exportFunc ( ) ;
342+ builder . addFunction ( "export2" , kSig_i_v )
343+ . addBody ( [
344+ // export2 -> import2 (suspending)
345+ kExprGlobalGet , 0 ,
346+ kExprCallFunction , import2_index ,
347+ ] ) . exportFunc ( ) ;
348+ let instance ;
349+ function import1 ( ) {
350+ // import1 -> export2 (unwrapped)
351+ instance . exports . export2 ( ) ;
352+ }
353+ function import2 ( ) {
354+ return Promise . resolve ( 0 ) ;
355+ }
356+ import2 = new WebAssembly . Function (
357+ { parameters : [ 'externref' ] , results : [ 'i32' ] } ,
358+ import2 ,
359+ { suspending : 'first' } ) ;
360+ instance = builder . instantiate (
361+ { 'm' :
362+ { 'import1' : import1 ,
363+ 'import2' : import2
364+ } } ) ;
365+ // export1 (promising)
366+ let wrapper = new WebAssembly . Function (
367+ { parameters : [ ] , results : [ 'externref' ] } ,
368+ instance . exports . export1 ,
369+ { promising : 'first' } ) ;
370+ promise_rejects ( t , new WebAssembly . RuntimeError ( ) , wrapper ( ) ) ;
371+ } , "Test that trying to suspend JS frames traps" ) ;
372+
373+ test ( ( ) => {
374+ let builder = new WasmModuleBuilder ( ) ;
375+ import_index = builder . addImport ( 'm' , 'import' , kSig_i_r ) ;
376+ builder . addFunction ( "test" , kSig_i_r )
377+ . addBody ( [
378+ kExprLocalGet , 0 ,
379+ kExprCallFunction , import_index , // suspend
380+ ] ) . exportFunc ( ) ;
381+ let js_import = new WebAssembly . Function (
382+ { parameters : [ 'externref' ] , results : [ 'i32' ] } ,
383+ ( ) => 42 ,
384+ { suspending : 'first' } ) ;
385+ let instance = builder . instantiate ( { m : { import : js_import } } ) ;
386+ assert_equals ( 42 , instance . exports . test ( null ) ) ;
387+ } , "Pass an invalid suspender to the import and return a non-promise" ) ;
0 commit comments