Skip to content

Commit 9e6ad5e

Browse files
committed
Remove remaining uses of eval in the JS compiler
Use `vm.runInCurrentContext` instead. We already use this in the preprocessor, but not we also use it for macro expansion and loading of the compiler code itself. This change should facilitate future changes to the JS compiler, such as changing the compiler itself to use JS modules.
1 parent e6be4f5 commit 9e6ad5e

File tree

5 files changed

+30
-38
lines changed

5 files changed

+30
-38
lines changed

src/compiler.mjs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,9 @@ globalThis.printErr = (x) => {
2828
function find(filename) {
2929
assert(filename);
3030
const dirname = url.fileURLToPath(new URL('.', import.meta.url));
31-
const prefixes = [dirname, process.cwd()];
32-
for (let i = 0; i < prefixes.length; ++i) {
33-
const combined = path.join(prefixes[i], filename);
34-
if (fs.existsSync(combined)) {
35-
return combined;
36-
}
31+
const combined = path.join(dirname, filename);
32+
if (fs.existsSync(combined)) {
33+
return combined;
3734
}
3835
return filename;
3936
}
@@ -45,8 +42,8 @@ globalThis.read = (filename) => {
4542
};
4643

4744
function load(f) {
48-
(0, eval)(read(f) + '//# sourceURL=' + find(f));
49-
};
45+
vm.runInThisContext(read(f), { filename: find(f) });
46+
}
5047

5148
// Basic utilities
5249
load('utility.js');

src/jsifier.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ function preJS() {
106106
let result = '';
107107
for (const fileName of PRE_JS_FILES) {
108108
if (shouldPreprocess(fileName)) {
109-
result += processMacros(preprocess(fileName));
109+
result += processMacros(preprocess(fileName), fileName);
110110
} else {
111111
result += read(fileName);
112112
}
@@ -603,7 +603,7 @@ function(${args}) {
603603
function includeFile(fileName, needsPreprocess = true) {
604604
print(`// include: ${fileName}`);
605605
if (needsPreprocess) {
606-
print(processMacros(preprocess(fileName)));
606+
print(processMacros(preprocess(fileName), fileName));
607607
} else {
608608
print(read(fileName));
609609
}

src/modules.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ globalThis.LibraryManager = {
233233
}
234234
currentFile = filename;
235235
try {
236-
processed = processMacros(preprocess(filename));
236+
processed = processMacros(preprocess(filename), filename);
237237
vm.runInThisContext(processed, { filename: filename.replace(/\.\w+$/, '.preprocessed$&') });
238238
} catch (e) {
239239
error(`failure to execute js library "${filename}":`);

src/parseTools.js

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,20 @@
99
*/
1010

1111
globalThis.FOUR_GB = 4 * 1024 * 1024 * 1024;
12+
globalThis.WASM_PAGE_SIZE = 64 * 1024;
13+
1214
const FLOAT_TYPES = new Set(['float', 'double']);
1315

1416
// Does simple 'macro' substitution, using Django-like syntax,
1517
// {{{ code }}} will be replaced with |eval(code)|.
1618
// NOTE: Be careful with that ret check. If ret is |0|, |ret ? ret.toString() : ''| would result in ''!
17-
function processMacros(text) {
19+
function processMacros(text, filename) {
1820
// The `?` here in makes the regex non-greedy so it matches with the closest
1921
// set of closing braces.
2022
// `[\s\S]` works like `.` but include newline.
2123
return text.replace(/{{{([\s\S]+?)}}}/g, (_, str) => {
22-
try {
23-
const ret = eval(str);
24-
return ret !== null ? ret.toString() : '';
25-
} catch (ex) {
26-
ex.stack = `In the following macro:\n\n${str}\n\n${ex.stack}`;
27-
throw ex;
28-
}
24+
const ret = vm.runInThisContext(str, { filename: filename });
25+
return ret !== null ? ret.toString() : '';
2926
});
3027
}
3128

@@ -180,21 +177,21 @@ function needsQuoting(ident) {
180177
globalThis.POINTER_SIZE = MEMORY64 ? 8 : 4;
181178
globalThis.POINTER_MAX = MEMORY64 ? 'Number.MAX_SAFE_INTEGER' : '0xFFFFFFFF';
182179
globalThis.STACK_ALIGN = 16;
183-
const POINTER_BITS = POINTER_SIZE * 8;
184-
const POINTER_TYPE = `u${POINTER_BITS}`;
185-
const POINTER_JS_TYPE = MEMORY64 ? "'bigint'" : "'number'";
186-
const POINTER_SHIFT = MEMORY64 ? '3' : '2';
187-
const POINTER_HEAP = MEMORY64 ? 'HEAP64' : 'HEAP32';
188-
const LONG_TYPE = `i${POINTER_BITS}`;
180+
globalThis.POINTER_BITS = POINTER_SIZE * 8;
181+
globalThis.POINTER_TYPE = `u${POINTER_BITS}`;
182+
globalThis.POINTER_JS_TYPE = MEMORY64 ? "'bigint'" : "'number'";
183+
globalThis.POINTER_SHIFT = MEMORY64 ? '3' : '2';
184+
globalThis.POINTER_HEAP = MEMORY64 ? 'HEAP64' : 'HEAP32';
185+
globalThis.LONG_TYPE = `i${POINTER_BITS}`;
189186

190-
const SIZE_TYPE = POINTER_TYPE;
187+
globalThis.SIZE_TYPE = POINTER_TYPE;
191188

192189

193190
// Similar to POINTER_TYPE, but this is the actual wasm type that is
194191
// used in practice, while POINTER_TYPE is the more refined internal
195192
// type (that is unsigned, where as core wasm does not have unsigned
196193
// types).
197-
const POINTER_WASM_TYPE = `i${POINTER_BITS}`;
194+
globalThis.POINTER_WASM_TYPE = `i${POINTER_BITS}`;
198195

199196
function isPointerType(type) {
200197
return type[type.length - 1] == '*';
@@ -699,9 +696,6 @@ function makeRetainedCompilerSettings() {
699696
return ret;
700697
}
701698

702-
// In wasm, the heap size must be a multiple of 64KiB.
703-
const WASM_PAGE_SIZE = 65536;
704-
705699
// Receives a function as text, and a function that constructs a modified
706700
// function, to which we pass the parsed-out arguments, body, and possible
707701
// "async" prefix of the input function. Returns the output of that function.

tools/preprocessor.mjs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,10 @@ global.printErr = (x) => {
3636

3737
function find(filename) {
3838
const dirname = url.fileURLToPath(new URL('.', import.meta.url));
39-
const prefixes = [process.cwd(), path.join(dirname, '..', 'src')];
40-
for (let i = 0; i < prefixes.length; ++i) {
41-
const combined = path.join(prefixes[i], filename);
42-
if (fs.existsSync(combined)) {
43-
return combined;
44-
}
39+
const prefixe = path.join(dirname, '..', 'src');
40+
const combined = path.join(prefixe, filename);
41+
if (fs.existsSync(combined)) {
42+
return combined;
4543
}
4644
return filename;
4745
}
@@ -52,7 +50,7 @@ global.read = (filename) => {
5250
};
5351

5452
global.load = (f) => {
55-
(0, eval)(read(f) + '//# sourceURL=' + find(f));
53+
vm.runInThisContext(read(f), { filename: find(f) });
5654
};
5755

5856
assert(args.length >= 2);
@@ -65,5 +63,8 @@ load('utility.js');
6563
load('modules.js');
6664
load('parseTools.js');
6765

68-
const output = expandMacros ? processMacros(preprocess(inputFile)) : preprocess(inputFile);
66+
let output = preprocess(inputFile);
67+
if (expandMacros) {
68+
output = processMacros(output, inputFile)
69+
}
6970
process.stdout.write(output);

0 commit comments

Comments
 (0)