diff --git a/src/ui.ts b/src/ui.ts index aae36391..d3634957 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -50,7 +50,7 @@ var TOOL_TO_SOURCE_STYLE = { } function newWorker() : Worker { - return new Worker("./src/worker/workermain.js"); + return new Worker("./src/worker/loader.js"); } var userPaused : boolean; // did user explicitly pause? diff --git a/src/worker/loader.js b/src/worker/loader.js new file mode 100644 index 00000000..2c50ba14 --- /dev/null +++ b/src/worker/loader.js @@ -0,0 +1,5 @@ +"use strict"; + +var exports = {}; +importScripts("../../gen/worker/workermain.js"); + diff --git a/src/worker/workermain.js b/src/worker/workermain.ts similarity index 89% rename from src/worker/workermain.js rename to src/worker/workermain.ts index b38674e6..cf1852d3 100644 --- a/src/worker/workermain.js +++ b/src/worker/workermain.ts @@ -1,6 +1,12 @@ "use strict"; -var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function'; +import { WorkerResult, WorkerFileUpdate, WorkerBuildStep, WorkerMessage, WorkerError, Dependency } from "../workertypes"; + +const emglobal : any = this['window'] || this['global'] || this; +declare var WebAssembly; +declare function importScripts(path:string); +declare function postMessage(msg); + var ENVIRONMENT_IS_WEB = typeof window === 'object'; var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function'; @@ -8,7 +14,7 @@ var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function'; // TODO: leaks memory even when disabled... var _WASM_module_cache = {}; var CACHE_WASM_MODULES = true; -function getWASMModule(module_id) { +function getWASMModule(module_id:string) { var module = _WASM_module_cache[module_id]; if (!module) { starttime(); @@ -22,7 +28,7 @@ function getWASMModule(module_id) { return module; } // function for use with instantiateWasm -function moduleInstFn(module_id) { +function moduleInstFn(module_id:string) { return function(imports,ri) { var mod = getWASMModule(module_id); var inst = new WebAssembly.Instance(mod, imports); @@ -176,32 +182,46 @@ var PLATFORM_PARAMS = { }, }; -// shim out window and document objects for security -// https://github.com/mbostock/d3/issues/1053 -var noop = function() { return new Function(); }; -var window = noop(); -window.CSSStyleDeclaration = noop(); -window.CSSStyleDeclaration.setProperty = noop(); -window.Element = noop(); -window.Element.setAttribute = noop(); -window.Element.setAttributeNS = noop(); -window.navigator = noop(); -var document = noop(); -document.documentElement = noop(); -document.documentElement.style = noop(); - var _t1; function starttime() { _t1 = new Date(); } function endtime(msg) { var _t2 = new Date(); console.log(msg, _t2.getTime() - _t1.getTime(), "ms"); } /// working file store and build steps -var buildsteps = []; -var buildstartseq = 0; -var workfs = {}; -var workerseq = 0; +type FileData = string | Uint8Array; -function compareData(a,b) { +type FileEntry = { + path: string + encoding: string + data: FileData + ts: number +}; + +type BuildOptions = { + mainFilePath : string +}; + +// TODO +interface BuildStep extends WorkerBuildStep { + files? : string[] + args? : string[] + nextstep? : BuildStep + linkstep? : BuildStep + params? + result? + code? + generated? + prefix? + maxts? + dependencies? +}; + +var buildsteps : BuildStep[] = []; +var buildstartseq : number = 0; +var workfs : {[path:string]:FileEntry} = {}; +var workerseq : number = 0; + +function compareData(a:FileData, b:FileData) : boolean { if (a.length != b.length) return false; if (typeof a === 'string' && typeof b === 'string') return a==b; @@ -214,7 +234,7 @@ function compareData(a,b) { } } -function putWorkFile(path, data) { +function putWorkFile(path:string, data:FileData) { var encoding = (typeof data === 'string') ? 'utf8' : 'binary'; var entry = workfs[path]; if (!entry || !compareData(entry.data, data) || entry.encoding != encoding) { @@ -225,18 +245,18 @@ function putWorkFile(path, data) { } // returns true if file changed during this build step -function wasChanged(entry) { +function wasChanged(entry:FileEntry) : boolean { return entry.ts > buildstartseq; } -function populateEntry(fs, path, entry) { +function populateEntry(fs, path:string, entry:FileEntry) { fs.writeFile(path, entry.data, {encoding:entry.encoding}); fs.utime(path, entry.ts, entry.ts); console.log("<<<", path, entry.data.length); } // can call multiple times (from populateFiles) -function gatherFiles(step, options) { +function gatherFiles(step:BuildStep, options?:BuildOptions) { var maxts = 0; if (step.files) { for (var i=0; i (.+)/; // TODO var errline = 0; var errpath = step.path; - function match_asm_fn(s) { + var match_asm_fn = (s:string) => { var m = match_asm_re1.exec(s); if (m) { errline = parseInt(m[1]); @@ -943,7 +969,7 @@ function assembleSDASZ80(step) { } } } - var ASZ80 = sdasz80({ + var ASZ80 = emglobal.sdasz80({ instantiateWasm: moduleInstFn('sdasz80'), noInitialRun:true, //logReadFiles:true, @@ -969,7 +995,7 @@ function assembleSDASZ80(step) { //symout = FS.readFile("main.sym", {encoding:'utf8'}); } -function linkSDLDZ80(step) +function linkSDLDZ80(step:BuildStep) { loadNative("sdldz80"); var errors = []; @@ -978,7 +1004,7 @@ function linkSDLDZ80(step) if (staleFiles(step, [binpath])) { //?ASlink-Warning-Undefined Global '__divsint' referenced by module 'main' var match_aslink_re = /\?ASlink-(\w+)-(.+)/; - function match_aslink_fn(s) { + var match_aslink_fn = (s:string) => { var matches = match_aslink_re.exec(s); if (matches) { errors.push({ @@ -988,7 +1014,7 @@ function linkSDLDZ80(step) } } var params = step.params; - var LDZ80 = sdldz80({ + var LDZ80 = emglobal.sdldz80({ instantiateWasm: moduleInstFn('sdldz80'), noInitialRun:true, //logReadFiles:true, @@ -1055,7 +1081,7 @@ function linkSDLDZ80(step) } var sdcc; -function compileSDCC(step) { +function compileSDCC(step:BuildStep) { gatherFiles(step, { mainFilePath:"main.c" // not used @@ -1076,7 +1102,7 @@ function compileSDCC(step) { var FS = SDCC['FS']; populateFiles(step, FS); // load source file and preprocess - var code = workfs[step.path].data; // TODO + var code = workfs[step.path].data as string; // TODO var preproc = preprocessMCPP(step); if (preproc.errors) return preproc; else code = preproc.code; @@ -1115,7 +1141,7 @@ function compileSDCC(step) { }; } -function preprocessMCPP(step) { +function preprocessMCPP(step:BuildStep) { load("mcpp"); var platform = step.platform; var params = PLATFORM_PARAMS[platform]; @@ -1123,7 +1149,7 @@ function preprocessMCPP(step) { // :2: error: Can't open include file "foo.h" var errors = []; var match_fn = makeErrorMatcher(errors, /:(\d+): (.+)/, 1, 2, step.path); - var MCPP = mcpp({ + var MCPP = emglobal.mcpp({ noInitialRun:true, noFSInit:true, print:print_fn, @@ -1166,21 +1192,21 @@ function preprocessMCPP(step) { // TODO: must be a better way to do all this -function detectModuleName(code) { +function detectModuleName(code:string) { var m = /^\s*module\s+(\w+_top)\b/m.exec(code) || /^\s*module\s+(top)\b/m.exec(code) || /^\s*module\s+(\w+)\b/m.exec(code); return m ? m[1] : null; } -function detectTopModuleName(code) { +function detectTopModuleName(code:string) { var topmod = detectModuleName(code) || "top"; var m = /^\s*module\s+(\w+?_top)/m.exec(code); if (m && m[1]) topmod = m[1]; return topmod; } -function writeDependencies(depends, FS, errors, callback) { +function writeDependencies(depends:Dependency[], FS, errors:WorkerError[], callback?) { if (depends) { for (var i=0; i0) s += ","; @@ -1286,7 +1312,7 @@ function compileInlineASM(code, platform, options, errors, asmlines) { } // TODO: make compliant with standard msg format -function compileVerilator(step) { +function compileVerilator(step:BuildStep) { loadNative("verilator_bin"); loadGen("worker/verilator2js"); var platform = step.platform || 'verilog'; @@ -1297,8 +1323,8 @@ function compileVerilator(step) { return {errors:errors}; } var code = step.code; - var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?:)?(\d+)?[:]?\s*(.+)/i, 3, 4); - var verilator_mod = verilator_bin({ + var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?:)?(\d+)?[:]?\s*(.+)/i, 3, 4, step.path); + var verilator_mod = emglobal.verilator_bin({ instantiateWasm: moduleInstFn('verilator_bin'), noInitialRun:true, print:print_fn, @@ -1336,13 +1362,16 @@ function compileVerilator(step) { putWorkFile("main.js", rtn.output.code); if (!anyTargetChanged(step, ["main.js"])) return; - rtn.errors = errors; - rtn.intermediate = {listing:h_file + cpp_file}; // TODO - rtn.listings = {}; + //rtn.intermediate = {listing:h_file + cpp_file}; // TODO + var listings = {}; // TODO: what if found in non-top-module? if (asmlines.length) - rtn.listings[step.path] = {lines:asmlines}; - return rtn; + listings[step.path] = {lines:asmlines}; + return { + output: rtn.output, + errors: errors, + listings: {}, + }; } catch(e) { console.log(e); return {errors:errors}; @@ -1350,13 +1379,13 @@ function compileVerilator(step) { } // TODO: test -function compileYosys(step) { +function compileYosys(step:BuildStep) { loadNative("yosys"); var code = step.code; var errors = []; - var match_fn = makeErrorMatcher(errors, /ERROR: (.+?) in line (.+?[.]v):(\d+)[: ]+(.+)/i, 3, 4); + var match_fn = makeErrorMatcher(errors, /ERROR: (.+?) in line (.+?[.]v):(\d+)[: ]+(.+)/i, 3, 4, step.path); starttime(); - var yosys_mod = yosys({ + var yosys_mod = emglobal.yosys({ instantiateWasm: moduleInstFn('yosys'), noInitialRun:true, print:print_fn, @@ -1389,7 +1418,7 @@ function compileYosys(step) { } } -function assembleZMAC(step) { +function assembleZMAC(step:BuildStep) { loadNative("zmac"); var hexout, lstout, binout; var errors = []; @@ -1406,7 +1435,7 @@ error1.asm(11): warning: 'foobar' treated as label (instruction typo?) Add a colon or move to first column to stop this warning. 1 errors (see listing if no diagnostics appeared here) */ - var ZMAC = zmac({ + var ZMAC = emglobal.zmac({ instantiateWasm: moduleInstFn('zmac'), noInitialRun:true, //logReadFiles:true, @@ -1490,7 +1519,7 @@ var TOOL_PRELOADFS = { 'sccz80': 'sccz80', } -function applyDefaultErrorPath(errors, path) { +function applyDefaultErrorPath(errors:WorkerError[], path:string) { if (!path) return; for (var i=0; i