@@ -7407,6 +7407,77 @@ def test_async_abort(self):
7407
7407
self .emcc_args += ['--js-library' , 'lib.js' ]
7408
7408
self .do_run (src , 'Hello' )
7409
7409
7410
+ def test_async_invoke_safe_heap (self ):
7411
+ if not self .is_emterpreter (): return self .skip ('emterpreter-only test' )
7412
+
7413
+ self .banned_js_engines = [SPIDERMONKEY_ENGINE , V8_ENGINE ] # needs setTimeout which only node has
7414
+
7415
+ # SAFE_HEAP leads to SAFE_FT_MASK, which appear in dynCall_*
7416
+ # and then if they are interpreted, that messes up reloading
7417
+ # of the stack (we can't run emterpreted code at that time,
7418
+ # we should just see calls and follow them).
7419
+ Settings .EMTERPRETIFY_ASYNC = 1
7420
+ Settings .SAFE_HEAP = 1
7421
+ Settings .EXPORTED_FUNCTIONS = ['_async_callback_test' ]
7422
+ Settings .EXTRA_EXPORTED_RUNTIME_METHODS = ["ccall" ]
7423
+ Settings .DISABLE_EXCEPTION_CATCHING = 0
7424
+ Settings .ALLOW_MEMORY_GROWTH = 1
7425
+ Settings .EMTERPRETIFY = 1
7426
+ Settings .EMTERPRETIFY_ASYNC = 1
7427
+ Settings .ASSERTIONS = 2
7428
+
7429
+ open ('post.js' , 'w' ).write (r'''
7430
+ var AsyncOperation = {
7431
+ done: false,
7432
+
7433
+ start: function() {
7434
+ // this.done = true; // uncomment this line => no crash
7435
+ Promise.resolve().then(function() {
7436
+ console.log('done!');
7437
+ AsyncOperation.done = true;
7438
+ });
7439
+ }
7440
+ };
7441
+
7442
+ Module.ccall('async_callback_test', null, [], [], { async: true });
7443
+ ''' )
7444
+
7445
+ src = r'''
7446
+ #include <stdio.h>
7447
+ #include <emscripten.h>
7448
+
7449
+ extern "C" {
7450
+ void call_async_operation() {
7451
+ printf("start\n");
7452
+ EM_ASM({AsyncOperation.start()});
7453
+ printf("mid\n");
7454
+ while (!EM_ASM_INT({return AsyncOperation.done})) {
7455
+ printf("sleep1\n");
7456
+ emscripten_sleep(200);
7457
+ printf("sleep2\n");
7458
+ }
7459
+ }
7460
+
7461
+ // remove throw() => no crash
7462
+ static void nothrow_func() throw()
7463
+ {
7464
+ call_async_operation();
7465
+ printf("async operation OK\n");
7466
+ }
7467
+
7468
+ void async_callback_test() {
7469
+ nothrow_func();
7470
+ }
7471
+ }'''
7472
+
7473
+ self .emcc_args += [
7474
+ '--post-js' , 'post.js' ,
7475
+ '--profiling-funcs' ,
7476
+ '--minify' , '0' ,
7477
+ '--memory-init-file' , '0'
7478
+ ]
7479
+ self .do_run (src , 'async operation OK' )
7480
+
7410
7481
def do_test_coroutine (self , additional_settings ):
7411
7482
Settings .NO_EXIT_RUNTIME = 0 # needs to flush stdio streams
7412
7483
src = open (path_from_root ('tests' , 'test_coroutines.cpp' )).read ()
@@ -7632,7 +7703,6 @@ def setUp(self):
7632
7703
7633
7704
# asm.js
7634
7705
asm2f = make_run ('asm2f' , compiler = CLANG , emcc_args = ['-Oz' , '-s' , 'PRECISE_F32=1' , '-s' , 'ALLOW_MEMORY_GROWTH=1' , '-s' , 'WASM=0' ])
7635
- asm2i = make_run ('asm2i' , compiler = CLANG , emcc_args = ['-O2' , '-s' , 'EMTERPRETIFY=1' , '-s' , 'WASM=0' ])
7636
7706
asm2nn = make_run ('asm2nn' , compiler = CLANG , emcc_args = ['-O2' , '-s' , 'WASM=0' ], env = {'EMCC_NATIVE_OPTIMIZER' : '0' })
7637
7707
7638
7708
# wasm
@@ -7641,4 +7711,8 @@ def setUp(self):
7641
7711
binaryen2s = make_run ('binaryen2s' , compiler = CLANG , emcc_args = ['-O2' , '-s' , 'SAFE_HEAP=1' ])
7642
7712
binaryen2_interpret = make_run ('binaryen2_interpret' , compiler = CLANG , emcc_args = ['-O2' , '-s' , 'BINARYEN_METHOD="interpret-binary"' ])
7643
7713
7714
+ # emterpreter
7715
+ asmi = make_run ('asmi' , compiler = CLANG , emcc_args = ['-s' , 'EMTERPRETIFY=1' , '-s' , 'WASM=0' ])
7716
+ asm2i = make_run ('asm2i' , compiler = CLANG , emcc_args = ['-O2' , '-s' , 'EMTERPRETIFY=1' , '-s' , 'WASM=0' ])
7717
+
7644
7718
del T # T is just a shape for the specific subclasses, we don't test it itself
0 commit comments