Commit eb90b106 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

bind-gen: Fix context-dependent property installation

Bug: 839389
Change-Id: I99856b3f70ed21a8bd1b618dd877d41b6b83f3d5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2220419Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#774038}
parent 599d300f
...@@ -143,7 +143,9 @@ def expr_uniq(terms): ...@@ -143,7 +143,9 @@ def expr_uniq(terms):
return uniq_terms return uniq_terms
def expr_from_exposure(exposure, global_names=None): def expr_from_exposure(exposure,
global_names=None,
may_use_feature_selector=False):
""" """
Returns an expression to determine whether this property should be exposed Returns an expression to determine whether this property should be exposed
or not. or not.
...@@ -152,30 +154,75 @@ def expr_from_exposure(exposure, global_names=None): ...@@ -152,30 +154,75 @@ def expr_from_exposure(exposure, global_names=None):
exposure: web_idl.Exposure of the target construct. exposure: web_idl.Exposure of the target construct.
global_names: When specified, it's taken into account that the global global_names: When specified, it's taken into account that the global
object implements |global_names|. object implements |global_names|.
may_use_feature_selector: True enables use of ${feature_selector} iff
the exposure is context dependent.
""" """
assert isinstance(exposure, web_idl.Exposure) assert isinstance(exposure, web_idl.Exposure)
assert (global_names is None assert (global_names is None
or (isinstance(global_names, (list, tuple)) or (isinstance(global_names, (list, tuple))
and all(isinstance(name, str) for name in global_names))) and all(isinstance(name, str) for name in global_names)))
# The property exposures are categorized into three.
# - Unconditional: Always exposed.
# - Context-independent: Enabled per v8::Isolate.
# - Context-dependent: Enabled per v8::Context, e.g. origin trials.
#
# Context-dependent properties can be installed in two phases.
# - The first phase installs all the properties that are associated with the
# features enabled at the moment. This phase is represented by
# FeatureSelector as FeatureSelector.IsAll().
# - The second phase installs the properties associated with the specified
# feature. This phase is represented as FeatureSelector.IsAny(feature).
#
# The exposure condition is represented as;
# (and feature_selector-independent-term
# (or
# feature_selector-1st-phase-term
# feature_selector-2nd-phase-term))
# which can be represented in more details as:
# (and secure_context_term
# uncond_exposed_term
# (or
# (and feature_selector.IsAll() # 1st phase; all enabled
# cond_exposed_term
# feature_enabled_term)
# (or exposed_selector_term # 2nd phase; any selected
# feature_selector_term)))
# where
# secure_context_term represents [SecureContext=F1]
# uncond_exposed_term represents [Exposed=(G1, G2)]
# cond_exposed_term represents [Exposed(G1 F1, G2 F2)]
# feature_enabled_term represents [RuntimeEnabled=(F1, F2)]
# exposed_selector_term represents [Exposed(G1 F1, G2 F2)]
# feature_selector_term represents [RuntimeEnabled=(F1, F2)]
uncond_exposed_terms = []
cond_exposed_terms = []
feature_enabled_terms = []
exposed_selector_terms = []
feature_selector_names = [] # Will turn into feature_selector.IsAnyOf(...)
def ref_enabled(feature): def ref_enabled(feature):
arg = "${execution_context}" if feature.is_context_dependent else "" arg = "${execution_context}" if feature.is_context_dependent else ""
return _Expr("RuntimeEnabledFeatures::{}Enabled({})".format( return _Expr("RuntimeEnabledFeatures::{}Enabled({})".format(
feature, arg)) feature, arg))
top_terms = [_Expr(True)] def ref_selected(features):
feature_tokens = map(
lambda feature: "OriginTrialFeature::k{}".format(feature),
features)
return _Expr("${{feature_selector}}.IsAnyOf({})".format(
", ".join(feature_tokens)))
# [SecureContext] # [SecureContext]
if exposure.only_in_secure_contexts is True: if exposure.only_in_secure_contexts is True:
top_terms.append(_Expr("${is_in_secure_context}")) secure_context_term = _Expr("${is_in_secure_context}")
elif exposure.only_in_secure_contexts is False: elif exposure.only_in_secure_contexts is False:
top_terms.append(_Expr(True)) secure_context_term = _Expr(True)
else: else:
terms = map(ref_enabled, exposure.only_in_secure_contexts) terms = map(ref_enabled, exposure.only_in_secure_contexts)
top_terms.append( secure_context_term = expr_or(
expr_or( [_Expr("${is_in_secure_context}"),
[_Expr("${is_in_secure_context}"), expr_not(expr_and(terms))])
expr_not(expr_and(terms))]))
# [Exposed] # [Exposed]
GLOBAL_NAME_TO_EXECUTION_CONTEXT_TEST = { GLOBAL_NAME_TO_EXECUTION_CONTEXT_TEST = {
...@@ -190,7 +237,6 @@ def expr_from_exposure(exposure, global_names=None): ...@@ -190,7 +237,6 @@ def expr_from_exposure(exposure, global_names=None):
"Worker": "IsWorkerGlobalScope", "Worker": "IsWorkerGlobalScope",
"Worklet": "IsWorkletGlobalScope", "Worklet": "IsWorkletGlobalScope",
} }
exposed_terms = []
if global_names: if global_names:
matched_global_count = 0 matched_global_count = 0
for entry in exposure.global_names_and_features: for entry in exposure.global_names_and_features:
...@@ -198,39 +244,62 @@ def expr_from_exposure(exposure, global_names=None): ...@@ -198,39 +244,62 @@ def expr_from_exposure(exposure, global_names=None):
continue continue
matched_global_count += 1 matched_global_count += 1
if entry.feature: if entry.feature:
exposed_terms.append(ref_enabled(entry.feature)) cond_exposed_terms.append(ref_enabled(entry.feature))
if entry.feature.is_context_dependent:
feature_selector_names.append(entry.feature)
assert (not exposure.global_names_and_features assert (not exposure.global_names_and_features
or matched_global_count > 0) or matched_global_count > 0)
else: else:
for entry in exposure.global_names_and_features: for entry in exposure.global_names_and_features:
terms = [] pred_term = _Expr("${{execution_context}}->{}()".format(
pred = GLOBAL_NAME_TO_EXECUTION_CONTEXT_TEST[entry.global_name] GLOBAL_NAME_TO_EXECUTION_CONTEXT_TEST[entry.global_name]))
terms.append(_Expr("${{execution_context}}->{}()".format(pred))) if not entry.feature:
if entry.feature: uncond_exposed_terms.append(pred_term)
terms.append(ref_enabled(entry.feature)) else:
if terms: cond_exposed_terms.append(
exposed_terms.append(expr_and(terms)) expr_and([pred_term, ref_enabled(entry.feature)]))
if exposed_terms: if entry.feature.is_context_dependent:
top_terms.append(expr_or(exposed_terms)) exposed_selector_terms.append(
expr_and([pred_term,
ref_selected([entry.feature])]))
# [RuntimeEnabled] # [RuntimeEnabled]
if exposure.runtime_enabled_features: if exposure.runtime_enabled_features:
terms = map(ref_enabled, exposure.runtime_enabled_features) feature_enabled_terms.extend(
top_terms.append(expr_or(terms)) map(ref_enabled, exposure.runtime_enabled_features))
feature_selector_names.extend(
return expr_and(top_terms) exposure.context_dependent_runtime_enabled_features)
# Build an expression.
def expr_of_feature_selector(exposure): top_level_terms = []
""" top_level_terms.append(secure_context_term)
Returns an expression that tells whether this property is a target of the if uncond_exposed_terms:
feature selector or not. top_level_terms.append(expr_or(uncond_exposed_terms))
Args: if not (may_use_feature_selector
exposure: web_idl.Exposure of the target construct. and exposure.is_context_dependent(global_names)):
""" if cond_exposed_terms:
assert isinstance(exposure, web_idl.Exposure) top_level_terms.append(expr_or(cond_exposed_terms))
if feature_enabled_terms:
features = map(lambda feature: "OriginTrialFeature::k{}".format(feature), top_level_terms.append(expr_and(feature_enabled_terms))
exposure.context_dependent_runtime_enabled_features) return expr_and(top_level_terms)
return _Expr("${{feature_selector}}.AnyOf({})".format(", ".join(features)))
all_enabled_terms = [_Expr("${feature_selector}.IsAll()")]
if cond_exposed_terms:
all_enabled_terms.append(expr_or(cond_exposed_terms))
if feature_enabled_terms:
all_enabled_terms.append(expr_or(feature_enabled_terms))
selector_terms = []
if exposed_selector_terms:
selector_terms.append(expr_or(exposed_selector_terms))
if feature_selector_names:
selector_terms.append(ref_selected(feature_selector_names))
terms = []
terms.append(expr_and(all_enabled_terms))
if selector_terms:
terms.append(expr_or(selector_terms))
top_level_terms.append(expr_or(terms))
return expr_and(top_level_terms)
...@@ -37,7 +37,6 @@ from .codegen_context import CodeGenContext ...@@ -37,7 +37,6 @@ from .codegen_context import CodeGenContext
from .codegen_expr import CodeGenExpr from .codegen_expr import CodeGenExpr
from .codegen_expr import expr_and from .codegen_expr import expr_and
from .codegen_expr import expr_from_exposure from .codegen_expr import expr_from_exposure
from .codegen_expr import expr_of_feature_selector
from .codegen_expr import expr_or from .codegen_expr import expr_or
from .codegen_format import format_template as _format from .codegen_format import format_template as _format
from .codegen_utils import component_export from .codegen_utils import component_export
...@@ -4483,8 +4482,10 @@ def _make_property_entries_and_callback_defs( ...@@ -4483,8 +4482,10 @@ def _make_property_entries_and_callback_defs(
for member in members: for member in members:
is_context_dependent = member.exposure.is_context_dependent( is_context_dependent = member.exposure.is_context_dependent(
global_names) global_names)
exposure_conditional = expr_from_exposure(member.exposure, exposure_conditional = expr_from_exposure(
global_names) member.exposure,
global_names=global_names,
may_use_feature_selector=True)
if "PerWorldBindings" in member.extended_attributes: if "PerWorldBindings" in member.extended_attributes:
worlds = (CodeGenContext.MAIN_WORLD, worlds = (CodeGenContext.MAIN_WORLD,
...@@ -5151,9 +5152,8 @@ def make_install_properties(cg_context, function_name, class_name, ...@@ -5151,9 +5152,8 @@ def make_install_properties(cg_context, function_name, class_name,
if is_context_dependent and install_prototype_object_node: if is_context_dependent and install_prototype_object_node:
body.extend([ body.extend([
CxxLikelyIfNode( CxxLikelyIfNode(cond="${feature_selector}.IsAll()",
cond="${feature_selector}.AnyOf()", body=[install_prototype_object_node]),
body=[install_prototype_object_node]),
EmptyNode(), EmptyNode(),
]) ])
...@@ -5181,11 +5181,6 @@ def make_install_properties(cg_context, function_name, class_name, ...@@ -5181,11 +5181,6 @@ def make_install_properties(cg_context, function_name, class_name,
])) ]))
body.append(EmptyNode()) body.append(EmptyNode())
for conditional, entries in conditional_to_entries.items(): for conditional, entries in conditional_to_entries.items():
if is_context_dependent:
conditional = expr_and([
expr_of_feature_selector(entries[0].property_.exposure),
conditional,
])
body.append( body.append(
CxxUnlikelyIfNode( CxxUnlikelyIfNode(
cond=conditional, cond=conditional,
...@@ -6634,11 +6629,16 @@ using InstallFuncType = ...@@ -6634,11 +6629,16 @@ using InstallFuncType =
for member in itertools.chain(interface.attributes, for member in itertools.chain(interface.attributes,
interface.constants, interface.constants,
interface.operation_groups): interface.operation_groups,
for feature in (member.exposure. interface.exposed_constructs):
context_dependent_runtime_enabled_features): features = list(
member.exposure.context_dependent_runtime_enabled_features)
for entry in member.exposure.global_names_and_features:
if entry.feature and entry.feature.is_context_dependent:
features.append(entry.feature)
for feature in features:
feature_to_interfaces.setdefault(feature, set()).add(interface) feature_to_interfaces.setdefault(feature, set()).add(interface)
if member.exposure.context_dependent_runtime_enabled_features: if features:
set_of_interfaces.add(interface) set_of_interfaces.add(interface)
switch_node = CxxSwitchNode(cond="${feature}") switch_node = CxxSwitchNode(cond="${feature}")
......
...@@ -53,16 +53,19 @@ class PLATFORM_EXPORT V8InterfaceBridgeBase { ...@@ -53,16 +53,19 @@ class PLATFORM_EXPORT V8InterfaceBridgeBase {
FeatureSelector& operator=(const FeatureSelector&) = default; FeatureSelector& operator=(const FeatureSelector&) = default;
FeatureSelector& operator=(FeatureSelector&&) = default; FeatureSelector& operator=(FeatureSelector&&) = default;
// Returns true if all properties that are associated with the features
// enabled at this moment should be installed.
bool IsAll() const { return does_select_all_; }
// Returns true if properties should be installed. Arguments |featureN| // Returns true if properties should be installed. Arguments |featureN|
// represent the origin trial features to which the properties are // represent the origin trial features to which the properties are
// associated. No argument means that the properties are not associated // associated.
// with any origin trial feature. bool IsAnyOf(OriginTrialFeature feature1) const {
bool AnyOf() const { return does_select_all_; } return selector_ == feature1;
bool AnyOf(OriginTrialFeature feature1) const {
return does_select_all_ || selector_ == feature1;
} }
bool AnyOf(OriginTrialFeature feature1, OriginTrialFeature feature2) const { bool IsAnyOf(OriginTrialFeature feature1,
return does_select_all_ || selector_ == feature1 || selector_ == feature2; OriginTrialFeature feature2) const {
return selector_ == feature1 || selector_ == feature2;
} }
private: private:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment