Skip to content

Commit 97c22d4

Browse files
authored
Build-time error on use of emscripten_promise_any if Promise.any is not available (#19172)
1 parent 309581e commit 97c22d4

File tree

5 files changed

+57
-14
lines changed

5 files changed

+57
-14
lines changed

emcc.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2420,6 +2420,14 @@ def phase_linker_setup(options, state, newargs):
24202420
if settings.INCLUDE_FULL_LIBRARY and not settings.DISABLE_EXCEPTION_CATCHING:
24212421
settings.EXPORTED_FUNCTIONS += ['___get_exception_message', '_free']
24222422

2423+
if settings.MEMORY64:
2424+
if settings.ASYNCIFY and settings.MEMORY64 == 1:
2425+
exit_with_error('MEMORY64=1 is not compatible with ASYNCIFY')
2426+
if not settings.DISABLE_EXCEPTION_CATCHING:
2427+
exit_with_error('MEMORY64 is not compatible with DISABLE_EXCEPTION_CATCHING=0')
2428+
# Any "pointers" passed to JS will now be i64's, in both modes.
2429+
settings.WASM_BIGINT = 1
2430+
24232431
if settings.WASM_WORKERS:
24242432
# TODO: After #15982 is resolved, these dependencies can be declared in library_wasm_worker.js
24252433
# instead of having to record them here.
@@ -2432,13 +2440,19 @@ def phase_linker_setup(options, state, newargs):
24322440
settings.WASM_WORKER_FILE = unsuffixed(os.path.basename(target)) + '.ww.js'
24332441
settings.JS_LIBRARIES.append((0, shared.path_from_root('src', 'library_wasm_worker.js')))
24342442

2443+
# Set min browser versions based on certain settings such as WASM_BIGINT,
2444+
# PTHREADS, AUDIO_WORKLET
2445+
# Such setting must be set before this point
2446+
feature_matrix.apply_min_browser_versions()
2447+
2448+
# TODO(sbc): Find make a generic way to expose the feature matrix to JS
2449+
# compiler rather then adding them all ad-hoc as internal settings
24352450
settings.SUPPORTS_GLOBALTHIS = feature_matrix.caniuse(feature_matrix.Feature.GLOBALTHIS)
2451+
settings.SUPPORTS_PROMISE_ANY = feature_matrix.caniuse(feature_matrix.Feature.PROMISE_ANY)
24362452
if not settings.BULK_MEMORY:
24372453
settings.BULK_MEMORY = feature_matrix.caniuse(feature_matrix.Feature.BULK_MEMORY)
24382454

24392455
if settings.AUDIO_WORKLET:
2440-
if not settings.SUPPORTS_GLOBALTHIS:
2441-
exit_with_error('Must target recent enough browser versions that will support globalThis in order to target Wasm Audio Worklets!')
24422456
if settings.AUDIO_WORKLET == 1:
24432457
settings.AUDIO_WORKLET_FILE = unsuffixed(os.path.basename(target)) + '.aw.js'
24442458
settings.JS_LIBRARIES.append((0, shared.path_from_root('src', 'library_webaudio.js')))
@@ -2552,14 +2566,6 @@ def check_memory_setting(setting):
25522566
if settings.SHARED_MEMORY or settings.RELOCATABLE or settings.ASYNCIFY_LAZY_LOAD_CODE or settings.WASM2JS:
25532567
settings.IMPORTED_MEMORY = 1
25542568

2555-
if settings.MEMORY64:
2556-
if settings.ASYNCIFY and settings.MEMORY64 == 1:
2557-
exit_with_error('MEMORY64=1 is not compatible with ASYNCIFY')
2558-
if not settings.DISABLE_EXCEPTION_CATCHING:
2559-
exit_with_error('MEMORY64 is not compatible with DISABLE_EXCEPTION_CATCHING=0')
2560-
# Any "pointers" passed to JS will now be i64's, in both modes.
2561-
settings.WASM_BIGINT = 1
2562-
25632569
if settings.WASM_BIGINT:
25642570
settings.LEGALIZE_JS_FFI = 0
25652571

@@ -2900,8 +2906,6 @@ def get_full_import_name(name):
29002906
if settings.WASM_EXCEPTIONS:
29012907
settings.EXPORTED_FUNCTIONS += ['___cpp_exception', '___cxa_increment_exception_refcount', '___cxa_decrement_exception_refcount', '___thrown_object_from_unwind_exception']
29022908

2903-
feature_matrix.apply_min_browser_versions()
2904-
29052909
if settings.SIDE_MODULE:
29062910
# For side modules, we ignore all REQUIRED_EXPORTS that might have been added above.
29072911
# They all come from either libc or compiler-rt. The exception is __wasm_call_ctors

src/library_promise.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,13 @@ mergeInto(LibraryManager.library, {
216216
return id;
217217
},
218218

219-
emscripten_promise_any__deps: ['$promiseMap', '$idsToPromises'],
219+
220+
emscripten_promise_any__deps: [
221+
'$promiseMap', '$idsToPromises',
222+
#if !SUPPORTS_PROMISE_ANY && !INCLUDE_FULL_LIBRARY
223+
() => error("emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration (run with EMCC_DEBUG=1 in the env for more details)"),
224+
#endif
225+
],
220226
emscripten_promise_any: function(idBuf, errorBuf, size) {
221227
var promises = idsToPromises(idBuf, size);
222228
#if RUNTIME_DEBUG

src/settings_internal.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ var TARGET_NOT_SUPPORTED = 0x7FFFFFFF;
175175
// Used to track whether target environment supports the 'globalThis' attribute.
176176
var SUPPORTS_GLOBALTHIS = false;
177177

178+
// Used to track whether target environment supports the 'Promise.any'.
179+
var SUPPORTS_PROMISE_ANY = false;
180+
178181
// Wasm backend symbols that are considered system symbols and don't
179182
// have the normal C symbol name mangled applied (== prefix with an underscore)
180183
// (Also implicily on this list is any function that starts with string "dynCall_")

test/test_core.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9761,6 +9761,14 @@ def test_main_reads_args(self):
97619761

97629762
@requires_node
97639763
def test_promise(self):
9764+
# This test depends on Promise.any, which in turn requires a modern target. Check that it
9765+
# fails to even build without bumping the min versions:
9766+
err = self.expect_fail([EMCC, test_file('core/test_promise.c')])
9767+
self.assertContained('error: emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration', err)
9768+
self.set_setting('MIN_NODE_VERSION', '150000')
9769+
self.set_setting('MIN_SAFARI_VERSION', '150000')
9770+
self.set_setting('MIN_FIREFOX_VERSION', '79')
9771+
self.set_setting('MIN_CHROME_VERSION', '85')
97649772
self.do_core_test('test_promise.c')
97659773

97669774

tools/feature_matrix.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Feature(IntEnum):
2222
JS_BIGINT_INTEGRATION = auto()
2323
THREADS = auto()
2424
GLOBALTHIS = auto()
25+
PROMISE_ANY = auto()
2526

2627

2728
default_features = {Feature.SIGN_EXT, Feature.MUTABLE_GLOBALS}
@@ -62,25 +63,44 @@ class Feature(IntEnum):
6263
'edge': 79,
6364
'firefox': 65,
6465
'safari': 120100,
65-
# 'node': 120000
66+
'node': 120000,
67+
},
68+
Feature.PROMISE_ANY: {
69+
'chrome': 85,
70+
'firefox': 79,
71+
'safari': 140000,
72+
'node': 150000,
6673
},
6774
}
6875

6976

7077
def caniuse(feature):
7178
min_versions = min_browser_versions[feature]
79+
80+
def report_missing(setting_name):
81+
setting_value = getattr(settings, setting_name)
82+
logger.debug(f'cannot use {feature.name} because {setting_name} is too old: {setting_value}')
83+
7284
if settings.MIN_CHROME_VERSION < min_versions['chrome']:
85+
report_missing('MIN_CHROME_VERSION')
7386
return False
7487
# For edge we just use the same version requirements as chrome since,
7588
# at least for modern versions of edge, they share version numbers.
7689
if settings.MIN_EDGE_VERSION < min_versions['chrome']:
90+
report_missing('MIN_EDGE_VERSION')
7791
return False
7892
if settings.MIN_FIREFOX_VERSION < min_versions['firefox']:
93+
report_missing('MIN_FIREFOX_VERSION')
7994
return False
8095
if settings.MIN_SAFARI_VERSION < min_versions['safari']:
96+
report_missing('MIN_SAFARI_VERSION')
8197
return False
8298
# IE don't support any non-MVP features
8399
if settings.MIN_IE_VERSION != 0x7FFFFFFF:
100+
report_missing('MIN_IE_VERSION')
101+
return False
102+
if 'node' in min_versions and settings.MIN_NODE_VERSION < min_versions['node']:
103+
report_missing('MIN_NODE_VERSION')
84104
return False
85105
return True
86106

@@ -112,3 +132,5 @@ def apply_min_browser_versions():
112132
if settings.PTHREADS:
113133
enable_feature(Feature.THREADS, 'pthreads')
114134
enable_feature(Feature.BULK_MEMORY, 'pthreads')
135+
if settings.AUDIO_WORKLET:
136+
enable_feature(Feature.GLOBALTHIS, 'AUDIO_WORKLET')

0 commit comments

Comments
 (0)