tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

embedjs.py (7130B)


      1 # This Source Code Form is subject to the terms of the Mozilla Public
      2 # License, v. 2.0. If a copy of the MPL was not distributed with this
      3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 #
      5 # ToCAsciiArray and ToCArray are from V8's js2c.py.
      6 #
      7 # Copyright 2012 the V8 project authors. All rights reserved.
      8 # Redistribution and use in source and binary forms, with or without
      9 # modification, are permitted provided that the following conditions are
     10 # met:
     11 #
     12 #     * Redistributions of source code must retain the above copyright
     13 #       notice, this list of conditions and the following disclaimer.
     14 #     * Redistributions in binary form must reproduce the above
     15 #       copyright notice, this list of conditions and the following
     16 #       disclaimer in the documentation and/or other materials provided
     17 #       with the distribution.
     18 #     * Neither the name of Google Inc. nor the names of its
     19 #       contributors may be used to endorse or promote products derived
     20 #       from this software without specific prior written permission.
     21 #
     22 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     23 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     24 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     25 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     26 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     27 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     28 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     31 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     32 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33 
     34 # This utility converts JS files containing self-hosted builtins into a C
     35 # header file that can be embedded into SpiderMonkey.
     36 #
     37 # It uses the C preprocessor to process its inputs.
     38 
     39 import errno
     40 import os
     41 import re
     42 import shlex
     43 import subprocess
     44 import sys
     45 
     46 import buildconfig
     47 import mozpack.path as mozpath
     48 from mozfile import which
     49 
     50 
     51 def ToCAsciiArray(lines):
     52    result = []
     53    for chr in lines:
     54        value = ord(chr)
     55        assert value < 128
     56        result.append(str(value))
     57    return ", ".join(result)
     58 
     59 
     60 def ToCArray(lines):
     61    result = []
     62    for chr in lines:
     63        result.append(str(chr))
     64    return ", ".join(result)
     65 
     66 
     67 HEADER_TEMPLATE = """\
     68 /* This Source Code Form is subject to the terms of the Mozilla Public
     69 * License, v. 2.0. If a copy of the MPL was not distributed with this
     70 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     71 
     72 namespace js {
     73 namespace %(namespace)s {
     74    static const %(sources_type)s data[] = { %(sources_data)s };
     75 
     76    static const %(sources_type)s * const %(sources_name)s = reinterpret_cast<const %(sources_type)s *>(data);
     77 
     78    uint32_t GetCompressedSize() {
     79        return %(compressed_total_length)i;
     80    }
     81 
     82    uint32_t GetRawScriptsSize() {
     83        return %(raw_total_length)i;
     84    }
     85 } // selfhosted
     86 } // js
     87 """  # NOQA: E501
     88 
     89 
     90 def embed(
     91    cxx, preprocessorOption, cppflags, msgs, sources, c_out, js_out, namespace, env
     92 ):
     93    objdir = os.getcwd()
     94    # Use relative pathnames to avoid path translation issues in WSL.
     95    combinedSources = "\n".join(
     96        [msgs]
     97        + [
     98            '#include "%(s)s"' % {"s": mozpath.relpath(source, objdir)}
     99            for source in sources
    100        ]
    101    )
    102    args = cppflags + ["-D%(k)s=%(v)s" % {"k": k, "v": env[k]} for k in env]
    103    preprocessed = preprocess(cxx, preprocessorOption, combinedSources, args)
    104    processed = "\n".join([
    105        line
    106        for line in preprocessed.splitlines()
    107        if (line.strip() and not line.startswith("#"))
    108    ])
    109 
    110    js_out.write(processed)
    111    import zlib
    112 
    113    compressed = zlib.compress(processed.encode("utf-8"))
    114    data = ToCArray(compressed)
    115    c_out.write(
    116        HEADER_TEMPLATE
    117        % {
    118            "sources_type": "unsigned char",
    119            "sources_data": data,
    120            "sources_name": "compressedSources",
    121            "compressed_total_length": len(compressed),
    122            "raw_total_length": len(processed),
    123            "namespace": namespace,
    124        }
    125    )
    126 
    127 
    128 def preprocess(cxx, preprocessorOption, source, args=[]):
    129    if not os.path.exists(cxx[0]):
    130        binary = cxx[0]
    131        cxx[0] = which(binary)
    132        if not cxx[0]:
    133            raise OSError(errno.ENOENT, "%s not found on PATH" % binary)
    134 
    135    # Clang seems to complain and not output anything if the extension of the
    136    # input is not something it recognizes, so just fake a .cpp here.
    137    tmpIn = "self-hosting-cpp-input.cpp"
    138    tmpOut = "self-hosting-preprocessed.pp"
    139    outputArg = shlex.split(preprocessorOption + tmpOut)
    140 
    141    with open(tmpIn, "wb") as input:
    142        input.write(source.encode("utf-8"))
    143 
    144    if os.environ.get("BUILD_VERBOSE_LOG"):
    145        print("Executing:", " ".join(cxx + outputArg + args + [tmpIn]))
    146    result = subprocess.Popen(cxx + outputArg + args + [tmpIn]).wait()
    147    if result != 0:
    148        sys.exit(result)
    149    with open(tmpOut) as output:
    150        processed = output.read()
    151    os.remove(tmpIn)
    152    os.remove(tmpOut)
    153    return processed
    154 
    155 
    156 def messages(jsmsg):
    157    defines = []
    158    for line in open(jsmsg):
    159        match = re.match(r"MSG_DEF\((JSMSG_(\w+))", line)
    160        if match:
    161            defines.append("#define %s %i" % (match.group(1), len(defines)))
    162            continue
    163 
    164        # Make sure that MSG_DEF isn't preceded by whitespace
    165        assert not line.strip().startswith("MSG_DEF")
    166 
    167        # This script doesn't support preprocessor
    168        assert not line.strip().startswith("#")
    169    return "\n".join(defines)
    170 
    171 
    172 def get_config_defines(buildconfig):
    173    # Collect defines equivalent to ACDEFINES and add MOZ_DEBUG_DEFINES.
    174    env = buildconfig.defines["ALLDEFINES"]
    175    for define in buildconfig.substs["MOZ_DEBUG_DEFINES"]:
    176        env[define] = 1
    177    return env
    178 
    179 
    180 def process_inputs(namespace, c_out, msg_file, inputs):
    181    deps = [path for path in inputs if path.endswith(".h") or path.endswith(".h.js")]
    182    sources = [
    183        path for path in inputs if path.endswith(".js") and not path.endswith(".h.js")
    184    ]
    185    assert len(deps) + len(sources) == len(inputs)
    186    cxx = shlex.split(buildconfig.substs["CXX"])
    187    pp_option = buildconfig.substs["PREPROCESS_OPTION"]
    188    cppflags = buildconfig.substs["OS_CPPFLAGS"]
    189    cppflags += shlex.split(buildconfig.substs["WARNINGS_AS_ERRORS"])
    190    env = get_config_defines(buildconfig)
    191    js_path = re.sub(r"\.out\.h$", "", c_out.name) + ".js"
    192    msgs = messages(msg_file)
    193    with open(js_path, "w") as js_out:
    194        embed(cxx, pp_option, cppflags, msgs, sources, c_out, js_out, namespace, env)
    195 
    196 
    197 def generate_selfhosted(c_out, msg_file, *inputs):
    198    # Called from moz.build to embed selfhosted JS.
    199    process_inputs("selfhosted", c_out, msg_file, inputs)
    200 
    201 
    202 def generate_shellmoduleloader(c_out, msg_file, *inputs):
    203    # Called from moz.build to embed shell module loader JS.
    204    process_inputs("moduleloader", c_out, msg_file, inputs)