From 88383f11e493f8401bb17c2fbc3c7ea2758b110b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 21 Dec 2021 16:59:08 -0800 Subject: [PATCH] Modernize internal JS code and run it through eslint. NFC This change does not effect the JS that we output, only the the internal JS tooling. This is a followup to #15836 which did this cleanup just for a single file. The long list of exclusions in `.eslintrc.yml` is because these files are part of the JS library code which we ship and we a lot of that cannot be run though the lint tool because it uses our speciall pre-processing techniques. --- .eslintrc.yml | 43 +++++- package.json | 2 +- .../minimal_runtime_worker_externs.js | 0 src/compiler.js | 53 +++---- src/emrun_prejs.js | 2 +- src/jsifier.js | 144 +++++++++--------- src/modules.js | 102 ++++++------- src/runtime.js | 17 ++- src/utility.js | 65 ++++---- tools/building.py | 2 +- tools/preprocessor.js | 30 ++-- 11 files changed, 250 insertions(+), 210 deletions(-) rename src/{ => closure-externs}/minimal_runtime_worker_externs.js (100%) diff --git a/.eslintrc.yml b/.eslintrc.yml index 90ac440a873d2..fcd8d1a08ce7e 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -6,7 +6,48 @@ extends: - google parserOptions: ecmaVersion: 12 -ignorePatterns: "library_*.js" +ignorePatterns: + - "site/" + - "third_party/" + - "tests/" + - "src/library*.js" + - "src/runtime_*.js" + - "src/shell*.js" + - "src/preamble*.js" + - "src/postamble*.js" + - "src/closure-externs/" + - "src/embind/" + - "src/emrun_postjs.js" + - "src/worker.js" + - "src/wrtcp.js" + - "src/wasm2js.js" + - "src/webGLClient.js" + - "src/webGLWorker.js" + - "src/*_shell_read.js" + - "src/wasm_offset_converter.js" + - "src/threadprofiler.js" + - "src/cpuprofiler.js" + - "src/memoryprofiler.js" + - "src/support.js" + - "src/gl-matrix.js" + - "src/promise_polyfill.js" + - "src/headless.js" + - "src/headlessCanvas.js" + - "src/socket.io.js" + - "src/emscripten-source-map.min.js" + - "src/source_map_support.js" + - "src/Fetch.js" + - "src/settings.js" + - "src/settings_internal.js" + - "src/arrayUtils.js" + - "src/deterministic.js" + - "src/base64Utils.js" + - "src/base64Decode.js" + - "src/proxyWorker.js" + - "src/proxyClient.js" + - "src/IDBStore.js" + - "src/URIUtils.js" + - "tools/experimental" rules: #max-len: ["error", 100] max-len: "off" diff --git a/package.json b/package.json index 58e3b4487ca2e..683a0c4b43f10 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,6 @@ "wasm2c": "1.0.0" }, "scripts": { - "lint": "eslint src/parseTools.js tools/acorn-optimizer.js tools/lz4-compress.js" + "lint": "eslint ." } } diff --git a/src/minimal_runtime_worker_externs.js b/src/closure-externs/minimal_runtime_worker_externs.js similarity index 100% rename from src/minimal_runtime_worker_externs.js rename to src/closure-externs/minimal_runtime_worker_externs.js diff --git a/src/compiler.js b/src/compiler.js index 144f8b8df61b7..a7ccc26e16f45 100755 --- a/src/compiler.js +++ b/src/compiler.js @@ -7,21 +7,21 @@ // LLVM => JavaScript compiler, main entry point -var nodeFS = require('fs'); -nodePath = require('path'); +global.nodeFS = require('fs'); +global.nodePath = require('path'); -print = (x) => { +global.print = (x) => { process['stdout'].write(x + '\n'); }; -printErr = (x) => { +global.printErr = (x) => { process['stderr'].write(x + '\n'); }; function find(filename) { - var prefixes = [__dirname, process.cwd()]; - for (var i = 0; i < prefixes.length; ++i) { - var combined = nodePath.join(prefixes[i], filename); + const prefixes = [__dirname, process.cwd()]; + for (let i = 0; i < prefixes.length; ++i) { + const combined = nodePath.join(prefixes[i], filename); if (nodeFS.existsSync(combined)) { return combined; } @@ -29,8 +29,8 @@ function find(filename) { return filename; } -read = (filename) => { - var absolute = find(filename); +global.read = (filename) => { + const absolute = find(filename); return nodeFS.readFileSync(absolute).toString(); }; @@ -45,22 +45,23 @@ load('utility.js'); load('./settings.js'); load('./settings_internal.js'); -var arguments_ = process['argv'].slice(2); -var settingsFile = arguments_[0]; +const settingsFile = process['argv'][2]; if (settingsFile) { - var settings = JSON.parse(read(settingsFile)); - for (var key in settings) { - var value = settings[key]; - if (value[0] == '@') { - // response file type thing, workaround for large inputs: value is @path-to-file - try { - value = JSON.parse(read(value.substr(1))); - } catch(e) { - // continue normally; assume it is not a response file + const settings = JSON.parse(read(settingsFile)); + for (const key in settings) { + if (Object.prototype.hasOwnProperty.call(settings, key)) { + let value = settings[key]; + if (value[0] == '@') { + // response file type thing, workaround for large inputs: value is @path-to-file + try { + value = JSON.parse(read(value.substr(1))); + } catch (e) { + // continue normally; assume it is not a response file + } } + global[key] = eval(JSON.stringify(value)); } - global[key] = eval(JSON.stringify(value)); } } @@ -72,7 +73,7 @@ INCOMING_MODULE_JS_API = new Set(INCOMING_MODULE_JS_API); RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG || DYLINK_DEBUG || PTHREADS_DEBUG; // Side modules are pure wasm and have no JS -assert(!SIDE_MODULE, "JS compiler should not run on side modules"); +assert(!SIDE_MODULE, 'JS compiler should not run on side modules'); // Output some info and warnings based on settings @@ -87,17 +88,17 @@ load('parseTools.js'); load('jsifier.js'); load('runtime.js'); -//=============================== +// =============================== // Main -//=============================== +// =============================== B = new Benchmarker(); try { - JSify(); + runJSify(); B.print('glue'); -} catch(err) { +} catch (err) { if (err.toString().includes('Aborting compilation due to previous errors')) { // Compiler failed on user error, don't print the stacktrace in this case. printErr(err); diff --git a/src/emrun_prejs.js b/src/emrun_prejs.js index 9f20035b0a08c..c4b0aee4bbb41 100644 --- a/src/emrun_prejs.js +++ b/src/emrun_prejs.js @@ -5,7 +5,7 @@ */ // Route URL GET parameters to argc+argv -if (typeof window === "object") { +if (typeof window === 'object') { Module['arguments'] = window.location.search.substr(1).trim().split('&'); // If no args were passed arguments = [''], in which case kill the single empty string. if (!Module['arguments'][0]) { diff --git a/src/jsifier.js b/src/jsifier.js index c580fd433bf30..dca06f1f7b221 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -4,16 +4,16 @@ * SPDX-License-Identifier: MIT */ -//"use strict"; +// "use strict"; // Convert analyzed data to javascript. Everything has already been calculated // before this stage, which just does the final conversion to JavaScript. -var addedLibraryItems = {}; +global.addedLibraryItems = {}; // Some JS-implemented library functions are proxied to be called on the main browser thread, if the Emscripten runtime is executing in a Web Worker. // Each such proxied function is identified via an ordinal number (this is not the same namespace as function pointers in general). -var proxiedFunctionTable = ["null" /* Reserve index 0 for an undefined function*/]; +global.proxiedFunctionTable = ['null'/* Reserve index 0 for an undefined function*/]; // Mangles the given C/JS side function name to assembly level function name (adds an underscore) function mangleCSymbolName(f) { @@ -22,9 +22,9 @@ function mangleCSymbolName(f) { // Splits out items that pass filter. Returns also the original sans the filtered function splitter(array, filter) { - var splitOut = array.filter(filter); - var leftIn = array.filter((x) => !filter(x)); - return { leftIn: leftIn, splitOut: splitOut }; + const splitOut = array.filter(filter); + const leftIn = array.filter((x) => !filter(x)); + return {leftIn: leftIn, splitOut: splitOut}; } // Functions that start with '$' should not be exported to the wasm module. @@ -62,11 +62,11 @@ function isDefined(symName) { } // JSifier -function JSify(functionsOnly) { - var mainPass = !functionsOnly; - var functionStubs = []; +function runJSify(functionsOnly) { + const mainPass = !functionsOnly; + const functionStubs = []; - var itemsDict = { type: [], functionStub: [], function: [], globalVariablePostSet: [] }; + const itemsDict = {type: [], functionStub: [], function: [], globalVariablePostSet: []}; if (mainPass) { // Add additional necessary items for the main pass. We can now do this since types are parsed (types can be used through @@ -74,9 +74,9 @@ function JSify(functionsOnly) { LibraryManager.load(); - var libFuncsToInclude = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE; + const libFuncsToInclude = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE; if (INCLUDE_FULL_LIBRARY) { - for (var key in LibraryManager.library) { + for (const key in LibraryManager.library) { if (!isJsLibraryConfigIdentifier(key)) { libFuncsToInclude.push(key); } @@ -85,7 +85,7 @@ function JSify(functionsOnly) { libFuncsToInclude.forEach((ident) => { functionStubs.push({ identOrig: ident, - identMangled: mangleCSymbolName(ident) + identMangled: mangleCSymbolName(ident), }); }); } @@ -94,23 +94,21 @@ function JSify(functionsOnly) { // It is possible that when printing the function as a string on Windows, the js interpreter we are in returns the string with Windows // line endings \r\n. This is undesirable, since line endings are managed in the form \n in the output for binary file writes, so // make sure the endings are uniform. - snippet = snippet.toString().replace(/\r\n/gm,'\n'); + snippet = snippet.toString().replace(/\r\n/gm, '\n'); // name the function; overwrite if it's already named snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function ' + finalName + '('); // apply LIBRARY_DEBUG if relevant if (LIBRARY_DEBUG && !isJsOnlyIdentifier(ident)) { - snippet = modifyFunction(snippet, (name, args, body) => { - return `\ + snippet = modifyFunction(snippet, (name, args, body) => `\ function ${name}(${args}) { var ret = (function() { if (runtimeDebug) err("[library call:${finalName}: " + Array.prototype.slice.call(arguments).map(prettyPrint) + "]"); ${body} }).apply(this, arguments); if (runtimeDebug && typeof ret !== "undefined") err(" [ return:" + prettyPrint(ret)); return ret; -}` - }); +}`); } return snippet; } @@ -125,7 +123,7 @@ function ${name}(${args}) { error('DISABLE_EXCEPTION_THROWING was set (likely due to -fno-exceptions), which means no C++ exception throwing support code is linked in, but exception catching code appears. Either do not set DISABLE_EXCEPTION_THROWING (if you do want exception throwing) or compile all source files with -fno-except (so that no exceptions support code is required); also make sure DISABLE_EXCEPTION_CATCHING is set to the right value - if you want exceptions, it should be off, and vice versa.'); return; } - var num = +item.identMangled.split('_').slice(-1)[0]; + const num = +item.identMangled.split('_').slice(-1)[0]; addCxaCatch(num); // Continue, with the code below emitting the proper JavaScript based on // what we just added to the library. @@ -137,8 +135,8 @@ function ${name}(${args}) { // dependencies can be JS functions, which we just run if (typeof item == 'function') return item(); - var ident = item.identOrig; - var finalName = item.identMangled; + const ident = item.identOrig; + const finalName = item.identMangled; if (ident in addedLibraryItems) return ''; addedLibraryItems[ident] = true; @@ -153,22 +151,22 @@ function ${name}(${args}) { return ''; } - var noExport = false; + let noExport = false; if (!LibraryManager.library.hasOwnProperty(ident)) { if (ONLY_CALC_JS_SYMBOLS) { return; } if (!isDefined(ident)) { - var msg = 'undefined symbol: ' + ident; + let msg = 'undefined symbol: ' + ident; if (dependent) msg += ` (referenced by ${dependent})`; if (ERROR_ON_UNDEFINED_SYMBOLS) { error(msg); if (dependent == TOP_LEVEL && !LLD_REPORT_UNDEFINED) { warnOnce('Link with `-s LLD_REPORT_UNDEFINED` to get more information on undefined symbols'); } - warnOnce('To disable errors for undefined symbols use `-s ERROR_ON_UNDEFINED_SYMBOLS=0`') - warnOnce(finalName + ' may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library') + warnOnce('To disable errors for undefined symbols use `-s ERROR_ON_UNDEFINED_SYMBOLS=0`'); + warnOnce(finalName + ' may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library'); } else if (VERBOSE || WARN_ON_UNDEFINED_SYMBOLS) { warn(msg); } @@ -184,41 +182,39 @@ function ${name}(${args}) { // (not useful to warn/error multiple times) LibraryManager.library[ident + '__docs'] = '/** @type {function(...*):?} */'; } else { - var target = `Module['${finalName}']`; - var assertion = ''; + const target = `Module['${finalName}']`; + let assertion = ''; if (ASSERTIONS) { - var what = 'function'; assertion += `if (!${target}) abort("external symbol '${ident}' is missing. perhaps a side module was not linked in? if this function was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment");\n`; - } - var functionBody = assertion + `return ${target}.apply(null, arguments);`; + const functionBody = assertion + `return ${target}.apply(null, arguments);`; LibraryManager.library[ident] = new Function(functionBody); noExport = true; } } - var original = LibraryManager.library[ident]; - var snippet = original; - var redirectedIdent = null; - var deps = LibraryManager.library[ident + '__deps'] || []; + const original = LibraryManager.library[ident]; + let snippet = original; + let redirectedIdent = null; + const deps = LibraryManager.library[ident + '__deps'] || []; if (!Array.isArray(deps)) { error(`JS library directive ${ident}__deps=${deps.toString()} is of type ${typeof deps}, but it should be an array!`); return; } - var isUserSymbol = LibraryManager.library[ident + '__user']; + const isUserSymbol = LibraryManager.library[ident + '__user']; deps.forEach((dep) => { if (typeof snippet === 'string' && !(dep in LibraryManager.library)) { warn(`missing library dependency ${dep}, make sure you are compiling with the right options (see #if in src/library*.js)`); } if (isUserSymbol && LibraryManager.library[dep + '__internal']) { - warn(`user library symbol '${ident}' depends on internal symbol '${dep}'`) + warn(`user library symbol '${ident}' depends on internal symbol '${dep}'`); } }); - var isFunction = false; + let isFunction = false; if (typeof snippet === 'string') { if (snippet[0] != '=') { - var target = LibraryManager.library[snippet]; + 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. @@ -246,11 +242,12 @@ function ${name}(${args}) { libraryFunctions.push(finalName); } - if (ONLY_CALC_JS_SYMBOLS) + if (ONLY_CALC_JS_SYMBOLS) { return ''; + } - var postsetId = ident + '__postset'; - var postset = LibraryManager.library[postsetId]; + const postsetId = ident + '__postset'; + let postset = LibraryManager.library[postsetId]; if (postset) { // A postset is either code to run right now, or some text we should emit. // If it's code, it may return some text to emit as well. @@ -260,7 +257,7 @@ function ${name}(${args}) { if (postset && !addedLibraryItems[postsetId]) { addedLibraryItems[postsetId] = true; itemsDict.globalVariablePostSet.push({ - JS: postset + ';' + JS: postset + ';', }); } } @@ -271,41 +268,37 @@ function ${name}(${args}) { if (VERBOSE) { printErr(`adding ${finalName} and deps ${deps} : ` + (snippet + '').substr(0, 40)); } - var identDependents = ident + "__deps: ['" + deps.join("','")+"']"; + const identDependents = ident + "__deps: ['" + deps.join("','") + "']"; function addDependency(dep) { if (typeof dep !== 'function') { dep = {identOrig: dep, identMangled: mangleCSymbolName(dep)}; } return addFromLibrary(dep, `${identDependents}, referenced by ${dependent}`); } - var contentText; + let contentText; if (isFunction) { // Emit the body of a JS library function. - var proxyingMode = LibraryManager.library[ident + '__proxy']; + const proxyingMode = LibraryManager.library[ident + '__proxy']; if (USE_PTHREADS && proxyingMode) { if (proxyingMode !== 'sync' && proxyingMode !== 'async') { - throw `Invalid proxyingMode ${ident}__proxy: '${proxyingMode}' specified!`; + throw new Error(`Invalid proxyingMode ${ident}__proxy: '${proxyingMode}' specified!`); } - var sync = proxyingMode === 'sync'; + const sync = proxyingMode === 'sync'; assert(typeof original === 'function'); - contentText = modifyFunction(snippet, (name, args, body) => { - return ` + contentText = modifyFunction(snippet, (name, args, body) => ` function ${name}(${args}) { if (ENVIRONMENT_IS_PTHREAD) return _emscripten_proxy_to_main_thread_js(${proxiedFunctionTable.length}, ${+sync}${args ? ', ' : ''}${args}); ${body} -}\n`; - }); +}\n`); proxiedFunctionTable.push(finalName); } else if ((USE_ASAN || USE_LSAN || UBSAN_RUNTIME) && LibraryManager.library[ident + '__noleakcheck']) { - contentText = modifyFunction(snippet, (name, args, body) => { - return ` + contentText = modifyFunction(snippet, (name, args, body) => ` function ${name}(${args}) { return withBuiltinMalloc(function() { ${body} }); -}\n`; - }); +}\n`); deps.push('$withBuiltinMalloc'); } else { contentText = snippet; // Regular JS function that will be executed in the context of the calling thread. @@ -316,7 +309,7 @@ function ${name}(${args}) { // emits // 'var foo;[code here verbatim];' contentText = 'var ' + finalName + snippet; - if (snippet[snippet.length-1] != ';' && snippet[snippet.length-1] != '}') contentText += ';'; + if (snippet[snippet.length - 1] != ';' && snippet[snippet.length - 1] != '}') contentText += ';'; } else { // In JS libraries // foo: '=[value]' @@ -325,7 +318,7 @@ function ${name}(${args}) { if (typeof snippet === 'string' && snippet[0] == '=') snippet = snippet.substr(1); contentText = `var ${finalName} = ${snippet};`; } - var sig = LibraryManager.library[ident + '__sig']; + const sig = LibraryManager.library[ident + '__sig']; // asm module exports are done in emscripten.py, after the asm module is ready. Here // we also export library methods as necessary. if ((EXPORT_ALL || EXPORTED_FUNCTIONS.has(finalName)) && !noExport) { @@ -335,12 +328,12 @@ function ${name}(${args}) { contentText += `\n${finalName}.sig = '${sig}';`; } - var commentText = ''; + let commentText = ''; if (LibraryManager.library[ident + '__docs']) { commentText = LibraryManager.library[ident + '__docs'] + '\n'; } - var depsText = (deps ? deps.map(addDependency).filter((x) => x != '').join('\n') + '\n' : ''); + const depsText = (deps ? deps.map(addDependency).filter((x) => x != '').join('\n') + '\n' : ''); return depsText + commentText + contentText; } @@ -351,15 +344,15 @@ function ${name}(${args}) { // Final combiner function finalCombiner() { - var splitPostSets = splitter(itemsDict.globalVariablePostSet, (x) => x.ident && x.dependencies); + const splitPostSets = splitter(itemsDict.globalVariablePostSet, (x) => x.ident && x.dependencies); itemsDict.globalVariablePostSet = splitPostSets.leftIn; - var orderedPostSets = splitPostSets.splitOut; + const orderedPostSets = splitPostSets.splitOut; - var limit = orderedPostSets.length * orderedPostSets.length; - for (var i = 0; i < orderedPostSets.length; i++) { - for (var j = i+1; j < orderedPostSets.length; j++) { + let limit = orderedPostSets.length * orderedPostSets.length; + for (let i = 0; i < orderedPostSets.length; i++) { + for (let j = i + 1; j < orderedPostSets.length; j++) { if (orderedPostSets[j].ident in orderedPostSets[i].dependencies) { - var temp = orderedPostSets[i]; + const temp = orderedPostSets[i]; orderedPostSets[i] = orderedPostSets[j]; orderedPostSets[j] = temp; i--; @@ -375,16 +368,16 @@ function ${name}(${args}) { // if (!mainPass) { - var generated = itemsDict.function.concat(itemsDict.type); + const generated = itemsDict.function.concat(itemsDict.type); print(generated.map((item) => item.JS).join('\n')); return; } - var shellFile = SHELL_FILE ? SHELL_FILE : (MINIMAL_RUNTIME ? 'shell_minimal.js' : 'shell.js'); + const shellFile = SHELL_FILE ? SHELL_FILE : (MINIMAL_RUNTIME ? 'shell_minimal.js' : 'shell.js'); - var shellParts = read(shellFile).split('{{BODY}}'); + const shellParts = read(shellFile).split('{{BODY}}'); print(processMacros(preprocess(shellParts[0], shellFile))); - var pre; + let pre; if (MINIMAL_RUNTIME) { pre = processMacros(preprocess(read('preamble_minimal.js'), 'preamble_minimal.js')); } else { @@ -394,18 +387,18 @@ function ${name}(${args}) { print(pre); // Print out global variables and postsets TODO: batching - var legalizedI64sDefault = legalizedI64s; + const legalizedI64sDefault = legalizedI64s; legalizedI64s = false; - JSify(true); + runJSify(true); - var generated = itemsDict.functionStub.concat(itemsDict.globalVariablePostSet); + const generated = itemsDict.functionStub.concat(itemsDict.globalVariablePostSet); generated.forEach((item) => print(indentify(item.JS || '', 2))); legalizedI64s = legalizedI64sDefault; if (USE_PTHREADS) { - print('\n // proxiedFunctionTable specifies the list of functions that can be called either synchronously or asynchronously from other threads in postMessage()d or internally queued events. This way a pthread in a Worker can synchronously access e.g. the DOM on the main thread.') + print('\n // proxiedFunctionTable specifies the list of functions that can be called either synchronously or asynchronously from other threads in postMessage()d or internally queued events. This way a pthread in a Worker can synchronously access e.g. the DOM on the main thread.'); print('\nvar proxiedFunctionTable = [' + proxiedFunctionTable.join() + '];\n'); } @@ -443,11 +436,10 @@ function ${name}(${args}) { print(read('deterministic.js')); } - var postFile = MINIMAL_RUNTIME ? 'postamble_minimal.js' : 'postamble.js'; - var post = processMacros(preprocess(read(postFile), postFile)); + const postFile = MINIMAL_RUNTIME ? 'postamble_minimal.js' : 'postamble.js'; + const post = processMacros(preprocess(read(postFile), postFile)); print(post); - var shellParts = read(shellFile).split('{{BODY}}'); print(processMacros(preprocess(shellParts[1], shellFile))); print('\n//FORWARDED_DATA:' + JSON.stringify({ diff --git a/src/modules.js b/src/modules.js index 37014e62a8e97..3adfa79c8d49e 100644 --- a/src/modules.js +++ b/src/modules.js @@ -4,25 +4,23 @@ * SPDX-License-Identifier: MIT */ -//"use strict"; +// "use strict"; // Various namespace-like modules -var STACK_ALIGN = 16; - // Constructs an array ['a0', 'a1', 'a2', ..., 'a(n-1)'] function genArgSequence(n) { - var args = []; - for (var i = 0; i < n; ++i) { - args.push('a'+i); + const args = []; + for (let i = 0; i < n; ++i) { + args.push('a' + i); } return args; } // List of functions that were added from the library. -var libraryFunctions = []; +global.libraryFunctions = []; -var LibraryManager = { +global.LibraryManager = { library: null, structs: {}, loaded: false, @@ -36,7 +34,7 @@ var LibraryManager = { if (this.library) return; // Core system libraries (always linked against) - var libraries = [ + let libraries = [ 'library.js', 'library_formatString.js', 'library_math.js', @@ -93,7 +91,7 @@ var LibraryManager = { } } else if (WASMFS) { libraries.push('library_wasmfs.js'); - } + } // Additional JS libraries (without AUTO_JS_LIBRARIES, link to these explicitly via -lxxx.js) if (AUTO_JS_LIBRARIES) { @@ -109,7 +107,7 @@ var LibraryManager = { 'library_uuid.js', 'library_glew.js', 'library_idbstore.js', - 'library_async.js' + 'library_async.js', ]); } else { if (ASYNCIFY) { @@ -171,8 +169,8 @@ var LibraryManager = { // Save the list for has() queries later. this.libraries = libraries; - for (var filename of libraries) { - var isUserLibrary = nodePath.isAbsolute(filename); + for (const filename of libraries) { + const isUserLibrary = nodePath.isAbsolute(filename); if (VERBOSE) { if (isUserLibrary) { printErr('processing user library: ' + filename); @@ -180,43 +178,43 @@ var LibraryManager = { printErr('processing system library: ' + filename); } } - var src = read(filename); - var origLibrary = undefined; - var processed = undefined; + const src = read(filename); + let origLibrary = undefined; + let processed = undefined; // When we parse user libraries also set `__user` attribute // on each element so that we can distinguish them later. if (isUserLibrary) { - origLibrary = this.library + origLibrary = this.library; this.library = new Proxy(this.library, { set: (target, prop, value) => { target[prop] = value; if (!isJsLibraryConfigIdentifier(prop)) { target[prop + '__user'] = true; } - } + }, }); } try { processed = processMacros(preprocess(src, filename)); eval(processed); - } catch(e) { - var details = [e, e.lineNumber ? `line number: ${e.lineNumber}` : '']; + } catch (e) { + const details = [e, e.lineNumber ? `line number: ${e.lineNumber}` : '']; if (VERBOSE) { - details.push((e.stack || "").toString().replace('Object.', filename)); + details.push((e.stack || '').toString().replace('Object.', filename)); } if (processed) { error(`failure to execute js library "${filename}": ${details}`); if (VERBOSE) { error(`preprocessed source (you can run a js engine on this to get a clearer error message sometimes):\n=============\n${processed}\n=============`); } else { - error('use -s VERBOSE to see more details') + error('use -s VERBOSE to see more details'); } } else { error(`failure to process js library "${filename}": ${details}`); if (VERBOSE) { error(`original source:\n=============\n${src}\n=============`); } else { - error('use -s VERBOSE to see more details') + error('use -s VERBOSE to see more details'); } } throw e; @@ -230,18 +228,21 @@ var LibraryManager = { // apply synonyms. these are typically not speed-sensitive, and doing it // this way makes it possible to not include hacks in the compiler // (and makes it simpler to switch between SDL versions, fastcomp and non-fastcomp, etc.). - var lib = this.library; - libloop: for (var x in lib) { + const lib = this.library; + libloop: for (const x in lib) { + if (!Object.prototype.hasOwnProperty.call(lib, x)) { + continue; + } if (isJsLibraryConfigIdentifier(x)) { - var index = x.lastIndexOf('__'); - var basename = x.slice(0, index); + const index = x.lastIndexOf('__'); + const basename = x.slice(0, index); if (!(basename in lib)) { error(`Missing library element '${basename}' for library config '${x}'`); } continue; } if (typeof lib[x] === 'string') { - var target = x; + let target = x; while (typeof lib[target] === 'string') { // ignore code and variable assignments, aliases are just simple names if (lib[target].search(/[=({; ]/) >= 0) continue libloop; @@ -257,15 +258,15 @@ var LibraryManager = { error(`${sig} should be a string! (was ${typeof lib[sig]})`); } } - var aliasSig = x + '__sig'; - var targetSig = target + '__sig'; + const aliasSig = x + '__sig'; + const targetSig = target + '__sig'; testStringType(aliasSig); testStringType(targetSig); if (typeof lib[aliasSig] === 'string' && typeof lib[targetSig] === 'string' && lib[aliasSig] != lib[targetSig]) { error(`${aliasSig} (${lib[aliasSig]}) differs from ${targetSig} (${lib[targetSig]})`); } - var sig = lib[aliasSig] || lib[targetSig]; + const sig = lib[aliasSig] || lib[targetSig]; if (typeof sig !== 'string') { error(`Function ${x} aliases to target function ${target}, but neither the alias or the target provide a signature. Please add a ${targetSig}: 'vifj...' annotation or a ${aliasSig}: 'vifj...' annotation to describe the type of function forwarding that is needed!`); } @@ -282,12 +283,12 @@ var LibraryManager = { error(`no alias found for ${x}`); } - var argCount = sig.length - 1; + const argCount = sig.length - 1; if (argCount !== lib[target].length) { error(`incorrect number of arguments in signature of ${x} (declared: ${argCount}, expected: ${lib[target].length})`); } - var ret = sig == 'v' ? '' : 'return '; - var args = genArgSequence(argCount).join(','); + const ret = sig == 'v' ? '' : 'return '; + const args = genArgSequence(argCount).join(','); lib[x] = new Function(args, `${ret}_${target}(${args});`); if (!lib[x + '__deps']) lib[x + '__deps'] = []; @@ -302,7 +303,7 @@ var LibraryManager = { if (!BOOTSTRAPPING_STRUCT_INFO) { // Load struct and define information. - var temp = JSON.parse(read(STRUCT_INFO)); + const temp = JSON.parse(read(STRUCT_INFO)); C_STRUCTS = temp.structs; C_DEFINES = temp.defines; } else { @@ -313,7 +314,7 @@ if (!BOOTSTRAPPING_STRUCT_INFO) { // Safe way to access a C define. We check that we don't add library functions with missing defines. function cDefine(key) { if (key in C_DEFINES) return C_DEFINES[key]; - throw `Missing C define ${key}! If you just added it to struct_info.json, you need to ./emcc --clear-cache`; + throw new Error(`Missing C define ${key}! If you just added it to struct_info.json, you need to ./emcc --clear-cache`); } function isFSPrefixed(name) { @@ -334,7 +335,7 @@ function isExportedByForceFilesystem(name) { // export parts of the JS runtime that the user asked for function exportRuntime() { - var EXPORTED_RUNTIME_METHODS_SET = new Set(EXPORTED_RUNTIME_METHODS); + const EXPORTED_RUNTIME_METHODS_SET = new Set(EXPORTED_RUNTIME_METHODS); // optionally export something. // in ASSERTIONS mode we show a useful error if it is used without @@ -343,7 +344,7 @@ function exportRuntime() { function maybeExport(name, isNumber) { // if requested to be exported, export it if (EXPORTED_RUNTIME_METHODS_SET.has(name)) { - var exported = name; + let exported = name; // the exported name may differ from the internal name if (isFSPrefixed(exported)) { // this is a filesystem value, FS.x exported as FS_x @@ -362,7 +363,7 @@ function exportRuntime() { // check if it already exists, to support EXPORT_ALL and other cases // (we could optimize this, but in ASSERTIONS mode code size doesn't // matter anyhow) - var extra = ''; + let extra = ''; if (isExportedByForceFilesystem(name)) { extra = '. Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you'; } @@ -380,7 +381,7 @@ function exportRuntime() { } // All possible runtime elements that can be exported - var runtimeElements = [ + let runtimeElements = [ 'intArrayFromString', 'intArrayToString', 'ccall', @@ -441,7 +442,7 @@ function exportRuntime() { // Add JS library elements such as FS, GL, ENV, etc. These are prefixed with // '$ which indicates they are JS methods. - for (var ident in LibraryManager.library) { + for (const ident in LibraryManager.library) { if (ident[0] === '$' && !isJsLibraryConfigIdentifier(ident)) { runtimeElements.push(ident.substr(1)); } @@ -463,9 +464,8 @@ function exportRuntime() { 'stringToUTF32', 'lengthBytesUTF32', 'allocateUTF8', - 'allocateUTF8OnStack' + 'allocateUTF8OnStack', ]); - } if (STACK_OVERFLOW_CHECK) { @@ -477,12 +477,12 @@ function exportRuntime() { // In pthreads mode, the following functions always need to be exported to // Module for closure compiler, and also for MODULARIZE (so worker.js can // access them). - var threadExports = ['PThread', 'wasmMemory']; + const threadExports = ['PThread', 'wasmMemory']; if (!MINIMAL_RUNTIME) { threadExports.push('ExitStatus'); } - threadExports.forEach(x => { + threadExports.forEach((x) => { EXPORTED_RUNTIME_METHODS_SET.add(x); runtimeElements.push(x); }); @@ -495,26 +495,26 @@ function exportRuntime() { // dynCall_* methods are not hardcoded here, as they // depend on the file being compiled. check for them // and add them. - for (var name of EXPORTED_RUNTIME_METHODS_SET) { + for (const name of EXPORTED_RUNTIME_METHODS_SET) { if (/^dynCall_/.test(name)) { // a specific dynCall; add to the list runtimeElements.push(name); } } - var runtimeNumbers = [ + const runtimeNumbers = [ 'ALLOC_NORMAL', 'ALLOC_STACK', ]; if (ASSERTIONS) { // check all exported things exist, warn about typos - for (var name of EXPORTED_RUNTIME_METHODS_SET) { + for (const name of EXPORTED_RUNTIME_METHODS_SET) { if (!runtimeElements.includes(name) && !runtimeNumbers.includes(name)) { printErr(`warning: invalid item (maybe a typo?) in EXPORTED_RUNTIME_METHODS: ${name}`); } } } - var exports = runtimeElements.map(name => maybeExport(name)); - exports = exports.concat(runtimeNumbers.map(name => maybeExportNumber(name))); - exports = exports.filter(name => name != ''); + let exports = runtimeElements.map((name) => maybeExport(name)); + exports = exports.concat(runtimeNumbers.map((name) => maybeExportNumber(name))); + exports = exports.filter((name) => name != ''); return exports.join('\n'); } diff --git a/src/runtime.js b/src/runtime.js index 48e132cb09243..f2ac78e50c803 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -4,12 +4,13 @@ * SPDX-License-Identifier: MIT */ -//"use strict"; +// "use strict"; // code used both at compile time and runtime is defined here, then put on // the Runtime object for compile time and support.js for the generated code -const POINTER_SIZE = MEMORY64 ? 8 : 4; +global.POINTER_SIZE = MEMORY64 ? 8 : 4; +global.STACK_ALIGN = 16; function getNativeTypeSize(type) { switch (type) { @@ -20,10 +21,10 @@ function getNativeTypeSize(type) { case 'float': return 4; case 'double': return 8; default: { - if (type[type.length-1] === '*') { + if (type[type.length - 1] === '*') { return POINTER_SIZE; } else if (type[0] === 'i') { - var bits = Number(type.substr(1)); + const bits = Number(type.substr(1)); assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type); return bits / 8; } else { @@ -33,12 +34,12 @@ function getNativeTypeSize(type) { } } -var Runtime = { +global.Runtime = { getNativeTypeSize: getNativeTypeSize, - //! TODO(sbc): This function is unused by emscripten but we can't be - //! sure there are not external users. - //! See: https://github.com/emscripten-core/emscripten/issues/15242 + // TODO(sbc): This function is unused by emscripten but we can't be + // sure there are not external users. + // See: https://github.com/emscripten-core/emscripten/issues/15242 getNativeFieldSize: function(type) { return Math.max(getNativeTypeSize(type), Runtime.QUANTUM_SIZE); }, diff --git a/src/utility.js b/src/utility.js index e20e82b274720..11317f5abb644 100644 --- a/src/utility.js +++ b/src/utility.js @@ -4,31 +4,33 @@ * SPDX-License-Identifier: MIT */ -//"use strict"; +// "use strict"; // General JS utilities - things that might be useful in any JS project. // Nothing specific to Emscripten appears here. function safeQuote(x) { - return x.replace(/"/g, '\\"') - .replace(/'/g, "\\'"); + return x.replace(/"/g, '\\"').replace(/'/g, "\\'"); } function dump(item) { + let funcData; try { if (typeof item == 'object' && item !== null && item.funcData) { - var funcData = item.funcData; + funcData = item.funcData; item.funcData = null; } return '// ' + JSON.stringify(item, null, ' ').replace(/\n/g, '\n// '); - } catch(e) { - var ret = []; - for (var i in item) { - var j = item[i]; - if (typeof j === 'string' || typeof j === 'number') { - ret.push(i + ': ' + j); - } else { - ret.push(i + ': [?]'); + } catch (e) { + const ret = []; + for (const i in item) { + if (Object.prototype.hasOwnProperty.call(item, i)) { + const j = item[i]; + if (typeof j === 'string' || typeof j === 'number') { + ret.push(i + ': ' + j); + } else { + ret.push(i + ': [?]'); + } } } return ret.join(',\n'); @@ -69,7 +71,7 @@ function warnOnce(a, msg) { } } -var abortExecution = false; +global.abortExecution = false; function error(msg) { abortExecution = true; @@ -77,24 +79,26 @@ function error(msg) { } function range(size) { - var ret = []; - for (var i = 0; i < size; i++) ret.push(i); + const ret = []; + for (let i = 0; i < size; i++) ret.push(i); return ret; } function bind(self, func) { - return function() { - func.apply(self, arguments); + return function(...args) { + func.apply(self, args); }; } function sum(x) { - return x.reduce(function(a,b) { return a+b }, 0); + return x.reduce((a, b) => a + b, 0); } function mergeInto(obj, other) { - for (var i in other) { - obj[i] = other[i]; + for (const i in other) { + if (Object.prototype.hasOwnProperty.call(other, i)) { + obj[i] = other[i]; + } } return obj; } @@ -122,33 +126,34 @@ function isJsLibraryConfigIdentifier(ident) { } function isPowerOfTwo(x) { - return x > 0 && ((x & (x-1)) == 0); + return x > 0 && ((x & (x - 1)) == 0); } function Benchmarker() { - var totals = {}; - var ids = [], lastTime = 0; + const totals = {}; + const ids = []; + const lastTime = 0; this.start = function(id) { - var now = Date.now(); + const now = Date.now(); if (ids.length > 0) { - totals[ids[ids.length-1]] += now - lastTime; + totals[ids[ids.length - 1]] += now - lastTime; } lastTime = now; ids.push(id); totals[id] = totals[id] || 0; }; this.stop = function(id) { - var now = Date.now(); - assert(id === ids[ids.length-1]); + const now = Date.now(); + assert(id === ids[ids.length - 1]); totals[id] += now - lastTime; lastTime = now; ids.pop(); }; this.print = function(text) { - var ids = Object.keys(totals); + const ids = Object.keys(totals); if (ids.length > 0) { - ids.sort(function(a, b) { return totals[b] - totals[a] }); - printErr(text + ' times: \n' + ids.map(function(id) { return id + ' : ' + totals[id] + ' ms' }).join('\n')); + ids.sort((a, b) => totals[b] - totals[a]); + printErr(text + ' times: \n' + ids.map((id) => id + ' : ' + totals[id] + ' ms').join('\n')); } }; } diff --git a/tools/building.py b/tools/building.py index 3d75a12f8dab8..75b25a470c051 100644 --- a/tools/building.py +++ b/tools/building.py @@ -795,7 +795,7 @@ def closure_compiler(filename, pretty, advanced=True, extra_closure_args=None): CLOSURE_EXTERNS += [path_from_root('src/closure-externs/dyncall-externs.js')] if settings.MINIMAL_RUNTIME and settings.USE_PTHREADS: - CLOSURE_EXTERNS += [path_from_root('src/minimal_runtime_worker_externs.js')] + CLOSURE_EXTERNS += [path_from_root('src/closure-externs/minimal_runtime_worker_externs.js')] args = ['--compilation_level', 'ADVANCED_OPTIMIZATIONS' if advanced else 'SIMPLE_OPTIMIZATIONS'] # Keep in sync with ecmaVersion in tools/acorn-optimizer.js diff --git a/tools/preprocessor.js b/tools/preprocessor.js index b7e6b29e10163..23375b9a5bca5 100755 --- a/tools/preprocessor.js +++ b/tools/preprocessor.js @@ -13,11 +13,11 @@ // shell file This is the file that will be processed by the preprocessor -var fs = require('fs'); -var path = require('path'); +const fs = require('fs'); +const path = require('path'); -var arguments_ = process['argv'].slice(2); -var debug = false; +const arguments_ = process['argv'].slice(2); +const debug = false; print = function(x) { process['stdout'].write(x + '\n'); @@ -27,9 +27,9 @@ printErr = function(x) { }; function find(filename) { - var prefixes = [process.cwd(), path.join(__dirname, '..', 'src')]; - for (var i = 0; i < prefixes.length; ++i) { - var combined = path.join(prefixes[i], filename); + const prefixes = [process.cwd(), path.join(__dirname, '..', 'src')]; + for (let i = 0; i < prefixes.length; ++i) { + const combined = path.join(prefixes[i], filename); if (fs.existsSync(combined)) { return combined; } @@ -38,7 +38,7 @@ function find(filename) { } read = function(filename) { - var absolute = find(filename); + const absolute = find(filename); return fs.readFileSync(absolute).toString(); }; @@ -46,16 +46,16 @@ load = function(f) { eval.call(null, read(f)); }; -var settings_file = arguments_[0]; -var shell_file = arguments_[1]; -var process_macros = arguments_.includes('--expandMacros'); +const settingsFile = arguments_[0]; +const shellFile = arguments_[1]; +const expandMacros = arguments_.includes('--expandMacros'); -load(settings_file) +load(settingsFile); load('utility.js'); load('modules.js'); load('parseTools.js'); -var from_html = read(shell_file); -var to_html = process_macros ? processMacros(preprocess(from_html, shell_file)) : preprocess(from_html, shell_file); +const fromHTML = read(shellFile); +const toHTML = expandMacros ? processMacros(preprocess(fromHTML, shellFile)) : preprocess(fromHTML, shellFile); -print(to_html); +print(toHTML);