diff options
Diffstat (limited to 'js/src/GeneratePrefs.py')
-rw-r--r-- | js/src/GeneratePrefs.py | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/js/src/GeneratePrefs.py b/js/src/GeneratePrefs.py new file mode 100644 index 0000000000..b28114c259 --- /dev/null +++ b/js/src/GeneratePrefs.py @@ -0,0 +1,179 @@ +# 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 <stdint.h> + +%(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, + } + ) |