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 )