Skip to content

Commit 0c7f23d

Browse files
authored
Add withStackSave JS helper function. NFC (#15262)
1 parent d655039 commit 0c7f23d

7 files changed

+124
-113
lines changed

src/library.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -625,13 +625,20 @@ LibraryManager.library = {
625625
return buf;
626626
},
627627

628-
ctime_r__deps: ['localtime_r', '__asctime'],
629-
ctime_r__sig: 'iii',
630-
ctime_r: function(time, buf) {
628+
$withStackSave__internal: true,
629+
$withStackSave: function(f) {
631630
var stack = stackSave();
632-
var rv = ___asctime(_localtime_r(time, stackAlloc({{{ C_STRUCTS.tm.__size__ }}})), buf);
631+
var ret = f();
633632
stackRestore(stack);
634-
return rv;
633+
return ret;
634+
},
635+
636+
ctime_r__deps: ['localtime_r', '__asctime', '$withStackSave'],
637+
ctime_r__sig: 'iii',
638+
ctime_r: function(time, buf) {
639+
return withStackSave(function() {
640+
return ___asctime(_localtime_r(time, stackAlloc({{{ C_STRUCTS.tm.__size__ }}})), buf);
641+
});
635642
},
636643

637644
dysize: function(year) {

src/library_dylink.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,10 @@ var LibraryDylink = {
213213
#endif
214214
],
215215
$dlSetError: function(msg) {
216-
var sp = stackSave();
217-
var msg = allocate(intArrayFromString(msg), ALLOC_STACK);
218-
___dl_seterr(msg);
219-
stackRestore(sp);
216+
withStackSave(function() {
217+
var cmsg = allocate(intArrayFromString(msg), ALLOC_STACK);
218+
___dl_seterr(cmsg);
219+
});
220220
},
221221

222222
// Dynamic version of shared.py:make_invoke. This is needed for invokes

src/library_html5.js

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
var LibraryHTML5 = {
8+
$JSEvents__deps: ['$withStackSave'],
89
$JSEvents: {
910

1011
/* We do not depend on the exact initial values of falsey member fields - these fields can be populated on-demand
@@ -188,13 +189,13 @@ var LibraryHTML5 = {
188189

189190
#if USE_PTHREADS
190191
queueEventHandlerOnThread_iiii: function(targetThread, eventHandlerFunc, eventTypeId, eventData, userData) {
191-
var stackTop = stackSave();
192-
var varargs = stackAlloc(12);
193-
{{{ makeSetValue('varargs', 0, 'eventTypeId', 'i32') }}};
194-
{{{ makeSetValue('varargs', 4, 'eventData', 'i32') }}};
195-
{{{ makeSetValue('varargs', 8, 'userData', 'i32') }}};
196-
__emscripten_call_on_thread(0, targetThread, {{{ cDefine('EM_FUNC_SIG_IIII') }}}, eventHandlerFunc, eventData, varargs);
197-
stackRestore(stackTop);
192+
withStackSave(function() {
193+
var varargs = stackAlloc(12);
194+
{{{ makeSetValue('varargs', 0, 'eventTypeId', 'i32') }}};
195+
{{{ makeSetValue('varargs', 4, 'eventData', 'i32') }}};
196+
{{{ makeSetValue('varargs', 8, 'userData', 'i32') }}};
197+
__emscripten_call_on_thread(0, targetThread, {{{ cDefine('EM_FUNC_SIG_IIII') }}}, eventHandlerFunc, eventData, varargs);
198+
});
198199
},
199200
#endif
200201

@@ -2458,23 +2459,23 @@ var LibraryHTML5 = {
24582459
return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}};
24592460
},
24602461

2461-
emscripten_set_offscreencanvas_size_on_target_thread_js__deps: ['$stringToNewUTF8', '_emscripten_call_on_thread'],
2462+
emscripten_set_offscreencanvas_size_on_target_thread_js__deps: ['$stringToNewUTF8', '_emscripten_call_on_thread', '$withStackSave'],
24622463
emscripten_set_offscreencanvas_size_on_target_thread_js: function(targetThread, targetCanvas, width, height) {
2463-
var stackTop = stackSave();
2464-
var varargs = stackAlloc(12);
2465-
var targetCanvasPtr = 0;
2466-
if (targetCanvas) {
2467-
targetCanvasPtr = stringToNewUTF8(targetCanvas);
2468-
}
2469-
{{{ makeSetValue('varargs', 0, 'targetCanvasPtr', 'i32')}}};
2470-
{{{ makeSetValue('varargs', 4, 'width', 'i32')}}};
2471-
{{{ makeSetValue('varargs', 8, 'height', 'i32')}}};
2472-
// Note: If we are also a pthread, the call below could theoretically be done synchronously. However if the target pthread is waiting for a mutex from us, then
2473-
// these two threads will deadlock. At the moment, we'd like to consider that this kind of deadlock would be an Emscripten runtime bug, although if
2474-
// emscripten_set_canvas_element_size() was documented to require running an event in the queue of thread that owns the OffscreenCanvas, then that might be ok.
2475-
// (safer this way however)
2476-
__emscripten_call_on_thread(0, targetThread, {{{ cDefine('EM_PROXIED_RESIZE_OFFSCREENCANVAS') }}}, 0, targetCanvasPtr /* satellite data */, varargs);
2477-
stackRestore(stackTop);
2464+
withStackSave(function() {
2465+
var varargs = stackAlloc(12);
2466+
var targetCanvasPtr = 0;
2467+
if (targetCanvas) {
2468+
targetCanvasPtr = stringToNewUTF8(targetCanvas);
2469+
}
2470+
{{{ makeSetValue('varargs', 0, 'targetCanvasPtr', 'i32')}}};
2471+
{{{ makeSetValue('varargs', 4, 'width', 'i32')}}};
2472+
{{{ makeSetValue('varargs', 8, 'height', 'i32')}}};
2473+
// Note: If we are also a pthread, the call below could theoretically be done synchronously. However if the target pthread is waiting for a mutex from us, then
2474+
// these two threads will deadlock. At the moment, we'd like to consider that this kind of deadlock would be an Emscripten runtime bug, although if
2475+
// emscripten_set_canvas_element_size() was documented to require running an event in the queue of thread that owns the OffscreenCanvas, then that might be ok.
2476+
// (safer this way however)
2477+
__emscripten_call_on_thread(0, targetThread, {{{ cDefine('EM_PROXIED_RESIZE_OFFSCREENCANVAS') }}}, 0, targetCanvasPtr /* satellite data */, varargs);
2478+
});
24782479
},
24792480

24802481
emscripten_set_offscreencanvas_size_on_target_thread__deps: ['emscripten_set_offscreencanvas_size_on_target_thread_js'],
@@ -2519,7 +2520,7 @@ var LibraryHTML5 = {
25192520
},
25202521
#endif
25212522

2522-
$setCanvasElementSize__deps: ['emscripten_set_canvas_element_size'],
2523+
$setCanvasElementSize__deps: ['emscripten_set_canvas_element_size', '$withStackSave'],
25232524
$setCanvasElementSize: function(target, width, height) {
25242525
#if GL_DEBUG
25252526
err('setCanvasElementSize(target='+target+',width='+width+',height='+height);
@@ -2530,13 +2531,13 @@ var LibraryHTML5 = {
25302531
} else {
25312532
// This function is being called from high-level JavaScript code instead of asm.js/Wasm,
25322533
// and it needs to synchronously proxy over to another thread, so marshal the string onto the heap to do the call.
2533-
var stackTop = stackSave();
2534-
var targetInt = stackAlloc(target.id.length+1);
2535-
stringToUTF8(target.id, targetInt, target.id.length+1);
2536-
_emscripten_set_canvas_element_size(targetInt, width, height);
2537-
stackRestore(stackTop);
2534+
withStackSave(function() {
2535+
var targetInt = stackAlloc(target.id.length+1);
2536+
stringToUTF8(target.id, targetInt, target.id.length+1);
2537+
_emscripten_set_canvas_element_size(targetInt, width, height);
2538+
});
25382539
}
2539-
},
2540+
},
25402541

25412542
#if USE_PTHREADS
25422543
emscripten_get_canvas_element_size_calling_thread__deps: ['$JSEvents', '$findCanvasEventTarget'],
@@ -2592,19 +2593,19 @@ var LibraryHTML5 = {
25922593
#endif
25932594

25942595
// JavaScript-friendly API, returns pair [width, height]
2595-
$getCanvasElementSize__deps: ['emscripten_get_canvas_element_size'],
2596+
$getCanvasElementSize__deps: ['emscripten_get_canvas_element_size', '$withStackSave'],
25962597
$getCanvasElementSize: function(target) {
2597-
var stackTop = stackSave();
2598-
var w = stackAlloc(8);
2599-
var h = w + 4;
2600-
2601-
var targetInt = stackAlloc(target.id.length+1);
2602-
stringToUTF8(target.id, targetInt, target.id.length+1);
2603-
var ret = _emscripten_get_canvas_element_size(targetInt, w, h);
2604-
var size = [{{{ makeGetValue('w', 0, 'i32')}}}, {{{ makeGetValue('h', 0, 'i32')}}}];
2605-
stackRestore(stackTop);
2606-
return size;
2607-
},
2598+
return withStackSave(function() {
2599+
var w = stackAlloc(8);
2600+
var h = w + 4;
2601+
2602+
var targetInt = stackAlloc(target.id.length+1);
2603+
stringToUTF8(target.id, targetInt, target.id.length+1);
2604+
var ret = _emscripten_get_canvas_element_size(targetInt, w, h);
2605+
var size = [{{{ makeGetValue('w', 0, 'i32')}}}, {{{ makeGetValue('h', 0, 'i32')}}}];
2606+
return size;
2607+
});
2608+
},
26082609

26092610
emscripten_set_element_css_size__proxy: 'sync',
26102611
emscripten_set_element_css_size__sig: 'iiii',

src/library_pthread.js

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,39 +1265,39 @@ var LibraryPThread = {
12651265
// all the args here.
12661266
// We also pass 'sync' to C separately, since C needs to look at it.
12671267
var numCallArgs = arguments.length - 2;
1268+
var outerArgs = arguments;
12681269
#if ASSERTIONS
12691270
if (numCallArgs > {{{ cDefine('EM_QUEUED_JS_CALL_MAX_ARGS') }}}-1) throw 'emscripten_proxy_to_main_thread_js: Too many arguments ' + numCallArgs + ' to proxied function idx=' + index + ', maximum supported is ' + ({{{ cDefine('EM_QUEUED_JS_CALL_MAX_ARGS') }}}-1) + '!';
12701271
#endif
12711272
// Allocate a buffer, which will be copied by the C code.
1272-
var stack = stackSave();
1273-
// First passed parameter specifies the number of arguments to the function.
1274-
// When BigInt support is enabled, we must handle types in a more complex
1275-
// way, detecting at runtime if a value is a BigInt or not (as we have no
1276-
// type info here). To do that, add a "prefix" before each value that
1277-
// indicates if it is a BigInt, which effectively doubles the number of
1278-
// values we serialize for proxying. TODO: pack this?
1279-
var serializedNumCallArgs = numCallArgs {{{ WASM_BIGINT ? "* 2" : "" }}};
1280-
var args = stackAlloc(serializedNumCallArgs * 8);
1281-
var b = args >> 3;
1282-
for (var i = 0; i < numCallArgs; i++) {
1283-
var arg = arguments[2 + i];
1284-
#if WASM_BIGINT
1285-
if (typeof arg === 'bigint') {
1286-
// The prefix is non-zero to indicate a bigint.
1287-
HEAP64[b + 2*i] = BigInt(1);
1288-
HEAP64[b + 2*i + 1] = arg;
1289-
} else {
1290-
// The prefix is zero to indicate a JS Number.
1291-
HEAP64[b + 2*i] = BigInt(0);
1292-
HEAPF64[b + 2*i + 1] = arg;
1273+
return withStackSave(function() {
1274+
// First passed parameter specifies the number of arguments to the function.
1275+
// When BigInt support is enabled, we must handle types in a more complex
1276+
// way, detecting at runtime if a value is a BigInt or not (as we have no
1277+
// type info here). To do that, add a "prefix" before each value that
1278+
// indicates if it is a BigInt, which effectively doubles the number of
1279+
// values we serialize for proxying. TODO: pack this?
1280+
var serializedNumCallArgs = numCallArgs {{{ WASM_BIGINT ? "* 2" : "" }}};
1281+
var args = stackAlloc(serializedNumCallArgs * 8);
1282+
var b = args >> 3;
1283+
for (var i = 0; i < numCallArgs; i++) {
1284+
var arg = outerArgs[2 + i];
1285+
#if WASM_BIGINT
1286+
if (typeof arg === 'bigint') {
1287+
// The prefix is non-zero to indicate a bigint.
1288+
HEAP64[b + 2*i] = BigInt(1);
1289+
HEAP64[b + 2*i + 1] = arg;
1290+
} else {
1291+
// The prefix is zero to indicate a JS Number.
1292+
HEAP64[b + 2*i] = BigInt(0);
1293+
HEAPF64[b + 2*i + 1] = arg;
1294+
}
1295+
#else
1296+
HEAPF64[b + i] = arg;
1297+
#endif
12931298
}
1294-
#else
1295-
HEAPF64[b + i] = arg;
1296-
#endif
1297-
}
1298-
var ret = _emscripten_run_in_main_runtime_thread_js(index, serializedNumCallArgs, args, sync);
1299-
stackRestore(stack);
1300-
return ret;
1299+
return _emscripten_run_in_main_runtime_thread_js(index, serializedNumCallArgs, args, sync);
1300+
});
13011301
},
13021302

13031303
emscripten_receive_on_main_thread_js_callArgs: '=[]',

src/library_sockfs.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -732,17 +732,19 @@ mergeInto(LibraryManager.library, {
732732
* Passing a NULL callback function to a emscripten_set_socket_*_callback call
733733
* will deregister the callback registered for that Event.
734734
*/
735+
$_setNetworkCallback__deps: ['$withStackSave',
735736
#if !MINIMAL_RUNTIME
736-
$_setNetworkCallback__deps: ['$runtimeKeepalivePush'],
737+
'$runtimeKeepalivePush',
737738
#endif
739+
],
738740
$_setNetworkCallback: function(event, userData, callback) {
739741
function _callback(data) {
740742
try {
741743
if (event === 'error') {
742-
var sp = stackSave();
743-
var msg = allocate(intArrayFromString(data[2]), ALLOC_STACK);
744-
{{{ makeDynCall('viiii', 'callback') }}}(data[0], data[1], msg, userData);
745-
stackRestore(sp);
744+
withStackSave(function() {
745+
var msg = allocate(intArrayFromString(data[2]), ALLOC_STACK);
746+
{{{ makeDynCall('viiii', 'callback') }}}(data[0], data[1], msg, userData);
747+
});
746748
} else {
747749
{{{ makeDynCall('vii', 'callback') }}}(data, userData);
748750
}

src/library_stack_trace.js

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
var LibraryStackTrace = {
8+
$demangle__deps: ['$withStackSave'],
89
$demangle: function(func) {
910
#if DEMANGLE_SUPPORT
1011
// If demangle has failed before, stop demangling any further function names
@@ -13,28 +14,28 @@ var LibraryStackTrace = {
1314
if (demangle.recursionGuard > 1) return func;
1415
var __cxa_demangle_func = Module['___cxa_demangle'] || Module['__cxa_demangle'];
1516
assert(__cxa_demangle_func);
16-
var stackTop = stackSave();
17-
try {
18-
var s = func;
19-
if (s.startsWith('__Z'))
20-
s = s.substr(1);
21-
var len = lengthBytesUTF8(s)+1;
22-
var buf = stackAlloc(len);
23-
stringToUTF8(s, buf, len);
24-
var status = stackAlloc(4);
25-
var ret = __cxa_demangle_func(buf, 0, 0, status);
26-
if ({{{ makeGetValue('status', '0', 'i32') }}} === 0 && ret) {
27-
return UTF8ToString(ret);
17+
return withStackSave(function() {
18+
try {
19+
var s = func;
20+
if (s.startsWith('__Z'))
21+
s = s.substr(1);
22+
var len = lengthBytesUTF8(s)+1;
23+
var buf = stackAlloc(len);
24+
stringToUTF8(s, buf, len);
25+
var status = stackAlloc(4);
26+
var ret = __cxa_demangle_func(buf, 0, 0, status);
27+
if ({{{ makeGetValue('status', '0', 'i32') }}} === 0 && ret) {
28+
return UTF8ToString(ret);
29+
}
30+
// otherwise, libcxxabi failed
31+
} catch(e) {
32+
} finally {
33+
_free(ret);
34+
if (demangle.recursionGuard < 2) --demangle.recursionGuard;
2835
}
29-
// otherwise, libcxxabi failed
30-
} catch(e) {
31-
} finally {
32-
_free(ret);
33-
stackRestore(stackTop);
34-
if (demangle.recursionGuard < 2) --demangle.recursionGuard;
35-
}
36-
// failure when using libcxxabi, don't demangle
37-
return func;
36+
// failure when using libcxxabi, don't demangle
37+
return func;
38+
});
3839
#else // DEMANGLE_SUPPORT
3940
#if ASSERTIONS
4041
warnOnce('warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling');

src/library_wget.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var LibraryWget = {
1616
},
1717
},
1818

19-
emscripten_async_wget__deps: ['$PATH_FS', '$wget', '$callUserCallback', '$Browser',
19+
emscripten_async_wget__deps: ['$PATH_FS', '$wget', '$callUserCallback', '$Browser', '$withStackSave',
2020
#if !MINIMAL_RUNTIME
2121
'$runtimeKeepalivePush', '$runtimeKeepalivePop',
2222
#endif
@@ -33,9 +33,9 @@ var LibraryWget = {
3333
if (callback) {
3434
{{{ runtimeKeepalivePop() }}}
3535
callUserCallback(function() {
36-
var stack = stackSave();
37-
{{{ makeDynCall('vi', 'callback') }}}(allocate(intArrayFromString(_file), ALLOC_STACK));
38-
stackRestore(stack);
36+
withStackSave(function() {
37+
{{{ makeDynCall('vi', 'callback') }}}(allocate(intArrayFromString(_file), ALLOC_STACK));
38+
});
3939
});
4040
}
4141
}
@@ -90,7 +90,7 @@ var LibraryWget = {
9090
}, true /* no need for run dependency, this is async but will not do any prepare etc. step */ );
9191
},
9292

93-
emscripten_async_wget2__deps: ['$PATH_FS', '$wget',
93+
emscripten_async_wget2__deps: ['$PATH_FS', '$wget', '$withStackSave',
9494
#if !MINIMAL_RUNTIME
9595
'$runtimeKeepalivePush', '$runtimeKeepalivePop',
9696
#endif
@@ -128,9 +128,9 @@ var LibraryWget = {
128128

129129
FS.createDataFile( _file.substr(0, index), _file.substr(index + 1), new Uint8Array(/** @type{ArrayBuffer}*/(http.response)), true, true, false);
130130
if (onload) {
131-
var stack = stackSave();
132-
{{{ makeDynCall('viii', 'onload') }}}(handle, arg, allocate(intArrayFromString(_file), ALLOC_STACK));
133-
stackRestore(stack);
131+
withStackSave(function() {
132+
{{{ makeDynCall('viii', 'onload') }}}(handle, arg, allocate(intArrayFromString(_file), ALLOC_STACK));
133+
});
134134
}
135135
} else {
136136
if (onerror) {{{ makeDynCall('viii', 'onerror') }}}(handle, arg, http.status);

0 commit comments

Comments
 (0)