# 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,
}
)