From bd0ec31931a8258ecef48e98bb61bcd7296f93de Mon Sep 17 00:00:00 2001 From: rina Date: Mon, 24 Jun 2024 16:53:35 +1000 Subject: [PATCH] prototype ui --- libASL/support/web/dune | 4 ++ libASL/support/web/solver.ml | 4 ++ web/aslp.js | 87 ++++++++++++++++++++++++++++++++++++ web/dune | 7 +-- web/index.html | 86 ++++++++++++++++++++++++++++++++++- web/js.ml | 40 +++++++++++++++-- web/reset.css | 27 +++++++++++ web/worker.js | 12 +++++ 8 files changed, 260 insertions(+), 7 deletions(-) create mode 100644 libASL/support/web/dune create mode 100644 libASL/support/web/solver.ml create mode 100644 web/aslp.js create mode 100644 web/reset.css create mode 100644 web/worker.js diff --git a/libASL/support/web/dune b/libASL/support/web/dune new file mode 100644 index 00000000..f9cb6a66 --- /dev/null +++ b/libASL/support/web/dune @@ -0,0 +1,4 @@ +(library + (name libASL_web) + (implements libASL_support) + (libraries libASL_ast zarith_stubs_js)) diff --git a/libASL/support/web/solver.ml b/libASL/support/web/solver.ml new file mode 100644 index 00000000..fa6b9717 --- /dev/null +++ b/libASL/support/web/solver.ml @@ -0,0 +1,4 @@ + +module AST = Asl_ast + +let check_constraints (_bs: AST.expr list) (_cs: AST.expr list): bool = true diff --git a/web/aslp.js b/web/aslp.js new file mode 100644 index 00000000..e312b86f --- /dev/null +++ b/web/aslp.js @@ -0,0 +1,87 @@ +/** + * Supporting code to enable ASLp-in-JS. Handles input/output. + */ + +const get = query => { + const result = document.querySelector(query); + console.assert(result, "query returned null: " + query); + return result; +}; + +// XXX: cannot use worker due to worker stack size being too small +// const worker = new Worker('worker.js'); + +const input = get('#op'); +const output = get('#output'); +const loading = get('#loading'); + + +const OPCODE = 'opcode'; +const BYTES = 'bytes'; +let mode = OPCODE; + +const flipEndian = s => { + const chunked = s.match(/.{1,2}/g); // chunks of 2 + chunked.reverse(); + return chunked.join(''); +}; + +// always returns BIG-endian string +const getOpcode = () => { + const val = input.value.trim().replace(/^0x/, '').replace(/\s/g, '').padStart(8, '0'); + + if (val.length > 8) throw Error('opcode too long: ' + val.length); + if (mode == OPCODE) return val; + return flipEndian(val); +} + +const setOpcodeMode = newMode => { + if (mode != newMode) { + const op = getOpcode(); + mode = newMode; + + if (mode == OPCODE) { + input.value = '0x' + op.toLowerCase(); + } else { + input.value = flipEndian(op).toUpperCase().match(/.{1,2}/g).join(' '); + } + } +}; + +const onChangeDebug = el => { + libASL_web.setDebugLevel(parseInt(el.value, 10)); +}; + +const clearOutput = () => { + output.innerHTML = ''; +}; + +const submit = () => { + clearOutput(); + loading.classList.remove('invisible'); + // defer computation so loading indicator shows. + setTimeout(() => { + try { + libASL_web.dis('0x' + getOpcode()); + } finally { + loading.classList.add('invisible'); + } + }, 30); +}; + + +const write = (isError) => s => { + const span = document.createElement('span'); + const data = new Uint8Array(s.length); + for (let i = 0; i < s.length; i++) { + data[i] = s.charCodeAt(i); + } + span.textContent = new TextDecoder('utf-8').decode(data); + if (isError) + span.classList.add('stderr'); + output.appendChild(span); + return 0; +}; + +libASL_web.init(write(false), write(true)); +libASL_web.setDebugLevel(0); diff --git a/web/dune b/web/dune index 0c1ced8f..5daaee9b 100644 --- a/web/dune +++ b/web/dune @@ -2,10 +2,11 @@ (name js) (modes js) (modules js) - (libraries z3 libASLResources dune-site str zarith pprint zarith_stubs_js) - (js_of_ocaml (flags --debug-info --no-inline :standard \ --source-map-inline)) + (libraries libASL libASL_web js_of_ocaml) + (js_of_ocaml (flags --debug-info --no-inline --sourcemap :standard \ --source-map-inline)) + (preprocess (pps js_of_ocaml-ppx)) ) (alias (name default) - (deps js.bc.js index.html)) + (deps js.bc.js index.html reset.css aslp.js worker.js)) diff --git a/web/index.html b/web/index.html index 1288b982..aa33d859 100644 --- a/web/index.html +++ b/web/index.html @@ -1,9 +1,93 @@ - Cubes + ASLp Web + + + + + +

