Skip to content

Commit 77133ba

Browse files
authored
Finish converting JS compiler to ES6 modules. NFC (#21542)
The compiler itself is now purely JS modules. As part of this change I create a new global context object in which all library code is processed. This allows is to have a clean separation between the compiler code itself and code being processed. Only symbols explicitly added to the macro context are available to JS library code.
1 parent 8236e54 commit 77133ba

File tree

8 files changed

+373
-183
lines changed

8 files changed

+373
-183
lines changed

ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ See docs/process.md for more on how version tagging works.
2020

2121
3.1.57 (in development)
2222
-----------------------
23+
- JS library code is now executed in its own context/scope, which limits how
24+
much of the compiler internals are accessible. If there are build time JS
25+
symbols that you are depending on, but that were not added to this scope,
26+
please file a bug and we can add more to this scope. (#21542)
2327

2428
3.1.56 - 03/14/24
2529
-----------------

src/compiler.mjs

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,9 @@
99

1010
import * as fs from 'fs';
1111
import * as path from 'path';
12-
import * as vm from 'vm';
1312
import * as url from 'url';
14-
import assert from 'assert';
1513

16-
globalThis.vm = vm;
17-
globalThis.assert = assert;
18-
globalThis.nodePath = path;
19-
20-
globalThis.print = (x) => {
21-
process.stdout.write(x + '\n');
22-
};
23-
24-
globalThis.printErr = (x) => {
25-
process.stderr.write(x + '\n');
26-
};
14+
import {Benchmarker, applySettings, assert, loadSettingsFile, printErr, read} from './utility.mjs';
2715

2816
function find(filename) {
2917
assert(filename);
@@ -38,22 +26,9 @@ function find(filename) {
3826
return filename;
3927
}
4028

41-
globalThis.read = (filename) => {
42-
assert(filename);
43-
const absolute = find(filename);
44-
return fs.readFileSync(absolute).toString();
45-
};
46-
47-
function load(f) {
48-
vm.runInThisContext(read(f), {filename: find(f)});
49-
}
50-
51-
// Basic utilities
52-
load('utility.js');
53-
5429
// Load default settings
55-
load('./settings.js');
56-
load('./settings_internal.js');
30+
loadSettingsFile(find('settings.js'));
31+
loadSettingsFile(find('settings_internal.js'));
5732

5833
const argv = process.argv.slice(2);
5934
const symbolsOnlyArg = argv.indexOf('--symbols-only');
@@ -64,11 +39,10 @@ if (symbolsOnlyArg != -1) {
6439
// Load settings from JSON passed on the command line
6540
const settingsFile = argv[0];
6641
assert(settingsFile);
42+
const user_settings = JSON.parse(read(settingsFile));
43+
applySettings(user_settings);
6744

68-
const settings = JSON.parse(read(settingsFile));
69-
Object.assign(global, settings);
70-
71-
globalThis.symbolsOnly = symbolsOnlyArg != -1;
45+
export const symbolsOnly = symbolsOnlyArg != -1;
7246

7347
// In case compiler.js is run directly (as in gen_sig_info)
7448
// ALL_INCOMING_MODULE_JS_API might not be populated yet.
@@ -88,18 +62,21 @@ if (symbolsOnly) {
8862

8963
// Side modules are pure wasm and have no JS
9064
assert(
91-
!SIDE_MODULE || (ASYNCIFY && globalThis.symbolsOnly),
65+
!SIDE_MODULE || (ASYNCIFY && symbolsOnly),
9266
'JS compiler should only run on side modules if asyncify is used.',
9367
);
9468

9569
// Load compiler code
9670

97-
load('modules.js');
98-
load('parseTools.js');
99-
load('jsifier.js');
71+
// We can't use static import statements here because several of these
72+
// file depend on having the settings defined in the global scope (which
73+
// we do dynamically above.
74+
await import('./modules.mjs');
75+
await import('./parseTools.mjs');
10076
if (!STRICT) {
101-
load('parseTools_legacy.js');
77+
await import('./parseTools_legacy.mjs');
10278
}
79+
const jsifier = await import('./jsifier.mjs');
10380

10481
// ===============================
10582
// Main
@@ -108,7 +85,7 @@ if (!STRICT) {
10885
const B = new Benchmarker();
10986

11087
try {
111-
runJSify();
88+
jsifier.runJSify(symbolsOnly);
11289

11390
B.print('glue');
11491
} catch (err) {

src/jsifier.js renamed to src/jsifier.mjs

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,46 @@
44
* SPDX-License-Identifier: MIT
55
*/
66

7-
// "use strict";
8-
97
// Convert analyzed data to javascript. Everything has already been calculated
108
// before this stage, which just does the final conversion to JavaScript.
119

12-
globalThis.addedLibraryItems = {};
13-
14-
globalThis.extraLibraryFuncs = [];
10+
import {
11+
ATEXITS,
12+
ATINITS,
13+
ATMAINS,
14+
defineI64Param,
15+
indentify,
16+
makeReturn64,
17+
modifyJSFunction,
18+
preprocess,
19+
processMacros,
20+
receiveI64ParamAsI53,
21+
} from './parseTools.mjs';
22+
import {
23+
addToCompileTimeContext,
24+
assert,
25+
error,
26+
errorOccured,
27+
isDecorator,
28+
isJsOnlySymbol,
29+
compileTimeContext,
30+
print,
31+
printErr,
32+
read,
33+
warn,
34+
warningOccured,
35+
} from './utility.mjs';
36+
import {LibraryManager, librarySymbols} from './modules.mjs';
37+
38+
const addedLibraryItems = {};
39+
40+
const extraLibraryFuncs = [];
1541

1642
// Some JS-implemented library functions are proxied to be called on the main
1743
// browser thread, if the Emscripten runtime is executing in a Web Worker.
1844
// Each such proxied function is identified via an ordinal number (this is not
1945
// the same namespace as function pointers in general).
20-
globalThis.proxiedFunctionTable = [];
46+
const proxiedFunctionTable = [];
2147

2248
// Mangles the given C/JS side function name to assembly level function name (adds an underscore)
2349
function mangleCSymbolName(f) {
@@ -121,7 +147,7 @@ function preJS() {
121147
return result;
122148
}
123149

124-
function runJSify() {
150+
export function runJSify(symbolsOnly) {
125151
const libraryItems = [];
126152
const symbolDeps = {};
127153
const asyncFuncs = [];
@@ -162,7 +188,6 @@ function runJSify() {
162188
.split(',')
163189
.map((name) => name.trim());
164190
const newArgs = [];
165-
let innerArgs = [];
166191
let argConversions = '';
167192
if (sig.length > argNames.length + 1) {
168193
error(`handleI64Signatures: signature too long for ${symbol}`);
@@ -188,7 +213,6 @@ function runJSify() {
188213
}
189214
}
190215

191-
var origArgs = args;
192216
if (!WASM_BIGINT) {
193217
args = newArgs.join(',');
194218
}
@@ -266,7 +290,7 @@ function(${args}) {
266290
((i53abi && sig.includes('j')) || ((MEMORY64 || CAN_ADDRESS_2GB) && sig.includes('p')))
267291
) {
268292
snippet = handleI64Signatures(symbol, snippet, sig, i53abi);
269-
i53ConversionDeps.forEach((d) => deps.push(d));
293+
compileTimeContext.i53ConversionDeps.forEach((d) => deps.push(d));
270294
}
271295

272296
const proxyingMode = LibraryManager.library[symbol + '__proxy'];
@@ -348,7 +372,7 @@ function(${args}) {
348372
if (!(symbol in LibraryManager.library)) {
349373
// Create a new __cxa_find_matching_catch variant on demand.
350374
const num = +symbol.split('_').slice(-1)[0];
351-
addCxaCatch(num);
375+
compileTimeContext.addCxaCatch(num);
352376
}
353377
// Continue, with the code below emitting the proper JavaScript based on
354378
// what we just added to the library.
@@ -376,7 +400,7 @@ function(${args}) {
376400
LibraryManager.library[symbol + '__deps'] = [];
377401
}
378402

379-
deps = LibraryManager.library[symbol + '__deps'];
403+
const deps = LibraryManager.library[symbol + '__deps'];
380404
let sig = LibraryManager.library[symbol + '__sig'];
381405
if (!WASM_BIGINT && sig && sig[0] == 'j') {
382406
// Without WASM_BIGINT functions that return i64 depend on setTempRet0
@@ -466,12 +490,11 @@ function(${args}) {
466490
// Create a stub for this symbol which can later be replaced by the
467491
// dynamic linker. If this stub is called before the symbol is
468492
// resolved assert in debug builds or trap in release builds.
493+
let target = `wasmImports['${symbol}']`;
469494
if (ASYNCIFY) {
470495
// See the definition of asyncifyStubs in preamble.js for why this
471496
// is needed.
472497
target = `asyncifyStubs['${symbol}']`;
473-
} else {
474-
target = `wasmImports['${symbol}']`;
475498
}
476499
let assertion = '';
477500
if (ASSERTIONS) {
@@ -536,8 +559,6 @@ function(${args}) {
536559
if (VERBOSE) {
537560
printErr(`adding ${symbol} (referenced by ${dependent})`);
538561
}
539-
const deps_list = deps.join("','");
540-
const identDependents = symbol + `__deps: ['${deps_list}']`;
541562
function addDependency(dep) {
542563
// dependencies can be JS functions, which we just run
543564
if (typeof dep == 'function') {
@@ -695,7 +716,7 @@ var proxiedFunctionTable = [
695716
`);
696717
}
697718

698-
if (abortExecution) {
719+
if (errorOccured()) {
699720
throw Error('Aborting compilation due to previous errors');
700721
}
701722

@@ -716,7 +737,7 @@ var proxiedFunctionTable = [
716737
'//FORWARDED_DATA:' +
717738
JSON.stringify({
718739
librarySymbols,
719-
warnings,
740+
warnings: warningOccured(),
720741
asyncFuncs,
721742
ATINITS: ATINITS.join('\n'),
722743
ATMAINS: STRICT ? '' : ATMAINS.join('\n'),
@@ -741,7 +762,13 @@ var proxiedFunctionTable = [
741762
finalCombiner();
742763
}
743764

744-
if (abortExecution) {
765+
if (errorOccured()) {
745766
throw Error('Aborting compilation due to previous errors');
746767
}
747768
}
769+
770+
addToCompileTimeContext({
771+
extraLibraryFuncs,
772+
addedLibraryItems,
773+
preJS,
774+
});

0 commit comments

Comments
 (0)