pebble/applib-targets/emscripten/transform_js.py
2025-01-27 11:38:16 -08:00

134 lines
4.4 KiB
Python
Executable file

#!/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()