Skip to content

Commit

Permalink
Remove remaining uses of eval in the JS compiler
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sbc100 committed Feb 26, 2024
1 parent e6be4f5 commit 7934687
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/compiler.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ globalThis.read = (filename) => {
};

function load(f) {
(0, eval)(read(f) + '//# sourceURL=' + find(f));
};
vm.runInThisContext(read(f), { filename: find(f) });
}

// Basic utilities
load('utility.js');
Expand Down
4 changes: 2 additions & 2 deletions src/jsifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function preJS() {
let result = '';
for (const fileName of PRE_JS_FILES) {
if (shouldPreprocess(fileName)) {
result += processMacros(preprocess(fileName));
result += processMacros(preprocess(fileName), fileName);
} else {
result += read(fileName);
}
Expand Down Expand Up @@ -603,7 +603,7 @@ function(${args}) {
function includeFile(fileName, needsPreprocess = true) {
print(`// include: ${fileName}`);
if (needsPreprocess) {
print(processMacros(preprocess(fileName)));
print(processMacros(preprocess(fileName), fileName));
} else {
print(read(fileName));
}
Expand Down
2 changes: 1 addition & 1 deletion src/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ globalThis.LibraryManager = {
}
currentFile = filename;
try {
processed = processMacros(preprocess(filename));
processed = processMacros(preprocess(filename), filename);
vm.runInThisContext(processed, { filename: filename.replace(/\.\w+$/, '.preprocessed$&') });
} catch (e) {
error(`failure to execute js library "${filename}":`);
Expand Down
32 changes: 13 additions & 19 deletions src/parseTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,20 @@
*/

globalThis.FOUR_GB = 4 * 1024 * 1024 * 1024;
globalThis.WASM_PAGE_SIZE = 64 * 1024;

const FLOAT_TYPES = new Set(['float', 'double']);

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

Expand Down Expand Up @@ -180,21 +177,21 @@ function needsQuoting(ident) {
globalThis.POINTER_SIZE = MEMORY64 ? 8 : 4;
globalThis.POINTER_MAX = MEMORY64 ? 'Number.MAX_SAFE_INTEGER' : '0xFFFFFFFF';
globalThis.STACK_ALIGN = 16;
const POINTER_BITS = POINTER_SIZE * 8;
const POINTER_TYPE = `u${POINTER_BITS}`;
const POINTER_JS_TYPE = MEMORY64 ? "'bigint'" : "'number'";
const POINTER_SHIFT = MEMORY64 ? '3' : '2';
const POINTER_HEAP = MEMORY64 ? 'HEAP64' : 'HEAP32';
const LONG_TYPE = `i${POINTER_BITS}`;
globalThis.POINTER_BITS = POINTER_SIZE * 8;
globalThis.POINTER_TYPE = `u${POINTER_BITS}`;
globalThis.POINTER_JS_TYPE = MEMORY64 ? "'bigint'" : "'number'";
globalThis.POINTER_SHIFT = MEMORY64 ? '3' : '2';
globalThis.POINTER_HEAP = MEMORY64 ? 'HEAP64' : 'HEAP32';
globalThis.LONG_TYPE = `i${POINTER_BITS}`;

const SIZE_TYPE = POINTER_TYPE;
globalThis.SIZE_TYPE = POINTER_TYPE;


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

function isPointerType(type) {
return type[type.length - 1] == '*';
Expand Down Expand Up @@ -699,9 +696,6 @@ function makeRetainedCompilerSettings() {
return ret;
}

// In wasm, the heap size must be a multiple of 64KiB.
const WASM_PAGE_SIZE = 65536;

// Receives a function as text, and a function that constructs a modified
// function, to which we pass the parsed-out arguments, body, and possible
// "async" prefix of the input function. Returns the output of that function.
Expand Down
7 changes: 5 additions & 2 deletions tools/preprocessor.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ global.read = (filename) => {
};

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

assert(args.length >= 2);
Expand All @@ -65,5 +65,8 @@ load('utility.js');
load('modules.js');
load('parseTools.js');

const output = expandMacros ? processMacros(preprocess(inputFile)) : preprocess(inputFile);
let output = preprocess(inputFile);
if (expandMacros) {
output = processMacros(output, inputFile)
}
process.stdout.write(output);

0 comments on commit 7934687

Please sign in to comment.