ASLp Web

+
+
+

+ +
+ + +

+
+

+ +

+ +

+ + +

+ +

+ +

+ Debug options + +
+ +

+ +
+ +

Output

+

+ + + +

+

+


+      
+      

+
+ + + diff --git a/web/js.ml b/web/js.ml index 8e5deaa9..f6cab93e 100644 --- a/web/js.ml +++ b/web/js.ml @@ -1,4 +1,38 @@ + +let init input out err = + Js_of_ocaml.Sys_js.set_channel_flusher stdout out; + Js_of_ocaml.Sys_js.set_channel_flusher stderr err; + Js_of_ocaml.Sys_js.set_channel_filler stdin input; + () + +let env = lazy (Option.get @@ LibASL.Arm_env.aarch64_evaluation_environment ()) +let denv = lazy (LibASL.Dis.build_env @@ Lazy.force env) + +let print_pp = ref true + +let pp_stmt () = + if !print_pp then Asl_utils.pp_stmt else fun x -> Utils.to_string (Asl_parser_pp.pp_raw_stmt x) + +let dis (x: string) = + let stmts = LibASL.Dis.retrieveDisassembly Lazy.(force env) Lazy.(force denv) x in + List.iter + (fun s -> print_endline @@ pp_stmt () s) + stmts; + flush stdout + + let () = - print_endline "hello from js"; - print_endline @@ Int.to_string @@ List.length LibASLResources.Res.Sites.aslfiles - (* print_endline @@ LibASL.Value.(pp_value @@ from_bitsLit "100") *) + print_endline "libASL_web ocaml-side..."; + + let open Js_of_ocaml in + let () = Js.export "libASL_web" + (object%js + (* TODO: support stdin from javascript for repl, possibly converting asli repl to lwt *) + method init (out : string -> unit) (err : string -> unit) = init (fun () -> "") out err + + method force = let _ = Lazy.force env and _ = Lazy.force denv in () + method dis (x: string) = dis x + method setDebugLevel i = (LibASL.Dis.debug_level := i) + method setPrettyPrint (x : bool) = (print_pp := x) + end) in + () diff --git a/web/reset.css b/web/reset.css new file mode 100644 index 00000000..bafd2ab0 --- /dev/null +++ b/web/reset.css @@ -0,0 +1,27 @@ +/* + Josh's Custom CSS Reset + https://www.joshwcomeau.com/css/custom-css-reset/ +*/ +*, *::before, *::after { + box-sizing: border-box; +} +* { + margin: 0; +} +body { + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} +img, picture, video, canvas, svg { + display: block; + max-width: 100%; +} +input, button, textarea, select { + font: inherit; +} +p, h1, h2, h3, h4, h5, h6 { + overflow-wrap: break-word; +} +#root, #__next { + isolation: isolate; +} diff --git a/web/worker.js b/web/worker.js new file mode 100644 index 00000000..42063258 --- /dev/null +++ b/web/worker.js @@ -0,0 +1,12 @@ +importScripts('js.bc.js'); + +console.log('libASL_web js-side:', libASL_web); + +libASL_web.go(); +console.log('libASL_web worker ready'); + +onmessage = function(e) { + const fn = libASL_web[e.data[0]]; + console.assert(fn, "libASL_web function not found: " + e.data); + fn(...e.data[1]); +};