summaryrefslogtreecommitdiffstats
path: root/js/src/GeneratePrefs.py
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/GeneratePrefs.py')
-rw-r--r--js/src/GeneratePrefs.py179
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,
+ }
+ )