Debugging nsjs memoryleak

This commit is contained in:
danielyxie 2018-05-11 19:45:40 -05:00
parent 6902ece765
commit 054cb63227
5 changed files with 596 additions and 525 deletions

480
dist/engine.bundle.js vendored

File diff suppressed because one or more lines are too long

572
dist/tests.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -14,34 +14,57 @@ export function makeScriptBlob(code) {
// (i.e. hack, grow, etc.).
// When the promise returned by this resolves, we'll have finished
// running the main function of the script.
export async function executeJSScript(script, scripts = [], env = {}) {
const envUuid = registerEnv(env);
const envHeader = makeEnvHeader(envUuid);
const urlStack = _getScriptUrls(script, scripts, envHeader, []);
export async function executeJSScript(script, scripts = [], workerScript) {
let loadedModule;
let urlStack = null;
if (script.module === "") {
// The URL at the top is the one we want to import. It will
// recursively import all the other modules in the urlStack.
//
// Webpack likes to turn the import into a require, which sort of
// but not really behaves like import. Particularly, it cannot
// load fully dynamic content. So we hide the import from webpack
// by placing it inside an eval call.
urlStack = _getScriptUrls(script, scripts, []);
script.module = await eval('import(urlStack[urlStack.length - 1])');
}
loadedModule = script.module;
let ns = workerScript.env.vars;
//ns.threads = workerScript.threads;
//ns.args = workerScript.args;
// The URL at the top is the one we want to import. It will
// recursively import all the other modules in the urlStack.
//
// Webpack likes to turn the import into a require, which sort of
// but not really behaves like import. Particularly, it cannot
// load fully dynamic content. So we hide the import from webpack
// by placing it inside an eval call.
try {
// TODO: putting await in a non-async function yields unhelpful
// "SyntaxError: unexpected reserved word" with no line number information.
const loadedModule = await eval('import(urlStack[urlStack.length - 1])');
if (!loadedModule.main) {
throw makeRuntimeRejectMsg(script.filename +
" did not have a main function, cannot run it.");
}
return await loadedModule.main();
console.log("loadedModule:");
console.log(loadedModule);
let constructedModule = await ConstructModule(loadedModule, ns);
console.log("constructedModule: ");
console.log(constructedModule);
return await constructedModule.main();
} finally {
// Revoke the generated URLs and unregister the environment.
for (const url in urlStack) URL.revokeObjectURL(url);
unregisterEnv(envUuid);
// Revoke the generated URLs
if (urlStack != null) {
for (const url in urlStack) URL.revokeObjectURL(url);
}
};
}
export async function ConstructModule(module, ns) {
for (var prop in ns) {
eval("var " + prop + " = ns[\"" + prop + "\"];");
}
async function mod() {
return module;
}
return mod();
}
// Gets a stack of blob urls, the top/right-most element being
// the blob url for the named script on the named server.
//
@ -54,7 +77,7 @@ export async function executeJSScript(script, scripts = [], env = {}) {
// different parts of the tree. That hasn't presented any problem with during
// testing, but it might be an idea for the future. Would require a topo-sort
// then url-izing from leaf-most to root-most.
function _getScriptUrls(script, scripts, envHeader, seen) {
function _getScriptUrls(script, scripts, seen) {
// Inspired by: https://stackoverflow.com/a/43834063/91401
const urlStack = [];
seen.push(script);
@ -78,19 +101,16 @@ function _getScriptUrls(script, scripts, envHeader, seen) {
const [importedScript] = scripts.filter(s => s.filename == filename);
// Try to get a URL for the requested script and its dependencies.
const urls = _getScriptUrls(importedScript, scripts, envHeader, seen);
const urls = _getScriptUrls(importedScript, scripts, seen);
// The top url in the stack is the replacement import file for this script.
urlStack.push(...urls);
return [prefix, urls[urls.length - 1], suffix].join('');
});
// Inject the NSJS preamble at the top of the code.
const transformedCodeWithHeader = [envHeader, transformedCode].join("\n");
// If we successfully transformed the code, create a blob url for it and
// push that URL onto the top of the stack.
urlStack.push(URL.createObjectURL(makeScriptBlob(transformedCodeWithHeader)));
urlStack.push(URL.createObjectURL(makeScriptBlob(transformedCode)));
return urlStack;
} catch (err) {
// If there is an error, we need to clean up the URLs.

@ -112,7 +112,7 @@ function startJsScript(workerScript) {
// to that script, which env.vars does at this point.
return executeJSScript(workerScript.scriptRef.scriptRef,
workerScript.getServer().scripts,
workerScript.env.vars).then(function (mainReturnValue) {
workerScript).then(function (mainReturnValue) {
if (mainReturnValue === undefined) return workerScript;
return [mainReturnValue, workerScript];
}).catch(e => {
@ -223,6 +223,7 @@ function runScriptsLoop() {
return;
} else {
dialogBoxCreate("An unknown script died for an unknown reason. This is a bug please contact game dev");
console.log(w);
}
});
}

@ -326,6 +326,7 @@ function Script() {
this.code = "";
this.ramUsage = 0;
this.server = ""; //IP of server this script is on
this.module = "";
};
//Get the script data from the Script Editor and save it to the object
@ -714,6 +715,7 @@ function loadAllRunningScripts() {
for (var j = 0; j < server.runningScripts.length; ++j) {
count++;
server.runningScripts[j].scriptRef.module = "";
addWorkerScript(server.runningScripts[j], server);
//Offline production