From 488deea164f5494e7fa1cff3e46848ca3e86bbac Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:24:39 +0200 Subject: [PATCH] fix: improve performance of typescript by caching separate declarations --- src/me/topchetoeu/jscript/engine/Context.java | 5 +- .../jscript/engine/Environment.java | 4 ++ src/me/topchetoeu/jscript/js/bootstrap.js | 55 +++++++++++++------ 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/me/topchetoeu/jscript/engine/Context.java b/src/me/topchetoeu/jscript/engine/Context.java index 1f00eb2..c8246a5 100644 --- a/src/me/topchetoeu/jscript/engine/Context.java +++ b/src/me/topchetoeu/jscript/engine/Context.java @@ -33,7 +33,8 @@ public class Context { } public FunctionValue compile(Filename filename, String raw) { - var transpiled = environment().compile.call(this, null, raw, filename.toString()); + var env = environment(); + var transpiled = env.compile.call(this, null, raw, filename.toString(), env); String source = null; FunctionValue runner = null; @@ -45,7 +46,7 @@ public class Context { else source = Values.toString(this, transpiled); var breakpoints = new TreeSet(); - FunctionValue res = Parsing.compile(Engine.functions, breakpoints, environment(), filename, source); + FunctionValue res = Parsing.compile(Engine.functions, breakpoints, env, filename, source); engine.onSource(filename, source, breakpoints); if (runner != null) res = (FunctionValue)runner.call(this, null, res); diff --git a/src/me/topchetoeu/jscript/engine/Environment.java b/src/me/topchetoeu/jscript/engine/Environment.java index 397ec78..30a77a7 100644 --- a/src/me/topchetoeu/jscript/engine/Environment.java +++ b/src/me/topchetoeu/jscript/engine/Environment.java @@ -22,6 +22,10 @@ public class Environment { public GlobalScope global; public WrappersProvider wrappers; + private static int nextId = 0; + + @Native public int id = ++nextId; + @Native public FunctionValue compile; @Native public FunctionValue regexConstructor = new NativeFunction("RegExp", (ctx, thisArg, args) -> { throw EngineException.ofError("Regular expressions not supported.").setCtx(ctx.environment(), ctx.engine); diff --git a/src/me/topchetoeu/jscript/js/bootstrap.js b/src/me/topchetoeu/jscript/js/bootstrap.js index 74477af..6736a28 100644 --- a/src/me/topchetoeu/jscript/js/bootstrap.js +++ b/src/me/topchetoeu/jscript/js/bootstrap.js @@ -1,7 +1,13 @@ (function (_arguments) { var ts = _arguments[0]; - var src = '', lib = _arguments[2].concat([ 'declare const exit: never; declare const go: any;' ]).join(''), decls = '', version = 0; + var src = '', version = 0; + var lib = _arguments[2].concat([ + 'declare const exit: never; declare const go: any;', + 'declare function getTsDeclarations(): string[];' + ]).join(''); var libSnapshot = ts.ScriptSnapshot.fromString(lib); + var environments = {}; + var declSnapshots = []; var settings = { outDir: "/out", @@ -21,18 +27,27 @@ var service = ts.createLanguageService({ getCurrentDirectory: function() { return "/"; }, getDefaultLibFileName: function() { return "/lib.d.ts"; }, - getScriptFileNames: function() { return [ "/src.ts", "/lib.d.ts", "/glob.d.ts" ]; }, + getScriptFileNames: function() { + var res = [ "/src.ts", "/lib.d.ts" ]; + for (var i = 0; i < declSnapshots.length; i++) res.push("/glob." + (i + 1) + ".d.ts"); + return res; + }, getCompilationSettings: function () { return settings; }, fileExists: function(filename) { return filename === "/lib.d.ts" || filename === "/src.ts" || filename === "/glob.d.ts"; }, getScriptSnapshot: function(filename) { if (filename === "/lib.d.ts") return libSnapshot; if (filename === "/src.ts") return ts.ScriptSnapshot.fromString(src); - if (filename === "/glob.d.ts") return ts.ScriptSnapshot.fromString(decls); + + var index = /\/glob\.(\d+)\.d\.ts/g.exec(filename); + if (index && index[1] && (index = Number(index[1])) && index > 0 && index <= declSnapshots.length) { + return declSnapshots[index - 1]; + } + throw new Error("File '" + filename + "' doesn't exist."); }, getScriptVersion: function (filename) { - if (filename === "/lib.d.ts") return 0; + if (filename === "/lib.d.ts" || filename.startsWith("/glob.")) return 0; else return version; }, }, reg); @@ -40,10 +55,12 @@ service.getEmitOutput("/lib.d.ts"); log("Loaded libraries!"); - function compile(code, filename) { + function compile(code, filename, env) { src = code; version++; + if (!environments[env.id]) environments[env.id] = [] + declSnapshots = environments[env.id]; var emit = service.getEmitOutput("/src.ts"); var diagnostics = [] @@ -58,31 +75,37 @@ if (file === "src.ts") file = filename; return file + ":" + (pos.line + 1) + ":" + (pos.character + 1) + ": " + message; } - else return "Error: " + message; + else return message; }); if (diagnostics.length > 0) { throw new SyntaxError(diagnostics.join("\n")); } - return { - result: emit.outputFiles[0].text, - declaration: emit.outputFiles[1].text - }; - } - - _arguments[1].compile = function (filename, code) { - var res = compile(filename, code); + var result = emit.outputFiles[0].text; + var declaration = emit.outputFiles[1].text; + return { - source: res.result, + source: result, runner: function(func) { return function() { var val = func.apply(this, arguments); - decls += res.declaration; + if (declaration !== '') { + declSnapshots.push(ts.ScriptSnapshot.fromString(declaration)); + } return val; } } + }; + } + + function apply(env) { + env.compile = compile; + env.global.getTsDeclarations = function() { + return environments[env.id]; } } + + apply(_arguments[1]); })(arguments);