# 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/. # This script generates js/public/PrefsGenerated.h from StaticPrefList.yaml import buildconfig import six import yaml from mozbuild.preprocessor import Preprocessor 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/. */ #ifndef js_PrefsGenerated_h #define js_PrefsGenerated_h /* This file is generated by js/src/GeneratePrefs.py. Do not edit! */ #include "mozilla/Atomics.h" #include %(contents)s #endif // js_PrefsGenerated_h """ def load_yaml(yaml_path): # First invoke the preprocessor to handle #ifdefs in the YAML file. pp = Preprocessor() pp.context.update(buildconfig.defines["ALLDEFINES"]) # To make #ifdef DEBUG work, use a similar hack as in emit_code in # generate_static_pref_list.py. if buildconfig.substs.get("MOZ_DEBUG"): pp.context["DEBUG"] = "1" pp.out = six.StringIO() pp.do_filter("substitution") pp.do_include(yaml_path) contents = pp.out.getvalue() return yaml.safe_load(contents) # Returns the C++ type to use for the pref type from the YAML file. Always use # the non-atomic type for return values and arguments. The field type is # determined elsewhere. def get_cpp_type(type): if type in ("bool", "RelaxedAtomicBool"): return "bool" if type in ("uint32_t", "RelaxedAtomicUint32"): return "uint32_t" if type in ("int32_t", "RelaxedAtomicInt32"): return "int32_t" raise Exception("Unexpected type: {}".format(type)) # Returns a C++ expression for the default pref value. Booleans in the YAML file # are converted to Pythonic True or False, so those need special handling. def get_cpp_init_value(val): if val is True: return "true" if val is False: return "false" return str(val) def generate_prefs_header(c_out, yaml_path): prefs = load_yaml(yaml_path) js_options_prefix = "javascript.options." def is_js_pref(pref): set_spidermonkey_pref = pref.get("set_spidermonkey_pref", False) if set_spidermonkey_pref not in (False, "startup", "always"): raise Exception("Invalid value for set_spidermonkey_pref") # Ignore prefs that don't have the |set_spidermonkey_pref| attribute. if set_spidermonkey_pref is False: return False # Only support prefs with javascript.options prefix. if not pref["name"].startswith(js_options_prefix): raise Exception("set_spidermonkey_pref only works for JS prefs") return True # Remove all non-JS prefs and sort prefs by name. prefs = list(filter(is_js_pref, prefs)) prefs.sort(key=lambda pref: pref["name"]) class_fields = [] class_fields_inits = [] macro_entries = [] browser_set_statements = [] browser_set_non_startup_statements = [] for pref in prefs: name = pref["name"] name = name[len(js_options_prefix) :] is_startup_pref = pref["set_spidermonkey_pref"] == "startup" cpp_name = name.replace(".", "_").replace("-", "_") type = get_cpp_type(pref["type"]) init_value = get_cpp_init_value(pref["value"]) setter_name = ("setAtStartup_" if is_startup_pref else "set_") + cpp_name # Use a relaxed atomic for non-startup prefs because those might be changed # after startup. field_type = type if not is_startup_pref: field_type = "mozilla::Atomic<{}, mozilla::Relaxed>".format(field_type) class_fields.append("static {} {}_;".format(field_type, cpp_name)) class_fields_inits.append( "{} JS::Prefs::{}_{{{}}};".format(field_type, cpp_name, init_value) ) is_startup_pref_bool = "true" if is_startup_pref else "false" # Generate a MACRO invocation like this: # MACRO("arraybuffer_transfer", arraybuffer_transfer, bool, setAtStartup_arraybuffer_transfer, true) macro_entries.append( 'MACRO("{}", {}, {}, {}, {})'.format( name, cpp_name, type, setter_name, is_startup_pref_bool ) ) # Generate a C++ statement to set the JS pref based on Gecko's StaticPrefs: # JS::Prefs::setAtStartup_foo(StaticPrefs::javascript_options_foo()); browser_pref_cpp_name = pref["name"].replace(".", "_").replace("-", "_") if pref.get("do_not_use_directly", False): browser_pref_cpp_name += "_DoNotUseDirectly" statement = "JS::Prefs::{}(mozilla::StaticPrefs::{}());".format( setter_name, browser_pref_cpp_name ) browser_set_statements.append(statement) # For non-startup prefs, also generate code to update the pref after startup. if not is_startup_pref: browser_set_non_startup_statements.append(statement) contents = "" contents += "#define JS_PREF_CLASS_FIELDS \\\n" contents += "".join(map(lambda s: " {}\\\n".format(s), class_fields)) contents += "\n\n" contents += "#define JS_PREF_CLASS_FIELDS_INIT \\\n" contents += "".join(map(lambda s: " {}\\\n".format(s), class_fields_inits)) contents += "\n\n" contents += "#define FOR_EACH_JS_PREF(MACRO) \\\n" contents += "".join(map(lambda s: " {}\\\n".format(s), macro_entries)) contents += "\n\n" contents += "#define SET_JS_PREFS_FROM_BROWSER_PREFS \\\n" contents += "".join(map(lambda s: " {}\\\n".format(s), browser_set_statements)) contents += "\n\n" contents += "#define SET_NON_STARTUP_JS_PREFS_FROM_BROWSER_PREFS \\\n" contents += "".join( map(lambda s: " {}\\\n".format(s), browser_set_non_startup_statements) ) contents += "\n\n" c_out.write( HEADER_TEMPLATE % { "contents": contents, } )