tor-browser

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

GeneratePrefs.py (5941B)


      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 # This script generates js/public/PrefsGenerated.h from StaticPrefList.yaml
      6 
      7 import io
      8 
      9 import buildconfig
     10 import yaml
     11 from mozbuild.preprocessor import Preprocessor
     12 
     13 HEADER_TEMPLATE = """\
     14 /* This Source Code Form is subject to the terms of the Mozilla Public
     15 * License, v. 2.0. If a copy of the MPL was not distributed with this
     16 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     17 
     18 #ifndef js_PrefsGenerated_h
     19 #define js_PrefsGenerated_h
     20 
     21 /* This file is generated by js/src/GeneratePrefs.py. Do not edit! */
     22 
     23 #include "mozilla/Atomics.h"
     24 
     25 #include <stdint.h>
     26 
     27 %(contents)s
     28 
     29 #endif // js_PrefsGenerated_h
     30 """
     31 
     32 
     33 def load_yaml(yaml_path):
     34    # First invoke the preprocessor to handle #ifdefs in the YAML file.
     35    pp = Preprocessor()
     36    pp.context.update(buildconfig.defines["ALLDEFINES"])
     37 
     38    # To make #ifdef DEBUG work, use a similar hack as in emit_code in
     39    # generate_static_pref_list.py.
     40    if buildconfig.substs.get("MOZ_DEBUG"):
     41        pp.context["DEBUG"] = "1"
     42 
     43    pp.out = io.StringIO()
     44    pp.do_filter("substitution")
     45    pp.do_include(yaml_path)
     46    contents = pp.out.getvalue()
     47    return yaml.safe_load(contents)
     48 
     49 
     50 # Returns the C++ type to use for the pref type from the YAML file. Always use
     51 # the non-atomic type for return values and arguments. The field type is
     52 # determined elsewhere.
     53 def get_cpp_type(type):
     54    if type in ("bool", "RelaxedAtomicBool"):
     55        return "bool"
     56    if type in ("uint32_t", "RelaxedAtomicUint32"):
     57        return "uint32_t"
     58    if type in ("int32_t", "RelaxedAtomicInt32"):
     59        return "int32_t"
     60    raise Exception(f"Unexpected type: {type}")
     61 
     62 
     63 # Returns a C++ expression for the default pref value. Booleans in the YAML file
     64 # are converted to Pythonic True or False, so those need special handling.
     65 def get_cpp_init_value(val):
     66    if val is True:
     67        return "true"
     68    if val is False:
     69        return "false"
     70    return str(val)
     71 
     72 
     73 def generate_prefs_header(c_out, yaml_path):
     74    prefs = load_yaml(yaml_path)
     75 
     76    js_options_prefix = "javascript.options."
     77 
     78    def is_js_pref(pref):
     79        set_spidermonkey_pref = pref.get("set_spidermonkey_pref", False)
     80        if set_spidermonkey_pref not in (False, "startup", "always"):
     81            raise Exception("Invalid value for set_spidermonkey_pref")
     82 
     83        # Ignore prefs that don't have the |set_spidermonkey_pref| attribute.
     84        if set_spidermonkey_pref is False:
     85            return False
     86 
     87        # Only support prefs with javascript.options prefix.
     88        if not pref["name"].startswith(js_options_prefix):
     89            raise Exception("set_spidermonkey_pref only works for JS prefs")
     90 
     91        return True
     92 
     93    # Remove all non-JS prefs and sort prefs by name.
     94    prefs = list(filter(is_js_pref, prefs))
     95    prefs.sort(key=lambda pref: pref["name"])
     96 
     97    class_fields = []
     98    class_fields_inits = []
     99 
    100    macro_entries = []
    101    browser_set_statements = []
    102    browser_set_non_startup_statements = []
    103 
    104    for pref in prefs:
    105        name = pref["name"]
    106        name = name[len(js_options_prefix) :]
    107 
    108        is_startup_pref = pref["set_spidermonkey_pref"] == "startup"
    109 
    110        cpp_name = name.replace(".", "_").replace("-", "_")
    111        type = get_cpp_type(pref["type"])
    112        init_value = get_cpp_init_value(pref["value"])
    113 
    114        setter_name = ("setAtStartup_" if is_startup_pref else "set_") + cpp_name
    115 
    116        # Use a relaxed atomic for non-startup prefs because those might be changed
    117        # after startup.
    118        field_type = type
    119        if not is_startup_pref:
    120            field_type = f"mozilla::Atomic<{field_type}, mozilla::Relaxed>"
    121        class_fields.append(f"static {field_type} {cpp_name}_;")
    122        class_fields_inits.append(
    123            f"{field_type} JS::Prefs::{cpp_name}_{{{init_value}}};"
    124        )
    125 
    126        is_startup_pref_bool = "true" if is_startup_pref else "false"
    127 
    128        # Generate a MACRO invocation like this:
    129        #   MACRO("arraybuffer_transfer", arraybuffer_transfer, bool, setAtStartup_arraybuffer_transfer, true)
    130        macro_entries.append(
    131            f'MACRO("{name}", {cpp_name}, {type}, {setter_name}, {is_startup_pref_bool})'
    132        )
    133 
    134        # Generate a C++ statement to set the JS pref based on Gecko's StaticPrefs:
    135        #   JS::Prefs::setAtStartup_foo(StaticPrefs::javascript_options_foo());
    136        browser_pref_cpp_name = pref["name"].replace(".", "_").replace("-", "_")
    137        if pref.get("do_not_use_directly", False):
    138            browser_pref_cpp_name += "_DoNotUseDirectly"
    139 
    140        statement = f"JS::Prefs::{setter_name}(mozilla::StaticPrefs::{browser_pref_cpp_name}());"
    141        browser_set_statements.append(statement)
    142 
    143        # For non-startup prefs, also generate code to update the pref after startup.
    144        if not is_startup_pref:
    145            browser_set_non_startup_statements.append(statement)
    146 
    147    contents = ""
    148 
    149    contents += "#define JS_PREF_CLASS_FIELDS \\\n"
    150    contents += "".join(map(lambda s: f"  {s}\\\n", class_fields))
    151    contents += "\n\n"
    152 
    153    contents += "#define JS_PREF_CLASS_FIELDS_INIT \\\n"
    154    contents += "".join(map(lambda s: f"  {s}\\\n", class_fields_inits))
    155    contents += "\n\n"
    156 
    157    contents += "#define FOR_EACH_JS_PREF(MACRO) \\\n"
    158    contents += "".join(map(lambda s: f"  {s}\\\n", macro_entries))
    159    contents += "\n\n"
    160 
    161    contents += "#define SET_JS_PREFS_FROM_BROWSER_PREFS \\\n"
    162    contents += "".join(map(lambda s: f"  {s}\\\n", browser_set_statements))
    163    contents += "\n\n"
    164 
    165    contents += "#define SET_NON_STARTUP_JS_PREFS_FROM_BROWSER_PREFS \\\n"
    166    contents += "".join(map(lambda s: f"  {s}\\\n", browser_set_non_startup_statements))
    167    contents += "\n\n"
    168 
    169    c_out.write(
    170        HEADER_TEMPLATE
    171        % {
    172            "contents": contents,
    173        }
    174    )