Skip to content

jsifier: Make JS libraries aliases work even when native export exists #19046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions embuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,11 @@
'libc++-mt-noexcept',
'libdlmalloc-mt',
'libGL-emu',
'libGL-emu-webgl2',
'libGL-mt',
'libGL-mt-emu',
'libGL-mt-emu-webgl2',
'libGL-mt-emu-webgl2-ofb',
'libsockets_proxy',
'libsockets-mt',
'crtbegin',
Expand Down
37 changes: 21 additions & 16 deletions src/jsifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,17 +228,12 @@ function ${name}(${args}) {
// what we just added to the library.
}

function addFromLibrary(symbol, dependent) {
function addFromLibrary(symbol, dependent, force = false) {
// dependencies can be JS functions, which we just run
if (typeof symbol == 'function') {
return symbol();
}

if (symbol in addedLibraryItems) {
return;
}
addedLibraryItems[symbol] = true;

// don't process any special identifiers. These are looked up when
// processing the base name of the identifier.
if (isJsLibraryConfigIdentifier(symbol)) {
Expand All @@ -257,9 +252,14 @@ function ${name}(${args}) {

// if the function was implemented in compiled code, there is no need to
// include the js version
if (WASM_EXPORTS.has(symbol)) {
if (WASM_EXPORTS.has(symbol) && !force) {
return;
}

if (symbol in addedLibraryItems) {
return;
}
addedLibraryItems[symbol] = true;

// This gets set to true in the case of dynamic linking for symbols that
// are undefined in the main module. In this case we create a stub that
Expand Down Expand Up @@ -334,17 +334,19 @@ function ${name}(${args}) {
warn(`user library symbol '${symbol}' depends on internal symbol '${dep}'`);
}
});

let isFunction = false;
let aliasTarget;

if (typeof snippet == 'string') {
if (snippet[0] != '=') {
const target = LibraryManager.library[snippet];
if (target) {
// Redirection for aliases. We include the parent, and at runtime make ourselves equal to it.
// This avoid having duplicate functions with identical content.
const redirectedTarget = snippet;
deps.push(redirectedTarget);
snippet = mangleCSymbolName(redirectedTarget);
if (LibraryManager.library[snippet]) {
// Redirection for aliases. We include the parent, and at runtime
// make ourselves equal to it. This avoid having duplicate
// functions with identical content.
aliasTarget = snippet;
snippet = mangleCSymbolName(aliasTarget);
deps.push(aliasTarget);
}
}
} else if (typeof snippet == 'object') {
Expand Down Expand Up @@ -376,7 +378,7 @@ function ${name}(${args}) {
const deps_list = deps.join("','");
const identDependents = symbol + `__deps: ['${deps_list}']`;
function addDependency(dep) {
return addFromLibrary(dep, `${identDependents}, referenced by ${dependent}`);
return addFromLibrary(dep, `${identDependents}, referenced by ${dependent}`, dep === aliasTarget);
}
let contentText;
if (isFunction) {
Expand Down Expand Up @@ -431,8 +433,11 @@ function ${name}(${args}) {
}

let commentText = '';
if (force) {
commentText += '/** @suppress {duplicate } */\n'
}
if (LibraryManager.library[symbol + '__docs']) {
commentText = LibraryManager.library[symbol + '__docs'] + '\n';
commentText += LibraryManager.library[symbol + '__docs'] + '\n';
}

const depsText = (deps ? deps.map(addDependency).filter((x) => x != '').join('\n') + '\n' : '');
Expand Down
2 changes: 1 addition & 1 deletion src/parseTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ function hasExportedSymbol(sym) {
// it is a BigInt. Otherwise, we legalize into pairs of i32s.
function defineI64Param(name) {
if (WASM_BIGINT) {
return `/** @type {!BigInt} */ ${name}`;
return name;
}
return `${name}_low, ${name}_high`;
}
Expand Down
9 changes: 6 additions & 3 deletions system/lib/gl/webgl2.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,10 @@ ASYNC_GL_FUNCTION_5(EM_FUNC_SIG_VIIIII, void, glTexStorage2D, GLenum, GLsizei, G
ASYNC_GL_FUNCTION_6(EM_FUNC_SIG_VIIIIII, void, glTexStorage3D, GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei);
VOID_SYNC_GL_FUNCTION_5(EM_FUNC_SIG_VIIIII, void, glGetInternalformativ, GLenum, GLenum, GLenum, GLsizei, GLint *);

#endif // ~__EMSCRIPTEN_PTHREADS__

// Extensions:
// Extensions that are aliases for the proxying functions defined above.
// Normally these aliases get defined in library_webgl.js but when building with
// __EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__ we want to intercept them in native
// code and redirect them to thier proxying couterparts.
GL_APICALL void GL_APIENTRY glVertexAttribDivisorNV(GLuint index, GLuint divisor) { glVertexAttribDivisor(index, divisor); }
GL_APICALL void GL_APIENTRY glVertexAttribDivisorEXT(GLuint index, GLuint divisor) { glVertexAttribDivisor(index, divisor); }
GL_APICALL void GL_APIENTRY glVertexAttribDivisorARB(GLuint index, GLuint divisor) { glVertexAttribDivisor(index, divisor); }
Expand All @@ -153,6 +154,8 @@ GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES(GLuint array) { return glIsV
GL_APICALL void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs) { glDrawBuffers(n, bufs); }
GL_APICALL void GL_APIENTRY glDrawBuffersWEBGL(GLsizei n, const GLenum *bufs) { glDrawBuffers(n, bufs); }

#endif // ~__EMSCRIPTEN_PTHREADS__) && __EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__

// Returns a function pointer to the given WebGL 2 extension function, when queried without
// a GL extension suffix such as "EXT", "OES", or "ANGLE". This function is used by
// emscripten_GetProcAddress() to implement legacy GL emulation semantics for portability.
Expand Down
4 changes: 2 additions & 2 deletions system/lib/gl/webgl_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ EMSCRIPTEN_RESULT emscripten_webgl_do_commit_frame(void);
EM_BOOL emscripten_supports_offscreencanvas(void);
void _emscripten_proxied_gl_context_activated_from_main_browser_thread(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);

#if defined(__EMSCRIPTEN_PTHREADS__) && defined(__EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__)

#ifdef EMSCRIPTEN_WEBGL_TRACE
#define GL_FUNCTION_TRACE(func) printf(#func "\n")
#else
Expand Down Expand Up @@ -52,8 +54,6 @@ void _emscripten_proxied_gl_context_activated_from_main_browser_thread(EMSCRIPTE
#define VOID_SYNC_GL_FUNCTION_10(sig, ret, functionName, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) ret functionName(t0 p0, t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) { GL_FUNCTION_TRACE(functionName); if (pthread_getspecific(currentThreadOwnsItsWebGLContext)) emscripten_##functionName(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); else emscripten_sync_run_in_main_runtime_thread(sig, &emscripten_##functionName, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); }
#define VOID_SYNC_GL_FUNCTION_11(sig, ret, functionName, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) ret functionName(t0 p0, t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) { GL_FUNCTION_TRACE(functionName); if (pthread_getspecific(currentThreadOwnsItsWebGLContext)) emscripten_##functionName(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); else emscripten_sync_run_in_main_runtime_thread(sig, &emscripten_##functionName, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); }

#if defined(__EMSCRIPTEN_PTHREADS__) && defined(__EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__)

#include <pthread.h>

extern pthread_key_t currentActiveWebGLContext;
Expand Down
2 changes: 2 additions & 0 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -8685,6 +8685,7 @@ def test_full_js_library_minimal_runtime(self):
# binaryen tools get run, which can affect how debug info is kept around
'bigint': [['-sWASM_BIGINT']],
'pthread': [['-pthread', '-Wno-experimental']],
'pthread_offscreen': [['-pthread', '-Wno-experimental', '-sOFFSCREEN_FRAMEBUFFER']],
})
def test_closure_full_js_library(self, args):
# Test for closure errors and warnings in the entire JS library.
Expand All @@ -8698,6 +8699,7 @@ def test_closure_full_js_library(self, args):
'-sFETCH',
'-sFETCH_SUPPORT_INDEXEDDB',
'-sLEGACY_GL_EMULATION',
'-sMAX_WEBGL_VERSION=2',
] + args)

def test_closure_webgpu(self):
Expand Down