Skip to content

Commit

Permalink
Merge branch 'main' into shared_memory
Browse files Browse the repository at this point in the history
  • Loading branch information
eyebrowsoffire committed Oct 10, 2024
2 parents 1d48e33 + 9e37a10 commit a2618d9
Show file tree
Hide file tree
Showing 82 changed files with 438 additions and 151 deletions.
7 changes: 7 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ See docs/process.md for more on how version tagging works.
- The usage of `EM_BOOL` in the emscripten API has been replaced with C/C++
bool. This change should not be observable since `EM_BOOL` has been
equivalent to `bool` since #22157. (#22155)
- Fix regression introduced in 3.1.67 (#22557) which broke webgpu / int64
integration. (#22689)
- SDL2 port updated from 2.28.4 to 2.30.8. (#22697)
- embind no longer exports any library functions by default. Previously we
would export getInheritedInstanceCount, getLiveInheritedInstances,
flushPendingDeletes and setDelayFunction. If you need these library function
exprted they can be added to `EXPORTED_RUNTIME_METHODS`. (#22705)

3.1.68 - 09/30/24
-----------------
Expand Down
3 changes: 1 addition & 2 deletions site/source/docs/api_reference/wasm_audio_worklets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ which resumes the audio context when the user clicks on the DOM Canvas element t
"noise-generator", &options, &GenerateNoise, 0);
// Connect it to audio context destination
EM_ASM({emscriptenGetAudioObject($0).connect(emscriptenGetAudioObject($1).destination)},
wasmAudioWorklet, audioContext);
emscripten_audio_node_connect(wasmAudioWorklet, audioContext, 0, 0);
// Resume context on mouse click
emscripten_set_click_callback("canvas", (void*)audioContext, 0, OnCanvasClick);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -613,30 +613,63 @@ Calling JavaScript functions as function pointers from C
========================================================

You can use ``addFunction`` to return an integer value that represents a
function pointer. Passing that integer to C code then lets it call that value as
a function pointer, and the JavaScript function you sent to ``addFunction`` will
be called.
function pointer. Passing that integer to C code then lets it call that value
as a function pointer, and the JavaScript function you sent to ``addFunction``
will be called.

See `test_add_function in test/test_core.py`_ for an example.

You should build with ``-sALLOW_TABLE_GROWTH`` to allow new functions to be
added to the table. Otherwise by default the table has a fixed size.

.. note:: When using ``addFunction`` on LLVM Wasm backend, you need to provide
an additional second argument, a Wasm function signature string. Each
character within a signature string represents a type. The first character
represents the return type of a function, and remaining characters are for
parameter types.
When using ``addFunction`` with a JavaScript function, you need to provide
an additional second argument, a Wasm function signature string, explained
below. See `test/interop/test_add_function_post.js <https://github.com/emscripten-core/emscripten/blob/main/test/interop/test_add_function_post.js>`_ for an example.


.. _interacting-with-code-function-signatures:

Function Signatures
===================

The LLVM Wasm backend requires a Wasm function signature string when using
``addFunction`` and in JavaScript libraries. Each character within a signature
string represents a type. The first character represents the return type of a
function, and remaining characters are for parameter types.

- ``'v'``: void type
- ``'i'``: 32-bit integer type
- ``'j'``: 64-bit integer type (currently does not exist in JavaScript)
- ``'j'``: 64-bit integer type (see note below)
- ``'f'``: 32-bit float type
- ``'d'``: 64-bit float type
- ``'p'``: 32-bit or 64-bit pointer (MEMORY64)

For example, if you add a function that takes an integer and does not return
anything, the signature is ``'vi'``.

When ``'j'`` is used there are several ways in which the parameter value will
be passed to JavaScript. By default, the value will either be passed as a
single BigInt or a pair of JavaScript numbers (double) depending on whether
the ``WASM_BIGINT`` settings is enabled. In addition, if you only require 53
bits of precision you can add the ``__i53abi`` decorator, which will ignore
the upper bits and the value will be received as a single JavaScript number
(double). It cannot be used with ``addFunction``. Here is an example of a
library function that sets the size of a file using a 64-bit value passed as
a 53 bit (double) and returns an integer error code:

.. code-block:: c
extern "C" int _set_file_size(int handle, uint64_t size);
.. code-block:: javascript
For example, if you add a function that takes an integer and does not return
anything, you can do ``addFunction(your_function, 'vi');``. See
`test/interop/test_add_function_post.js <https://github.com/emscripten-core/emscripten/blob/main/test/interop/test_add_function_post.js>`_ for an example.
_set_file_size__i53abi: true, // Handle 64-bit
_set_file_size__sig: 'iij', // Function signature
_set_file_size: function(handle, size) { ... return error; }
Using ``-sWASM_BIGINT`` when linking is an alternative method of handling
64-bit types in libraries. ```Number()``` may be needed on the JavaScript
side to convert it to a useable value. See `settings reference <https://emscripten.org/docs/tools_reference/settings_reference.html?highlight=environment#wasm-bigint>`_.


.. _interacting-with-code-access-memory:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ For convenience, *embind* provides factory functions to register
EMSCRIPTEN_BINDINGS(stl_wrappers) {
register_vector<int>("VectorInt");
register_map<int,int>("MapIntInt");
register_optional<std::string>("Optional");
register_optional<std::string>();
}
A full example is shown below:
Expand Down
15 changes: 15 additions & 0 deletions src/closure-externs/node-externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,18 @@ Buffer.prototype.toString = function(encoding, start, end) {};

Worker.prototype.ref = function() {};
Worker.prototype.unref = function() {};

/**
* @type {number}
*/
fs.Stats.prototype.atimeMs;

/**
* @type {number}
*/
fs.Stats.prototype.mtimeMs;

/**
* @type {number}
*/
fs.Stats.prototype.ctimeMs;
13 changes: 2 additions & 11 deletions src/embind/embind.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,6 @@ var LibraryEmbind = {
}`,
$EmValOptionalType__deps: ['$EmValType'],
$EmValOptionalType: '=Object.assign({optional: true}, EmValType);',
$init_embind__deps: [
'$getInheritedInstanceCount', '$getLiveInheritedInstances',
'$flushPendingDeletes', '$setDelayFunction'],
$init_embind__postset: 'init_embind();',
$init_embind: () => {
Module['getInheritedInstanceCount'] = getInheritedInstanceCount;
Module['getLiveInheritedInstances'] = getLiveInheritedInstances;
Module['flushPendingDeletes'] = flushPendingDeletes;
Module['setDelayFunction'] = setDelayFunction;
},

$throwUnboundTypeError__deps: ['$registeredTypes', '$typeDependencies', '$UnboundTypeError', '$getTypeName'],
$throwUnboundTypeError: (message, types) => {
Expand Down Expand Up @@ -219,7 +209,6 @@ var LibraryEmbind = {
},

// raw pointer -> instance
$registeredInstances__deps: ['$init_embind'],
$registeredInstances: {},

$getBasestPointer__deps: ['$throwBindingError'],
Expand Down Expand Up @@ -1582,6 +1571,8 @@ var LibraryEmbind = {
'$releaseClassHandle',
'$throwBindingError',
'$detachFinalizer',
'$flushPendingDeletes',
'$delayFunction',
],
$init_ClassHandle: () => {
Object.assign(ClassHandle.prototype, {
Expand Down
2 changes: 1 addition & 1 deletion src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -1534,7 +1534,7 @@ addToLibrary({
emscripten_log__deps: ['$formatString', '$emscriptenLog'],
emscripten_log: (flags, format, varargs) => {
var result = formatString(format, varargs);
var str = UTF8ArrayToString(result, 0);
var str = UTF8ArrayToString(result);
emscriptenLog(flags, str);
},
Expand Down
2 changes: 1 addition & 1 deletion src/library_fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1303,7 +1303,7 @@ FS.staticInit();
var buf = new Uint8Array(length);
FS.read(stream, buf, 0, length, 0);
if (opts.encoding === 'utf8') {
ret = UTF8ArrayToString(buf, 0);
ret = UTF8ArrayToString(buf);
} else if (opts.encoding === 'binary') {
ret = buf;
}
Expand Down
12 changes: 11 additions & 1 deletion src/library_noderawfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,17 @@ addToLibrary({
var stream = FS.getStreamChecked(fd);
fs.ftruncateSync(stream.nfd, len);
},
utime(path, atime, mtime) { fs.utimesSync(path, atime/1000, mtime/1000); },
utime(path, atime, mtime) {
// -1 here for atime or mtime means UTIME_OMIT was passed. Since node
// doesn't support this concept we need to first find the existing
// timestamps in order to preserve them.
if (atime == -1 || mtime == -1) {
var st = fs.statSync(path);
if (atime == -1) atime = st.atimeMs;
if (mtime == -1) mtime = st.mtimeMs;
}
fs.utimesSync(path, atime/1000, mtime/1000);
},
open(path, flags, mode) {
if (typeof flags == "string") {
flags = FS_modeStringToFlags(flags)
Expand Down
4 changes: 4 additions & 0 deletions src/library_pthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,11 @@ var LibraryPThread = {
#if ENVIRONMENT_MAY_BE_WEB || ENVIRONMENT_MAY_BE_WORKER
// This is the way that we signal to the Web Worker that it is hosting
// a pthread.
#if ASSERTIONS
'name': 'em-pthread-' + PThread.nextWorkerID,
#else
'name': 'em-pthread',
#endif
#endif
};
#if EXPORT_ES6 && USE_ES6_IMPORT_META
Expand Down
14 changes: 12 additions & 2 deletions src/library_sdl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2821,6 +2821,7 @@ var LibrarySDL = {
Mix_ReserveChannels: (num) => {
SDL.channelMinimumNumber = num;
},
Mix_PlayChannelTimed__deps: ['Mix_HaltChannel'],
Mix_PlayChannelTimed__proxy: 'sync',
Mix_PlayChannelTimed: (channel, id, loops, ticks) => {
// TODO: handle fixed amount of N loops. Currently loops either 0 or infinite times.
Expand Down Expand Up @@ -2864,9 +2865,14 @@ var LibrarySDL = {
audio.frequency = info.audio.frequency;
}
audio['onended'] = function() { // TODO: cache these
if (channelInfo.audio == this) { channelInfo.audio.paused = true; channelInfo.audio = null; }
if (channelInfo.audio === this || channelInfo.audio.webAudioNode === this) {
channelInfo.audio.paused = true; channelInfo.audio = null;
}
if (SDL.channelFinished) {{{ makeDynCall('vi', 'SDL.channelFinished') }}}(channel);
}
if (channelInfo.audio) {
_Mix_HaltChannel(channel);
}
channelInfo.audio = audio;
// TODO: handle N loops. Behavior matches Mix_PlayMusic
audio.loop = loops != 0;
Expand Down Expand Up @@ -2946,7 +2952,11 @@ var LibrarySDL = {
} else if (info.audio) { // Play via the <audio> element
audio = info.audio;
}
audio['onended'] = function() { if (SDL.music.audio == this) _Mix_HaltMusic(); } // will send callback
audio['onended'] = function() {
if (SDL.music.audio === this || SDL.music.audio?.webAudioNode === this) {
_Mix_HaltMusic(); // will send callback
}
}
audio.loop = loops != 0 && loops != 1; // TODO: handle N loops for finite N
audio.volume = SDL.music.volume;
SDL.music.audio = audio;
Expand Down
1 change: 1 addition & 0 deletions src/library_sigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ sigs = {
emscripten_atomic_wait_async__sig: 'ipippd',
emscripten_atomics_is_lock_free__sig: 'ii',
emscripten_audio_context_state__sig: 'ii',
emscripten_audio_node_connect__sig: 'viiii',
emscripten_audio_worklet_post_function_sig__sig: 'vippp',
emscripten_audio_worklet_post_function_v__sig: 'vip',
emscripten_audio_worklet_post_function_vd__sig: 'vipd',
Expand Down
6 changes: 3 additions & 3 deletions src/library_strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ addToLibrary({
* array that contains uint8 values, returns a copy of that string as a
* Javascript String object.
* heapOrArray is either a regular array, or a JavaScript typed array view.
* @param {number} idx
* @param {number=} idx
* @param {number=} maxBytesToRead
* @return {string}
*/`,
#if TEXTDECODER
$UTF8ArrayToString__deps: ['$UTF8Decoder'],
#endif
$UTF8ArrayToString: (heapOrArray, idx, maxBytesToRead) => {
$UTF8ArrayToString: (heapOrArray, idx = 0, maxBytesToRead = NaN) => {
#if CAN_ADDRESS_2GB
idx >>>= 0;
#endif
Expand All @@ -38,7 +38,7 @@ addToLibrary({
// null terminator by itself. Also, use the length info to avoid running tiny
// strings through TextDecoder, since .subarray() allocates garbage.
// (As a tiny code save trick, compare endPtr against endIdx using a negation,
// so that undefined means Infinity)
// so that undefined/NaN means Infinity)
while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
#endif // TEXTDECODER

Expand Down
8 changes: 4 additions & 4 deletions src/library_tty.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,15 @@ addToLibrary({
},
put_char(tty, val) {
if (val === null || val === {{{ charCode('\n') }}}) {
out(UTF8ArrayToString(tty.output, 0));
out(UTF8ArrayToString(tty.output));
tty.output = [];
} else {
if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle.
}
},
fsync(tty) {
if (tty.output && tty.output.length > 0) {
out(UTF8ArrayToString(tty.output, 0));
out(UTF8ArrayToString(tty.output));
tty.output = [];
}
},
Expand Down Expand Up @@ -143,15 +143,15 @@ addToLibrary({
default_tty1_ops: {
put_char(tty, val) {
if (val === null || val === {{{ charCode('\n') }}}) {
err(UTF8ArrayToString(tty.output, 0));
err(UTF8ArrayToString(tty.output));
tty.output = [];
} else {
if (val != 0) tty.output.push(val);
}
},
fsync(tty) {
if (tty.output && tty.output.length > 0) {
err(UTF8ArrayToString(tty.output, 0));
err(UTF8ArrayToString(tty.output));
tty.output = [];
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/library_wasi.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ var WasiLibrary = {
assert(buffer);
#endif
if (curr === 0 || curr === {{{ charCode('\n') }}}) {
(stream === 1 ? out : err)(UTF8ArrayToString(buffer, 0));
(stream === 1 ? out : err)(UTF8ArrayToString(buffer));
buffer.length = 0;
} else {
buffer.push(curr);
Expand Down
2 changes: 1 addition & 1 deletion src/library_wasmfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ FS.init();
// The buffer contents exist 8 bytes after the returned pointer.
var ret = new Uint8Array(HEAPU8.subarray(buf + 8, buf + 8 + length));
if (opts.encoding === 'utf8') {
ret = UTF8ArrayToString(ret, 0);
ret = UTF8ArrayToString(ret);
}

return ret;
Expand Down
15 changes: 15 additions & 0 deletions src/library_webaudio.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,21 @@ let LibraryWebAudio = {
},
#endif // ~AUDIO_WORKLET

emscripten_audio_node_connect: (source, destination, outputIndex, inputIndex) => {
var srcNode = EmAudio[source];
var dstNode = EmAudio[destination];
#if ASSERTIONS
assert(srcNode, `Called emscripten_audio_node_connect() with an invalid AudioNode handle ${source}`);
assert(srcNode instanceof window.AudioNode, `Called emscripten_audio_node_connect() on handle ${source} that is not an AudiotNode, but of type ${srcNode}`);
assert(dstNode, `Called emscripten_audio_node_connect() with an invalid AudioNode handle ${destination}!`);
assert(dstNode instanceof (window.AudioContext || window.webkitAudioContext) || dstNode instanceof window.AudioNode, `Called emscripten_audio_node_connect() on handle ${destination} that is not an AudioContext or AudioNode, but of type ${dstNode}`);
#endif
#if WEBAUDIO_DEBUG
console.log(`Connecting audio node ID ${source} to audio node ID ${destination} (${srcNode} to ${dstNode})`);
#endif
srcNode.connect(dstNode.destination || dstNode, outputIndex, inputIndex);
},

emscripten_current_thread_is_audio_worklet: () => typeof AudioWorkletGlobalScope !== 'undefined',

emscripten_audio_worklet_post_function_v: (audioContext, funcPtr) => {
Expand Down
4 changes: 2 additions & 2 deletions src/library_webgpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -2883,9 +2883,9 @@ for (var value in LibraryWebGPU.$WebGPU.FeatureName) {

for (const key of Object.keys(LibraryWebGPU)) {
if (typeof LibraryWebGPU[key] === 'function') {
const sig = LibraryWebGPU[key + '__sig'];
const sig = LibraryManager.library[key + '__sig'];
if (sig?.includes('j')) {
LibraryWebGPU[key + '__i53abi'] = true;
LibraryManager.library[key + '__i53abi'] = true;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIR

// The way we signal to a worker that it is hosting a pthread is to construct
// it with a specific name.
var ENVIRONMENT_IS_PTHREAD = ENVIRONMENT_IS_WORKER && self.name == 'em-pthread';
var ENVIRONMENT_IS_PTHREAD = ENVIRONMENT_IS_WORKER && self.name?.startsWith('em-pthread');

#if MODULARIZE && ASSERTIONS
if (ENVIRONMENT_IS_PTHREAD) {
Expand Down
2 changes: 1 addition & 1 deletion src/shell_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ function ready() {
// MINIMAL_RUNTIME does not support --proxy-to-worker option, so Worker and Pthread environments
// coincide.
var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function';
var ENVIRONMENT_IS_PTHREAD = ENVIRONMENT_IS_WORKER && self.name == 'em-pthread';
var ENVIRONMENT_IS_PTHREAD = ENVIRONMENT_IS_WORKER && self.name?.startsWith('em-pthread');

#if !MODULARIZE
// In MODULARIZE mode _scriptName needs to be captured already at the very top of the page immediately when the page is parsed, so it is generated there
Expand Down
2 changes: 1 addition & 1 deletion src/source_map_support.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ if (!isDataURI(wasmSourceMapFile)) {

function getSourceMap() {
var buf = readBinary(wasmSourceMapFile);
return JSON.parse(UTF8ArrayToString(buf, 0, buf.length));
return JSON.parse(UTF8ArrayToString(buf));
}

function getSourceMapPromise() {
Expand Down
Loading

0 comments on commit a2618d9

Please sign in to comment.