diff options
Diffstat (limited to 'js/src/builtin/embedjs.py')
-rw-r--r-- | js/src/builtin/embedjs.py | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/js/src/builtin/embedjs.py b/js/src/builtin/embedjs.py new file mode 100644 index 0000000000..abe9e9344e --- /dev/null +++ b/js/src/builtin/embedjs.py @@ -0,0 +1,203 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# ToCAsciiArray and ToCArray are from V8's js2c.py. +# +# Copyright 2012 the V8 project authors. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This utility converts JS files containing self-hosted builtins into a C +# header file that can be embedded into SpiderMonkey. +# +# It uses the C preprocessor to process its inputs. + +from __future__ import with_statement + +import errno +import re +import sys +import os +import subprocess +import shlex + +import buildconfig +import mozpack.path as mozpath +from mozfile import which +from mozbuild.util import ensure_bytes + + +def ToCAsciiArray(lines): + result = [] + for chr in lines: + value = ord(chr) + assert value < 128 + result.append(str(value)) + return ", ".join(result) + + +def ToCArray(lines): + result = [] + for chr in lines: + result.append(str(chr)) + return ", ".join(result) + + +HEADER_TEMPLATE = """\ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +namespace js { +namespace %(namespace)s { + static const %(sources_type)s data[] = { %(sources_data)s }; + + static const %(sources_type)s * const %(sources_name)s = reinterpret_cast<const %(sources_type)s *>(data); + + uint32_t GetCompressedSize() { + return %(compressed_total_length)i; + } + + uint32_t GetRawScriptsSize() { + return %(raw_total_length)i; + } +} // selfhosted +} // js +""" # NOQA: E501 + + +def embed( + cxx, preprocessorOption, cppflags, msgs, sources, c_out, js_out, namespace, env +): + objdir = os.getcwd() + # Use relative pathnames to avoid path translation issues in WSL. + combinedSources = "\n".join( + [msgs] + + [ + '#include "%(s)s"' % {"s": mozpath.relpath(source, objdir)} + for source in sources + ] + ) + args = cppflags + ["-D%(k)s=%(v)s" % {"k": k, "v": env[k]} for k in env] + preprocessed = preprocess(cxx, preprocessorOption, combinedSources, args) + processed = "\n".join( + [ + line + for line in preprocessed.splitlines() + if (line.strip() and not line.startswith("#")) + ] + ) + + js_out.write(processed) + import zlib + + compressed = zlib.compress(ensure_bytes(processed)) + data = ToCArray(compressed) + c_out.write( + HEADER_TEMPLATE + % { + "sources_type": "unsigned char", + "sources_data": data, + "sources_name": "compressedSources", + "compressed_total_length": len(compressed), + "raw_total_length": len(processed), + "namespace": namespace, + } + ) + + +def preprocess(cxx, preprocessorOption, source, args=[]): + if not os.path.exists(cxx[0]): + binary = cxx[0] + cxx[0] = which(binary) + if not cxx[0]: + raise OSError(errno.ENOENT, "%s not found on PATH" % binary) + + # Clang seems to complain and not output anything if the extension of the + # input is not something it recognizes, so just fake a .cpp here. + tmpIn = "self-hosting-cpp-input.cpp" + tmpOut = "self-hosting-preprocessed.pp" + outputArg = shlex.split(preprocessorOption + tmpOut) + + with open(tmpIn, "wb") as input: + input.write(ensure_bytes(source)) + print(" ".join(cxx + outputArg + args + [tmpIn])) + result = subprocess.Popen(cxx + outputArg + args + [tmpIn]).wait() + if result != 0: + sys.exit(result) + with open(tmpOut, "r") as output: + processed = output.read() + os.remove(tmpIn) + os.remove(tmpOut) + return processed + + +def messages(jsmsg): + defines = [] + for line in open(jsmsg): + match = re.match("MSG_DEF\((JSMSG_(\w+))", line) + if match: + defines.append("#define %s %i" % (match.group(1), len(defines))) + else: + # Make sure that MSG_DEF isn't preceded by whitespace + assert not line.strip().startswith("MSG_DEF") + return "\n".join(defines) + + +def get_config_defines(buildconfig): + # Collect defines equivalent to ACDEFINES and add MOZ_DEBUG_DEFINES. + env = buildconfig.defines["ALLDEFINES"] + for define in buildconfig.substs["MOZ_DEBUG_DEFINES"]: + env[define] = 1 + return env + + +def process_inputs(namespace, c_out, msg_file, inputs): + deps = [path for path in inputs if path.endswith(".h") or path.endswith(".h.js")] + sources = [ + path for path in inputs if path.endswith(".js") and not path.endswith(".h.js") + ] + assert len(deps) + len(sources) == len(inputs) + cxx = shlex.split(buildconfig.substs["CXX"]) + pp_option = buildconfig.substs["PREPROCESS_OPTION"] + cppflags = buildconfig.substs["OS_CPPFLAGS"] + cppflags += shlex.split(buildconfig.substs["WARNINGS_AS_ERRORS"]) + env = get_config_defines(buildconfig) + js_path = re.sub(r"\.out\.h$", "", c_out.name) + ".js" + msgs = messages(msg_file) + with open(js_path, "w") as js_out: + embed(cxx, pp_option, cppflags, msgs, sources, c_out, js_out, namespace, env) + + +def generate_selfhosted(c_out, msg_file, *inputs): + # Called from moz.build to embed selfhosted JS. + process_inputs("selfhosted", c_out, msg_file, inputs) + + +def generate_shellmoduleloader(c_out, msg_file, *inputs): + # Called from moz.build to embed shell module loader JS. + process_inputs("moduleloader", c_out, msg_file, inputs) |