#!/usr/bin/env python # Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import re import sys def main(): parser = argparse.ArgumentParser() parser.add_argument('js_file') parser.add_argument('--unittest', action='store_true') args = parser.parse_args() # load file to be processed with open(args.js_file, "r") as f: source = f.read() # remove all known functions for memory access # note: this implementation uses a weak heuristic: only the closing } of a # given function has no indentation for func in ["SAFE_HEAP_LOAD", "SAFE_HEAP_LOAD_D", "SAFE_HEAP_STORE", "SAFE_HEAP_STORE_D"]: source = re.sub("function %s\([^\)]*\)\s*{(.*\n)+?}" % func, "", source) # applies the same patch as seen at # https://github.com/kripken/emscripten/commit/bc11547fbf446993ee0f6f30a0deb3f80f205c35 # which is part of the fix for https://github.com/kripken/emscripten/issues/3945 # TODO: fix after PBL-32521 is done orig_source = source source = source.replace("funcstr += arg + '=' + convertCode.returnValue + ';';", "funcstr += arg + '=(' + convertCode.returnValue + ');';") # assert source != orig_source, "Emscripten output does not match expected output of 1.35.0" # we're not using emscripten's --pre-js and --post-js as it interferes # with --embed-file with open(args.js_file, "w") as f: f.write(PROLOGUE) if args.unittest: f.write(UNITTEST_PROLOGUE) f.write(source) f.write(EPILOGUE) if args.unittest: f.write("new RockySimulator();\n") PROLOGUE = """ RockySimulator = function(options) { options = options || {}; var Module = { print: function(text) { console.log(text); }, printErr: function(text) { console.error(text); }, }; """ EPILOGUE = """ // support non-aligned memory access function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { if (dest <= 0) abort('segmentation fault storing ' + bytes + ' bytes to address ' + dest); if (dest + bytes > Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault, exceeded the top of the available heap when storing ' + bytes + ' bytes to address ' + dest + '. STATICTOP=' + STATICTOP + ', DYNAMICTOP=' + DYNAMICTOP); assert(DYNAMICTOP <= TOTAL_MEMORY); if (dest % bytes !== 0) { for (var i = 0; i < bytes; i++) { HEAPU8[dest + i >> 0] = (value >> (8 * i)) & 0xff; } } else { setValue(dest, value, getSafeHeapType(bytes, isFloat), 1); } } function SAFE_HEAP_STORE_D(dest, value, bytes) { SAFE_HEAP_STORE(dest, value, bytes, true); } function SAFE_HEAP_LOAD(dest, bytes, unsigned, isFloat) { // overrule if (dest <= 0) abort('segmentation fault loading ' + bytes + ' bytes from address ' + dest); if (dest + bytes > Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault, exceeded the top of the available heap when loading ' + bytes + ' bytes from address ' + dest + '. STATICTOP=' + STATICTOP + ', DYNAMICTOP=' + DYNAMICTOP); assert(DYNAMICTOP <= TOTAL_MEMORY); var type = getSafeHeapType(bytes, isFloat); var ret; if (dest % bytes !== 0) { for (var i = 0; i < bytes; i++) { ret |= HEAPU8[dest + i >> 0] << (8 * i); } } else { ret = getValue(dest, type, 1); } if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1); return ret; } function SAFE_HEAP_LOAD_D(dest, bytes, unsigned) { return SAFE_HEAP_LOAD(dest, bytes, unsigned, true); } return Module; }; if (typeof(module) !== "undefined") { module.exports = RockySimulator; } """ UNITTEST_PROLOGUE = """ var defaultPreRun = Module.preRun; Module.preRun = function() { if (defaultPreRun) { defaultPreRun(); } // Mount the host filesystem to make the fixture files accessible: FS.mkdir('/node_fs'); FS.mount(NODEFS, { root: '/' }, '/node_fs'); } """ if __name__ == "__main__": main()