1# Copyright 2019 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import itertools 6 7import web_idl 8 9from . import name_style 10from .blink_v8_bridge import blink_class_name 11from .blink_v8_bridge import blink_type_info 12from .blink_v8_bridge import make_v8_to_blink_value 13from .blink_v8_bridge import make_v8_to_blink_value_variadic 14from .blink_v8_bridge import v8_bridge_class_name 15from .code_node import EmptyNode 16from .code_node import ListNode 17from .code_node import SequenceNode 18from .code_node import SymbolDefinitionNode 19from .code_node import SymbolNode 20from .code_node import SymbolScopeNode 21from .code_node import TextNode 22from .code_node import WeakDependencyNode 23from .code_node_cxx import CxxBlockNode 24from .code_node_cxx import CxxBreakableBlockNode 25from .code_node_cxx import CxxClassDefNode 26from .code_node_cxx import CxxFuncDeclNode 27from .code_node_cxx import CxxFuncDefNode 28from .code_node_cxx import CxxLikelyIfNode 29from .code_node_cxx import CxxMultiBranchesNode 30from .code_node_cxx import CxxNamespaceNode 31from .code_node_cxx import CxxSwitchNode 32from .code_node_cxx import CxxUnlikelyIfNode 33from .codegen_accumulator import CodeGenAccumulator 34from .codegen_context import CodeGenContext 35from .codegen_expr import CodeGenExpr 36from .codegen_expr import expr_and 37from .codegen_expr import expr_from_exposure 38from .codegen_expr import expr_or 39from .codegen_format import format_template as _format 40from .codegen_utils import component_export 41from .codegen_utils import component_export_header 42from .codegen_utils import enclose_with_header_guard 43from .codegen_utils import make_copyright_header 44from .codegen_utils import make_forward_declarations 45from .codegen_utils import make_header_include_directives 46from .codegen_utils import write_code_node_to_file 47from .mako_renderer import MakoRenderer 48from .package_initializer import package_initializer 49from .path_manager import PathManager 50from .task_queue import TaskQueue 51 52 53def _is_none_or_str(arg): 54 return arg is None or isinstance(arg, str) 55 56 57def backward_compatible_api_func(cg_context): 58 """ 59 Returns the Blink function name compatible with the old bindings generator. 60 """ 61 assert isinstance(cg_context, CodeGenContext) 62 63 name = (cg_context.member_like.code_generator_info.property_implemented_as 64 or cg_context.member_like.identifier 65 or cg_context.property_.identifier) 66 67 if cg_context.attribute_get: 68 # modules/webaudio/biquad_filter_node.idl has readonly attribute "Q" 69 # and somehow it's implemented as "q" in Blink. 70 if name == "Q": 71 name = "q" 72 73 if cg_context.attribute_set: 74 tokens = name_style.raw.tokenize(name) 75 if tokens[0] in ("IDL", "css", "xml"): 76 tokens[0] = tokens[0].upper() 77 else: 78 tokens[0] = tokens[0].capitalize() 79 tokens.insert(0, "set") 80 name = "".join(tokens) 81 82 if cg_context.indexed_property_getter and not name: 83 name = "AnonymousIndexedGetter" 84 if cg_context.indexed_property_setter and not name: 85 name = "AnonymousIndexedSetter" 86 if cg_context.named_property_getter and not name: 87 name = "AnonymousNamedGetter" 88 if cg_context.named_property_setter and not name: 89 name = "AnonymousNamedSetter" 90 if cg_context.named_property_deleter and not name: 91 name = "AnonymousNamedDeleter" 92 93 return name 94 95 96def callback_function_name(cg_context, 97 overload_index=None, 98 for_cross_origin=False, 99 no_alloc_direct_call=False): 100 assert isinstance(cg_context, CodeGenContext) 101 102 def _cxx_name(name): 103 """ 104 Returns a property name that the bindings generator can use in 105 generated code. 106 107 Note that Web IDL allows '-' (hyphen-minus) and '_' (low line) in 108 identifiers but C++ does not allow or recommend them. This function 109 encodes these characters. 110 """ 111 # In Python3, we can use str.maketrans and str.translate. 112 # 113 # We're optimistic about name conflict. It's highly unlikely that 114 # these replacements will cause a conflict. 115 assert "Dec45" not in name 116 assert "Dec95" not in name 117 name = name.replace("-", "Dec45") 118 name = name.replace("_", "Dec95") 119 return name 120 121 if cg_context.constant: 122 property_name = cg_context.property_.identifier 123 else: 124 property_name = _cxx_name(cg_context.property_.identifier) 125 126 if cg_context.attribute_get: 127 kind = "AttributeGet" 128 elif cg_context.attribute_set: 129 kind = "AttributeSet" 130 elif cg_context.constant: 131 kind = "Constant" 132 elif cg_context.constructor_group: 133 if cg_context.is_named_constructor: 134 kind = "NamedConstructor" 135 else: 136 property_name = "" 137 kind = "Constructor" 138 elif cg_context.exposed_construct: 139 if cg_context.is_named_constructor: 140 kind = "NamedConstructorProperty" 141 elif cg_context.legacy_window_alias: 142 kind = "LegacyWindowAlias" 143 else: 144 kind = "ExposedConstruct" 145 elif cg_context.operation_group: 146 kind = "Operation" 147 elif cg_context.stringifier: 148 kind = "Operation" 149 150 if for_cross_origin: 151 suffix = "CrossOrigin" 152 elif overload_index is not None: 153 suffix = "Overload{}".format(overload_index + 1) 154 elif no_alloc_direct_call: 155 suffix = "NoAllocDirectCallback" 156 else: 157 suffix = "Callback" 158 159 if cg_context.for_world == CodeGenContext.MAIN_WORLD: 160 world_suffix = "ForMainWorld" 161 elif cg_context.for_world == CodeGenContext.NON_MAIN_WORLDS: 162 world_suffix = "ForNonMainWorlds" 163 elif cg_context.for_world == CodeGenContext.ALL_WORLDS: 164 world_suffix = "" 165 166 return name_style.func(property_name, kind, suffix, world_suffix) 167 168 169def constant_name(cg_context): 170 assert isinstance(cg_context, CodeGenContext) 171 assert cg_context.constant 172 173 property_name = cg_context.property_.identifier.lower() 174 175 return name_style.constant(property_name) 176 177 178def custom_function_name(cg_context): 179 assert isinstance(cg_context, CodeGenContext) 180 181 if cg_context.named_property_getter: 182 return "NamedPropertyGetterCustom" 183 if cg_context.named_property_setter: 184 return "NamedPropertySetterCustom" 185 if cg_context.named_property_deleter: 186 return "NamedPropertyDeleterCustom" 187 188 if cg_context.attribute_get: 189 suffix = "AttributeGetterCustom" 190 elif cg_context.attribute_set: 191 suffix = "AttributeSetterCustom" 192 elif cg_context.operation_group: 193 suffix = "MethodCustom" 194 else: 195 assert False 196 197 return name_style.func(cg_context.property_.identifier, suffix) 198 199 200# ---------------------------------------------------------------------------- 201# Callback functions 202# ---------------------------------------------------------------------------- 203 204 205def bind_blink_api_arguments(code_node, cg_context): 206 assert isinstance(code_node, SymbolScopeNode) 207 assert isinstance(cg_context, CodeGenContext) 208 209 if cg_context.attribute_get: 210 return 211 212 if cg_context.attribute_set: 213 real_type = cg_context.attribute.idl_type.unwrap(typedef=True) 214 if real_type.is_enumeration: 215 pattern = """\ 216// https://heycam.github.io/webidl/#dfn-attribute-setter 217// step 4.6.1. Let S be ? ToString(V). 218const auto&& arg1_value_string = 219 NativeValueTraits<IDLStringV2>::NativeValue( 220 ${isolate}, ${v8_property_value}, ${exception_state}); 221if (${exception_state}.HadException()) 222 return; 223// step 4.6.2. If S is not one of the enumeration's values, then return 224// undefined. 225const auto arg1_value_maybe_enum = {enum_type}::Create(arg1_value_string); 226if (!arg1_value_maybe_enum) {{ 227 bindings::ReportInvalidEnumSetToAttribute( 228 ${isolate}, arg1_value_string, "{enum_type_name}", ${exception_state}); 229 return; // Return undefined. 230}} 231const auto ${arg1_value} = arg1_value_maybe_enum.value(); 232""" 233 text = _format(pattern, 234 enum_type=blink_class_name( 235 real_type.type_definition_object), 236 enum_type_name=real_type.identifier) 237 code_node.register_code_symbol(SymbolNode("arg1_value", text)) 238 return 239 240 name = "arg1_value" 241 v8_value = "${v8_property_value}" 242 code_node.register_code_symbol( 243 make_v8_to_blink_value(name, v8_value, 244 cg_context.attribute.idl_type)) 245 return 246 247 for index, argument in enumerate(cg_context.function_like.arguments): 248 name = name_style.arg_f("arg{}_{}", index + 1, argument.identifier) 249 if argument.is_variadic: 250 code_node.register_code_symbol( 251 make_v8_to_blink_value_variadic(name, "${info}", index, 252 argument.idl_type)) 253 else: 254 v8_value = "${{info}}[{}]".format(argument.index) 255 code_node.register_code_symbol( 256 make_v8_to_blink_value(name, 257 v8_value, 258 argument.idl_type, 259 argument_index=index, 260 default_value=argument.default_value, 261 cg_context=cg_context)) 262 263 264def bind_callback_local_vars(code_node, cg_context): 265 assert isinstance(code_node, SymbolScopeNode) 266 assert isinstance(cg_context, CodeGenContext) 267 268 S = SymbolNode 269 T = TextNode 270 271 local_vars = [] 272 template_vars = {} 273 274 local_vars.extend([ 275 S("blink_property_name", 276 ("const AtomicString& ${blink_property_name} = " 277 "ToCoreAtomicString(${v8_property_name}.As<v8::String>());")), 278 S("class_like_name", ("const char* const ${class_like_name} = " 279 "\"${class_like.identifier}\";")), 280 S("current_context", ("v8::Local<v8::Context> ${current_context} = " 281 "${isolate}->GetCurrentContext();")), 282 S("current_script_state", ("ScriptState* ${current_script_state} = " 283 "ScriptState::From(${current_context});")), 284 S("isolate", "v8::Isolate* ${isolate} = ${info}.GetIsolate();"), 285 S("non_undefined_argument_length", 286 ("const int ${non_undefined_argument_length} = " 287 "bindings::NonUndefinedArgumentLength(${info});")), 288 S("per_context_data", ("V8PerContextData* ${per_context_data} = " 289 "${script_state}->PerContextData();")), 290 S("per_isolate_data", ("V8PerIsolateData* ${per_isolate_data} = " 291 "V8PerIsolateData::From(${isolate});")), 292 S("property_name", 293 "const char* const ${property_name} = \"${property.identifier}\";"), 294 S("receiver_context", ("v8::Local<v8::Context> ${receiver_context} = " 295 "${v8_receiver}->CreationContext();")), 296 S("receiver_script_state", 297 ("ScriptState* ${receiver_script_state} = " 298 "ScriptState::From(${receiver_context});")), 299 ]) 300 301 is_receiver_context = not ( 302 (cg_context.member_like and cg_context.member_like.is_static) 303 or cg_context.constructor) 304 305 # creation_context 306 pattern = "const v8::Local<v8::Context>& ${creation_context} = {_1};" 307 _1 = "${receiver_context}" if is_receiver_context else "${current_context}" 308 local_vars.append(S("creation_context", _format(pattern, _1=_1))) 309 310 # creation_context_object 311 text = ("${v8_receiver}" 312 if is_receiver_context else "${current_context}->Global()") 313 template_vars["creation_context_object"] = T(text) 314 315 # script_state 316 pattern = "ScriptState* ${script_state} = {_1};" 317 _1 = ("${receiver_script_state}" 318 if is_receiver_context else "${current_script_state}") 319 local_vars.append(S("script_state", _format(pattern, _1=_1))) 320 321 # execution_context 322 pattern = "ExecutionContext* ${execution_context} = {_1};" 323 _1 = ("${receiver_execution_context}" 324 if is_receiver_context else "${current_execution_context}") 325 local_vars.append(S("execution_context", _format(pattern, _1=_1))) 326 node = S("current_execution_context", 327 ("ExecutionContext* ${current_execution_context} = " 328 "ExecutionContext::From(${current_context});")) 329 node.accumulate( 330 CodeGenAccumulator.require_include_headers([ 331 "third_party/blink/renderer/core/execution_context/execution_context.h" 332 ])) 333 local_vars.append(node) 334 node = S("receiver_execution_context", 335 ("ExecutionContext* ${receiver_execution_context} = " 336 "ExecutionContext::From(${receiver_context});")) 337 node.accumulate( 338 CodeGenAccumulator.require_include_headers([ 339 "third_party/blink/renderer/core/execution_context/execution_context.h" 340 ])) 341 local_vars.append(node) 342 343 # execution_context_of_document_tree 344 pattern = "ExecutionContext* ${execution_context_of_document_tree} = {_1};" 345 if is_receiver_context: 346 _1 = "bindings::ExecutionContextFromV8Wrappable(${blink_receiver})" 347 else: 348 _1 = "${current_execution_context}" 349 text = _format(pattern, _1=_1) 350 local_vars.append(S("execution_context_of_document_tree", text)) 351 352 # exception_state_context_type 353 pattern = ( 354 "const ExceptionState::ContextType ${exception_state_context_type} = " 355 "{_1};") 356 if cg_context.attribute_get: 357 _1 = "ExceptionState::kGetterContext" 358 elif cg_context.attribute_set: 359 _1 = "ExceptionState::kSetterContext" 360 elif cg_context.constructor_group: 361 _1 = "ExceptionState::kConstructionContext" 362 elif cg_context.indexed_property_getter: 363 _1 = "ExceptionState::kIndexedGetterContext" 364 elif cg_context.indexed_property_setter: 365 _1 = "ExceptionState::kIndexedSetterContext" 366 elif cg_context.named_property_getter: 367 _1 = "ExceptionState::kNamedGetterContext" 368 elif cg_context.named_property_setter: 369 _1 = "ExceptionState::kNamedSetterContext" 370 elif cg_context.named_property_deleter: 371 _1 = "ExceptionState::kNamedDeletionContext" 372 else: 373 _1 = "ExceptionState::kExecutionContext" 374 local_vars.append( 375 S("exception_state_context_type", _format(pattern, _1=_1))) 376 377 # exception_state 378 pattern = "ExceptionState ${exception_state}({_1});{_2}" 379 _1 = ["${isolate}", "${exception_state_context_type}"] 380 if cg_context.is_named_constructor: 381 _1.append("\"{}\"".format(cg_context.property_.identifier)) 382 else: 383 _1.append("${class_like_name}") 384 if (cg_context.property_ and cg_context.property_.identifier 385 and not cg_context.constructor_group): 386 _1.append("${property_name}") 387 _2 = "" 388 if cg_context.is_return_type_promise_type: 389 _2 = ("\n" 390 "ExceptionToRejectPromiseScope reject_promise_scope" 391 "(${info}, ${exception_state});") 392 local_vars.append( 393 S("exception_state", _format(pattern, _1=", ".join(_1), _2=_2))) 394 395 # blink_receiver 396 if cg_context.class_like.identifier == "Window": 397 # TODO(yukishiino): Window interface should be 398 # [ImplementedAs=LocalDOMWindow] instead of [ImplementedAs=DOMWindow], 399 # and [CrossOrigin] properties should be implemented specifically with 400 # DOMWindow class. Then, we'll have less hacks. 401 if (not cg_context.member_like or 402 "CrossOrigin" in cg_context.member_like.extended_attributes): 403 text = ("DOMWindow* ${blink_receiver} = " 404 "${class_name}::ToWrappableUnsafe(${v8_receiver});") 405 else: 406 text = ("LocalDOMWindow* ${blink_receiver} = To<LocalDOMWindow>(" 407 "${class_name}::ToWrappableUnsafe(${v8_receiver}));") 408 else: 409 pattern = ("{_1}* ${blink_receiver} = " 410 "${class_name}::ToWrappableUnsafe(${v8_receiver});") 411 _1 = blink_class_name(cg_context.class_like) 412 text = _format(pattern, _1=_1) 413 local_vars.append(S("blink_receiver", text)) 414 415 # v8_property_value 416 if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK: 417 # In case of V8_ACCESSOR_NAME_SETTER_CALLBACK, |v8_property_value| is 418 # defined as an argument. In case of V8_FUNCTION_CALLBACK (of IDL 419 # attribute set function), |info[0]| is the value to be set. 420 local_vars.append( 421 S("v8_property_value", 422 "v8::Local<v8::Value> ${v8_property_value} = ${info}[0];")) 423 424 # v8_receiver 425 if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK: 426 # In case of v8::FunctionCallbackInfo, This() is the receiver object. 427 local_vars.append( 428 S("v8_receiver", 429 "v8::Local<v8::Object> ${v8_receiver} = ${info}.This();")) 430 else: 431 # In case of v8::PropertyCallbackInfo, Holder() is the object that has 432 # the property being processed. 433 local_vars.append( 434 S("v8_receiver", 435 "v8::Local<v8::Object> ${v8_receiver} = ${info}.Holder();")) 436 437 # throw_security_error 438 template_vars["throw_security_error"] = T( 439 "BindingSecurity::FailedAccessCheckFor(" 440 "${info}.GetIsolate(), " 441 "${class_name}::GetWrapperTypeInfo(), " 442 "${info}.Holder());") 443 444 code_node.register_code_symbols(local_vars) 445 code_node.add_template_vars(template_vars) 446 447 448def _make_reflect_content_attribute_key(code_node, cg_context): 449 assert isinstance(code_node, SymbolScopeNode) 450 assert isinstance(cg_context, CodeGenContext) 451 452 name = (cg_context.attribute.extended_attributes.value_of("Reflect") 453 or cg_context.attribute.identifier.lower()) 454 if cg_context.attribute_get and name in ("class", "id", "name"): 455 return None 456 457 if cg_context.class_like.identifier.startswith("SVG"): 458 namespace = "svg_names" 459 code_node.accumulate( 460 CodeGenAccumulator.require_include_headers( 461 ["third_party/blink/renderer/core/svg_names.h"])) 462 else: 463 namespace = "html_names" 464 code_node.accumulate( 465 CodeGenAccumulator.require_include_headers( 466 ["third_party/blink/renderer/core/html_names.h"])) 467 return "{}::{}".format(namespace, name_style.constant(name, "attr")) 468 469 470def _make_reflect_accessor_func_name(cg_context): 471 assert isinstance(cg_context, CodeGenContext) 472 assert cg_context.attribute_get or cg_context.attribute_set 473 474 if cg_context.attribute_get: 475 name = (cg_context.attribute.extended_attributes.value_of("Reflect") 476 or cg_context.attribute.identifier.lower()) 477 if name in ("class", "id", "name"): 478 return name_style.func("get", name, "attribute") 479 480 if "URL" in cg_context.attribute.extended_attributes: 481 return "GetURLAttribute" 482 483 FAST_ACCESSORS = { 484 "boolean": ("FastHasAttribute", "SetBooleanAttribute"), 485 "long": ("GetIntegralAttribute", "SetIntegralAttribute"), 486 "unsigned long": ("GetUnsignedIntegralAttribute", 487 "SetUnsignedIntegralAttribute"), 488 } 489 idl_type = cg_context.attribute.idl_type.unwrap() 490 accessors = FAST_ACCESSORS.get(idl_type.keyword_typename) 491 if accessors: 492 return accessors[0 if cg_context.attribute_get else 1] 493 494 if (idl_type.is_interface 495 and idl_type.type_definition_object.does_implement("Element")): 496 if cg_context.attribute_get: 497 return "GetElementAttribute" 498 else: 499 return "SetElementAttribute" 500 501 if idl_type.element_type: 502 element_type = idl_type.element_type.unwrap() 503 if (element_type.is_interface and 504 element_type.type_definition_object.does_implement("Element")): 505 if cg_context.attribute_get: 506 return "GetElementArrayAttribute" 507 else: 508 return "SetElementArrayAttribute" 509 510 if cg_context.attribute_get: 511 return "FastGetAttribute" 512 else: 513 return "setAttribute" 514 515 516def _make_reflect_process_keyword_state(cg_context): 517 # https://html.spec.whatwg.org/C/#keywords-and-enumerated-attributes 518 519 assert isinstance(cg_context, CodeGenContext) 520 assert cg_context.attribute_get or cg_context.attribute_set 521 522 T = TextNode 523 F = lambda *args, **kwargs: T(_format(*args, **kwargs)) 524 525 if not cg_context.attribute_get: 526 return None 527 528 ext_attrs = cg_context.attribute.extended_attributes 529 keywords = ext_attrs.values_of("ReflectOnly") 530 missing_default = ext_attrs.value_of("ReflectMissing") 531 empty_default = ext_attrs.value_of("ReflectEmpty") 532 invalid_default = ext_attrs.value_of("ReflectInvalid") 533 534 def constant(keyword): 535 if not keyword: 536 return "g_empty_atom" 537 return "keywords::{}".format(name_style.constant(keyword)) 538 539 branches = CxxMultiBranchesNode() 540 branches.accumulate( 541 CodeGenAccumulator.require_include_headers( 542 ["third_party/blink/renderer/core/keywords.h"])) 543 nodes = [ 544 T("// [ReflectOnly]"), 545 T("const AtomicString reflect_value(${return_value}.LowerASCII());"), 546 branches, 547 ] 548 549 if missing_default is not None: 550 branches.append( 551 cond="reflect_value.IsNull()", 552 body=F("${return_value} = {};", constant(missing_default))) 553 elif cg_context.return_type.unwrap(nullable=False).is_nullable: 554 branches.append( 555 cond="reflect_value.IsNull()", 556 body=T("// Null string to IDL null.")) 557 558 if empty_default is not None: 559 branches.append( 560 cond="reflect_value.IsEmpty()", 561 body=F("${return_value} = {};", constant(empty_default))) 562 563 expr = " || ".join( 564 map(lambda keyword: "reflect_value == {}".format(constant(keyword)), 565 keywords)) 566 branches.append(cond=expr, body=T("${return_value} = reflect_value;")) 567 568 if invalid_default is not None: 569 branches.append( 570 cond=True, 571 body=F("${return_value} = {};", constant(invalid_default))) 572 else: 573 branches.append( 574 cond=True, body=F("${return_value} = {};", constant(""))) 575 576 return SequenceNode(nodes) 577 578 579def _make_blink_api_call(code_node, 580 cg_context, 581 num_of_args=None, 582 overriding_args=None): 583 assert isinstance(code_node, SymbolScopeNode) 584 assert isinstance(cg_context, CodeGenContext) 585 assert num_of_args is None or isinstance(num_of_args, (int, long)) 586 assert (overriding_args is None 587 or (isinstance(overriding_args, (list, tuple)) 588 and all(isinstance(arg, str) for arg in overriding_args))) 589 590 arguments = [] 591 ext_attrs = cg_context.member_like.extended_attributes 592 593 values = ext_attrs.values_of("CallWith") + ( 594 ext_attrs.values_of("GetterCallWith") if cg_context.attribute_get else 595 ext_attrs.values_of("SetterCallWith") if cg_context.attribute_set else 596 ()) 597 if "Isolate" in values: 598 arguments.append("${isolate}") 599 if "ScriptState" in values: 600 arguments.append("${script_state}") 601 if "ExecutionContext" in values: 602 arguments.append("${execution_context}") 603 if "Document" in values: 604 arguments.append( 605 "*bindings::ToDocumentFromExecutionContext(${execution_context})") 606 if "ThisValue" in values: 607 arguments.append("ScriptValue(${isolate}, ${v8_receiver})") 608 609 code_generator_info = cg_context.member_like.code_generator_info 610 is_partial = code_generator_info.defined_in_partial 611 if (is_partial and 612 not (cg_context.constructor or cg_context.member_like.is_static)): 613 arguments.append("*${blink_receiver}") 614 615 if "Reflect" in ext_attrs: # [Reflect] 616 key = _make_reflect_content_attribute_key(code_node, cg_context) 617 if key: 618 arguments.append(key) 619 620 if overriding_args is not None: 621 arguments.extend(overriding_args) 622 elif cg_context.attribute_get: 623 pass 624 elif cg_context.attribute_set: 625 arguments.append("${arg1_value}") 626 else: 627 for index, argument in enumerate(cg_context.function_like.arguments): 628 if num_of_args is not None and index == num_of_args: 629 break 630 name = name_style.arg_f("arg{}_{}", index + 1, argument.identifier) 631 arguments.append(_format("${{{}}}", name)) 632 633 if cg_context.is_return_by_argument: 634 arguments.append("${return_value}") 635 636 if cg_context.may_throw_exception: 637 arguments.append("${exception_state}") 638 639 func_name = backward_compatible_api_func(cg_context) 640 if cg_context.constructor: 641 if cg_context.is_named_constructor: 642 func_name = "CreateForJSConstructor" 643 else: 644 func_name = "Create" 645 if "Reflect" in ext_attrs: # [Reflect] 646 func_name = _make_reflect_accessor_func_name(cg_context) 647 648 if (cg_context.constructor or cg_context.member_like.is_static 649 or is_partial): 650 class_like = cg_context.member_like.owner_mixin or cg_context.class_like 651 class_name = (code_generator_info.receiver_implemented_as 652 or name_style.class_(class_like.identifier)) 653 func_designator = "{}::{}".format(class_name, func_name) 654 else: 655 func_designator = _format("${blink_receiver}->{}", func_name) 656 657 return _format("{_1}({_2})", _1=func_designator, _2=", ".join(arguments)) 658 659 660def bind_return_value(code_node, cg_context, overriding_args=None): 661 assert isinstance(code_node, SymbolScopeNode) 662 assert isinstance(cg_context, CodeGenContext) 663 assert (overriding_args is None 664 or (isinstance(overriding_args, (list, tuple)) 665 and all(isinstance(arg, str) for arg in overriding_args))) 666 667 T = TextNode 668 F = lambda *args, **kwargs: T(_format(*args, **kwargs)) 669 670 def create_definition(symbol_node): 671 api_calls = [] # Pairs of (num_of_args, api_call_text) 672 if overriding_args is None: 673 arguments = (cg_context.function_like.arguments 674 if cg_context.function_like else []) 675 for index, arg in enumerate(arguments): 676 if arg.is_optional and not arg.default_value: 677 api_calls.append((index, 678 _make_blink_api_call( 679 code_node, cg_context, index))) 680 api_calls.append((None, _make_blink_api_call( 681 code_node, cg_context))) 682 else: 683 api_calls.append((None, 684 _make_blink_api_call( 685 code_node, 686 cg_context, 687 overriding_args=overriding_args))) 688 689 nodes = [] 690 is_return_type_void = ((not cg_context.return_type 691 or cg_context.return_type.unwrap().is_void) and 692 not cg_context.does_override_idl_return_type) 693 if not (is_return_type_void 694 or cg_context.does_override_idl_return_type): 695 return_type = blink_type_info(cg_context.return_type).value_t 696 if len(api_calls) == 1: 697 _, api_call = api_calls[0] 698 if is_return_type_void: 699 nodes.append(F("{};", api_call)) 700 elif cg_context.is_return_by_argument: 701 nodes.append(F("{} ${return_value};", return_type)) 702 nodes.append(F("{};", api_call)) 703 elif "ReflectOnly" in cg_context.member_like.extended_attributes: 704 # [ReflectOnly] 705 nodes.append(F("auto ${return_value} = {};", api_call)) 706 else: 707 nodes.append(F("auto&& ${return_value} = {};", api_call)) 708 else: 709 branches = SequenceNode() 710 for index, api_call in api_calls: 711 if is_return_type_void or cg_context.is_return_by_argument: 712 assignment = "{};".format(api_call) 713 else: 714 assignment = _format("${return_value} = {};", api_call) 715 if index is not None: 716 branches.append( 717 CxxLikelyIfNode( 718 cond=_format( 719 "${non_undefined_argument_length} <= {}", 720 index), 721 body=[ 722 T(assignment), 723 T("break;"), 724 ])) 725 else: 726 branches.append(T(assignment)) 727 728 if not is_return_type_void: 729 nodes.append(F("{} ${return_value};", return_type)) 730 nodes.append(CxxBreakableBlockNode(branches)) 731 732 if cg_context.may_throw_exception: 733 nodes.append( 734 CxxUnlikelyIfNode( 735 cond="${exception_state}.HadException()", 736 body=T("return;"))) 737 738 if "ReflectOnly" in cg_context.member_like.extended_attributes: 739 # [ReflectOnly] 740 node = _make_reflect_process_keyword_state(cg_context) 741 if node: 742 nodes.append(EmptyNode()) 743 nodes.append(node) 744 745 return SymbolDefinitionNode(symbol_node, nodes) 746 747 code_node.register_code_symbol( 748 SymbolNode("return_value", definition_constructor=create_definition)) 749 750 751def make_bindings_trace_event(cg_context): 752 assert isinstance(cg_context, CodeGenContext) 753 754 event_name = "{}.{}".format(cg_context.class_like.identifier, 755 cg_context.property_.identifier) 756 if cg_context.attribute_get: 757 event_name = "{}.{}".format(event_name, "get") 758 elif cg_context.attribute_set: 759 event_name = "{}.{}".format(event_name, "set") 760 elif cg_context.constructor_group and not cg_context.is_named_constructor: 761 event_name = "{}.{}".format(cg_context.class_like.identifier, 762 "constructor") 763 764 return TextNode("BLINK_BINDINGS_TRACE_EVENT(\"{}\");".format(event_name)) 765 766 767def make_check_argument_length(cg_context): 768 assert isinstance(cg_context, CodeGenContext) 769 770 T = TextNode 771 F = lambda *args, **kwargs: T(_format(*args, **kwargs)) 772 773 if cg_context.v8_callback_type != CodeGenContext.V8_FUNCTION_CALLBACK: 774 return None 775 776 if cg_context.attribute_get: 777 num_of_required_args = 0 778 elif cg_context.attribute_set: 779 idl_type = cg_context.attribute.idl_type 780 if not (idl_type.does_include_nullable_or_dict 781 or idl_type.unwrap().is_any or "LegacyTreatNonObjectAsNull" in 782 idl_type.unwrap().extended_attributes 783 or "PutForwards" in cg_context.attribute.extended_attributes 784 or "Replaceable" in cg_context.attribute.extended_attributes): 785 # ES undefined in ${v8_property_value} will cause a TypeError 786 # anyway, so omit the check against the number of arguments. 787 return None 788 num_of_required_args = 1 789 elif cg_context.function_like: 790 num_of_required_args = ( 791 cg_context.function_like.num_of_required_arguments) 792 elif isinstance(cg_context.property_, web_idl.OverloadGroup): 793 num_of_required_args = ( 794 cg_context.property_.min_num_of_required_arguments) 795 else: 796 assert False 797 798 if num_of_required_args == 0: 799 return None 800 801 return CxxUnlikelyIfNode( 802 cond=_format("UNLIKELY(${info}.Length() < {})", num_of_required_args), 803 body=[ 804 F(("${exception_state}.ThrowTypeError(" 805 "ExceptionMessages::NotEnoughArguments" 806 "({}, ${info}.Length()));"), num_of_required_args), 807 T("return;"), 808 ]) 809 810 811def make_check_constructor_call(cg_context): 812 assert isinstance(cg_context, CodeGenContext) 813 814 T = TextNode 815 816 node = SequenceNode([ 817 CxxUnlikelyIfNode( 818 cond="!${info}.IsConstructCall()", 819 body=T("${exception_state}.ThrowTypeError(" 820 "ExceptionMessages::ConstructorCalledAsFunction());\n" 821 "return;")), 822 ]) 823 if not cg_context.is_named_constructor: 824 node.append( 825 CxxLikelyIfNode( 826 cond=("ConstructorMode::Current(${isolate}) == " 827 "ConstructorMode::kWrapExistingObject"), 828 body=T("bindings::V8SetReturnValue(${info}, ${v8_receiver});\n" 829 "return;"))) 830 node.accumulate( 831 CodeGenAccumulator.require_include_headers([ 832 "third_party/blink/renderer/platform/bindings/v8_object_constructor.h" 833 ])) 834 return node 835 836 837def make_check_receiver(cg_context): 838 assert isinstance(cg_context, CodeGenContext) 839 840 T = TextNode 841 842 if cg_context.member_like.is_static: 843 return None 844 845 if (cg_context.attribute and 846 "LegacyLenientThis" in cg_context.attribute.extended_attributes): 847 return SequenceNode([ 848 T("// [LegacyLenientThis]"), 849 CxxUnlikelyIfNode( 850 cond="!${class_name}::HasInstance(${isolate}, ${v8_receiver})", 851 body=T("return;")), 852 ]) 853 854 if cg_context.is_return_type_promise_type: 855 return SequenceNode([ 856 T("// Promise returning function: " 857 "Convert a TypeError to a reject promise."), 858 CxxUnlikelyIfNode( 859 cond="!${class_name}::HasInstance(${isolate}, ${v8_receiver})", 860 body=[ 861 T("${exception_state}.ThrowTypeError(" 862 "\"Illegal invocation\");"), 863 T("return;"), 864 ]) 865 ]) 866 867 return None 868 869 870def make_check_security_of_return_value(cg_context): 871 assert isinstance(cg_context, CodeGenContext) 872 873 T = TextNode 874 875 check_security = cg_context.member_like.extended_attributes.value_of( 876 "CheckSecurity") 877 if check_security != "ReturnValue": 878 return None 879 880 web_feature = _format( 881 "WebFeature::{}", 882 name_style.constant("CrossOrigin", cg_context.class_like.identifier, 883 cg_context.property_.identifier)) 884 use_counter = _format( 885 "UseCounter::Count(${current_execution_context}, {});", web_feature) 886 cond = T("!BindingSecurity::ShouldAllowAccessTo(" 887 "ToLocalDOMWindow(${current_context}), ${return_value}, " 888 "BindingSecurity::ErrorReportOption::kDoNotReport)") 889 body = [ 890 T(use_counter), 891 T("bindings::V8SetReturnValue(${info}, nullptr);\n" 892 "return;"), 893 ] 894 node = SequenceNode([ 895 T("// [CheckSecurity=ReturnValue]"), 896 CxxUnlikelyIfNode(cond=cond, body=body), 897 ]) 898 node.accumulate( 899 CodeGenAccumulator.require_include_headers([ 900 "third_party/blink/renderer/bindings/core/v8/binding_security.h", 901 "third_party/blink/renderer/core/frame/web_feature.h", 902 "third_party/blink/renderer/platform/instrumentation/use_counter.h", 903 ])) 904 return node 905 906 907def make_cooperative_scheduling_safepoint(cg_context): 908 assert isinstance(cg_context, CodeGenContext) 909 910 node = TextNode("scheduler::CooperativeSchedulingManager::Instance()" 911 "->Safepoint();") 912 node.accumulate( 913 CodeGenAccumulator.require_include_headers([ 914 "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h" 915 ])) 916 return node 917 918 919def make_log_activity(cg_context): 920 assert isinstance(cg_context, CodeGenContext) 921 922 target = cg_context.member_like or cg_context.property_ 923 ext_attrs = target.extended_attributes 924 if "LogActivity" not in ext_attrs: 925 return None 926 target = ext_attrs.value_of("LogActivity") 927 if target: 928 assert target in ("GetterOnly", "SetterOnly") 929 if ((target == "GetterOnly" and not cg_context.attribute_get) 930 or (target == "SetterOnly" and not cg_context.attribute_set)): 931 return None 932 if (cg_context.for_world == cg_context.MAIN_WORLD 933 and "LogAllWorlds" not in ext_attrs): 934 return None 935 936 pattern = "{_1}${per_context_data} && ${per_context_data}->ActivityLogger()" 937 _1 = "" 938 if (cg_context.attribute and "PerWorldBindings" not in ext_attrs 939 and "LogAllWorlds" not in ext_attrs): 940 _1 = "${script_state}->World().IsIsolatedWorld() && " 941 cond = _format(pattern, _1=_1) 942 943 pattern = "${per_context_data}->ActivityLogger()->{_1}(\"{_2}.{_3}\"{_4});" 944 _2 = cg_context.class_like.identifier 945 _3 = cg_context.property_.identifier 946 if cg_context.attribute_get: 947 _1 = "LogGetter" 948 _4 = "" 949 elif cg_context.attribute_set: 950 _1 = "LogSetter" 951 _4 = ", ${v8_property_value}" 952 elif cg_context.operation_group: 953 _1 = "LogMethod" 954 _4 = ", ${info}" 955 body = _format(pattern, _1=_1, _2=_2, _3=_3, _4=_4) 956 957 pattern = ("// [LogActivity], [LogAllWorlds]\n" "if ({_1}) {{ {_2} }}") 958 node = TextNode(_format(pattern, _1=cond, _2=body)) 959 node.accumulate( 960 CodeGenAccumulator.require_include_headers([ 961 "third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.h", 962 "third_party/blink/renderer/platform/bindings/v8_per_context_data.h", 963 ])) 964 return node 965 966 967def _make_overload_dispatcher_per_arg_size(cg_context, items): 968 """ 969 https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm 970 971 Args: 972 items: Partial list of an "effective overload set" with the same 973 type list size. 974 975 Returns: 976 A pair of a resulting CodeNode and a boolean flag that is True if there 977 exists a case that overload resolution will fail, i.e. a bailout that 978 throws a TypeError is necessary. 979 """ 980 assert isinstance(cg_context, CodeGenContext) 981 assert isinstance(items, (list, tuple)) 982 assert all( 983 isinstance(item, web_idl.OverloadGroup.EffectiveOverloadItem) 984 for item in items) 985 986 # Variables shared with nested functions 987 if len(items) > 1: 988 arg_index = web_idl.OverloadGroup.distinguishing_argument_index(items) 989 else: 990 arg_index = None 991 func_like = None 992 dispatcher_nodes = SequenceNode() 993 994 # True if there exists a case that overload resolution will fail. 995 can_fail = True 996 997 def find_test(item, test): 998 # |test| is a callable that takes (t, u) where: 999 # t = the idl_type (in the original form) 1000 # u = the unwrapped version of t 1001 idl_type = item.type_list[arg_index] 1002 t = idl_type 1003 u = idl_type.unwrap() 1004 return test(t, u) or (u.is_union and any( 1005 [test(m, m.unwrap()) for m in u.flattened_member_types])) 1006 1007 def find(test): 1008 for item in items: 1009 if find_test(item, test): 1010 return item.function_like 1011 return None 1012 1013 def find_all_interfaces(): 1014 result = [] # [(func_like, idl_type), ...] 1015 for item in items: 1016 idl_type = item.type_list[arg_index].unwrap() 1017 if idl_type.is_interface: 1018 result.append((item.function_like, idl_type)) 1019 if idl_type.is_union: 1020 for member_type in idl_type.flattened_member_types: 1021 if member_type.unwrap().is_interface: 1022 result.append((item.function_like, 1023 member_type.unwrap())) 1024 return result 1025 1026 def make_node(pattern): 1027 value = _format("${info}[{}]", arg_index) 1028 func_name = callback_function_name(cg_context, 1029 func_like.overload_index) 1030 return TextNode(_format(pattern, value=value, func_name=func_name)) 1031 1032 def dispatch_if(expr): 1033 if expr is True: 1034 pattern = "return {func_name}(${info});" 1035 else: 1036 pattern = ("if (" + expr + ") {{\n" 1037 " return {func_name}(${info});\n" 1038 "}}") 1039 node = make_node(pattern) 1040 conditional = expr_from_exposure(func_like.exposure) 1041 if not conditional.is_always_true: 1042 node = CxxUnlikelyIfNode(cond=conditional, body=node) 1043 dispatcher_nodes.append(node) 1044 return expr is True and conditional.is_always_true 1045 1046 if len(items) == 1: 1047 func_like = items[0].function_like 1048 can_fail = False 1049 return make_node("return {func_name}(${info});"), can_fail 1050 1051 # 12.2. If V is undefined, ... 1052 func_like = find(lambda t, u: t.is_optional) 1053 if func_like: 1054 dispatch_if("{value}->IsUndefined()") 1055 1056 # 12.3. if V is null or undefined, ... 1057 func_like = find(lambda t, u: t.does_include_nullable_or_dict) 1058 if func_like: 1059 dispatch_if("{value}->IsNullOrUndefined()") 1060 1061 # 12.4. if V is a platform object, ... 1062 def inheritance_length(func_and_type): 1063 return len(func_and_type[1].type_definition_object. 1064 inclusive_inherited_interfaces) 1065 1066 # Attempt to match from most derived to least derived. 1067 for func_like, idl_type in sorted( 1068 find_all_interfaces(), key=inheritance_length, reverse=True): 1069 v8_bridge_name = v8_bridge_class_name( 1070 idl_type.unwrap().type_definition_object) 1071 dispatch_if( 1072 _format("{}::HasInstance(${isolate}, {value})", v8_bridge_name)) 1073 1074 # V8 specific optimization: BufferSource = ArrayBufferView or ArrayBuffer 1075 is_typedef_name = lambda t, name: t.is_typedef and t.identifier == name 1076 func_like = find( 1077 lambda t, u: is_typedef_name(t.unwrap(typedef=False), "BufferSource")) 1078 if func_like: 1079 dispatch_if("{value}->IsArrayBufferView() || " 1080 "{value}->IsArrayBuffer() || " 1081 "{value}->IsSharedArrayBuffer()") 1082 else: 1083 # 12.5. if Type(V) is Object, V has an [[ArrayBufferData]] internal 1084 # slot, ... 1085 func_like = find(lambda t, u: u.is_array_buffer) 1086 if func_like: 1087 dispatch_if("{value}->IsArrayBuffer() || " 1088 "{value}->IsSharedArrayBuffer()") 1089 1090 # V8 specific optimization: ArrayBufferView 1091 func_like = find(lambda t, u: u.is_array_buffer_view) 1092 if func_like: 1093 dispatch_if("{value}->IsArrayBufferView()") 1094 1095 # 12.6. if Type(V) is Object, V has a [[DataView]] internal slot, ... 1096 func_like = find(lambda t, u: u.is_data_view) 1097 if func_like: 1098 dispatch_if("{value}->IsDataView()") 1099 1100 # 12.7. if Type(V) is Object, V has a [[TypedArrayName]] internal slot, ... 1101 typed_array_types = ("Int8Array", "Int16Array", "Int32Array", "Uint8Array", 1102 "Uint16Array", "Uint32Array", "Uint8ClampedArray", 1103 "Float32Array", "Float64Array") 1104 for typed_array_type in typed_array_types: 1105 func_like = find(lambda t, u: u.keyword_typename == typed_array_type) 1106 if func_like: 1107 dispatch_if(_format("{value}->Is{}()", typed_array_type)) 1108 1109 # 12.8. if IsCallable(V) is true, ... 1110 func_like = find(lambda t, u: u.is_callback_function) 1111 if func_like: 1112 dispatch_if("{value}->IsFunction()") 1113 1114 # 12.9. if Type(V) is Object and ... @@iterator ... 1115 func_like = find(lambda t, u: u.is_sequence or u.is_frozen_array) 1116 if func_like: 1117 dispatch_if("{value}->IsArray() || " # Excessive optimization 1118 "bindings::IsEsIterableObject" 1119 "(${isolate}, {value}, ${exception_state})") 1120 dispatcher_nodes.append( 1121 TextNode("if (${exception_state}.HadException()) {\n" 1122 " return;\n" 1123 "}")) 1124 1125 # 12.10. if Type(V) is Object and ... 1126 def is_es_object_type(t, u): 1127 return (u.is_callback_interface or u.is_dictionary or u.is_record 1128 or u.is_object) 1129 1130 func_like = find(is_es_object_type) 1131 if func_like: 1132 dispatch_if("{value}->IsObject()") 1133 1134 # 12.11. if Type(V) is Boolean and ... 1135 func_like = find(lambda t, u: u.is_boolean) 1136 if func_like: 1137 dispatch_if("{value}->IsBoolean()") 1138 1139 # 12.12. if Type(V) is Number and ... 1140 func_like = find(lambda t, u: u.is_numeric) 1141 if func_like: 1142 dispatch_if("{value}->IsNumber()") 1143 1144 # 12.13. if there is an entry in S that has ... a string type ... 1145 # 12.14. if there is an entry in S that has ... a numeric type ... 1146 # 12.15. if there is an entry in S that has ... boolean ... 1147 # 12.16. if there is an entry in S that has any ... 1148 func_likes = [ 1149 find(lambda t, u: u.is_enumeration), 1150 find(lambda t, u: u.is_string), 1151 find(lambda t, u: u.is_numeric), 1152 find(lambda t, u: u.is_boolean), 1153 find(lambda t, u: u.is_any), 1154 ] 1155 for func_like in func_likes: 1156 if func_like: 1157 if dispatch_if(True): 1158 can_fail = False 1159 break 1160 1161 return dispatcher_nodes, can_fail 1162 1163 1164def make_overload_dispatcher(cg_context): 1165 # https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm 1166 1167 assert isinstance(cg_context, CodeGenContext) 1168 1169 T = TextNode 1170 F = lambda *args, **kwargs: T(_format(*args, **kwargs)) 1171 1172 overload_group = cg_context.property_ 1173 items = overload_group.effective_overload_set() 1174 args_size = lambda item: len(item.type_list) 1175 items_grouped_by_arg_size = itertools.groupby( 1176 sorted(items, key=args_size, reverse=True), key=args_size) 1177 1178 # TODO(yukishiino): Runtime-enabled features should be taken into account 1179 # when calculating the max argument size. 1180 max_arg_size = max(map(args_size, items)) 1181 arg_count_def = F("const int arg_count = std::min(${info}.Length(), {});", 1182 max_arg_size) 1183 1184 branches = SequenceNode() 1185 did_use_break = False 1186 for arg_size, items in items_grouped_by_arg_size: 1187 items = list(items) 1188 1189 node, can_fail = _make_overload_dispatcher_per_arg_size( 1190 cg_context, items) 1191 1192 if arg_size > 0: 1193 node = CxxLikelyIfNode( 1194 cond="arg_count == {}".format(arg_size), 1195 body=[node, T("break;") if can_fail else None]) 1196 did_use_break = did_use_break or can_fail 1197 1198 conditional = expr_or( 1199 map(lambda item: expr_from_exposure(item.function_like.exposure), 1200 items)) 1201 if not conditional.is_always_true: 1202 node = CxxUnlikelyIfNode(cond=conditional, body=node) 1203 1204 branches.append(node) 1205 1206 if did_use_break: 1207 branches = CxxBreakableBlockNode(branches) 1208 branches = SequenceNode([ 1209 arg_count_def, 1210 branches, 1211 ]) 1212 1213 if not did_use_break and arg_size == 0 and conditional.is_always_true: 1214 return branches 1215 1216 return SequenceNode([ 1217 branches, 1218 EmptyNode(), 1219 make_check_argument_length(cg_context), 1220 T("${exception_state}.ThrowTypeError" 1221 "(\"Overload resolution failed.\");\n" 1222 "return;"), 1223 ]) 1224 1225 1226def make_report_coop_access(cg_context): 1227 assert isinstance(cg_context, CodeGenContext) 1228 1229 if cg_context.class_like.identifier != "Window": 1230 return None 1231 1232 ext_attrs = cg_context.member_like.extended_attributes 1233 if "CrossOrigin" not in ext_attrs: 1234 return None 1235 1236 values = ext_attrs.values_of("CrossOrigin") 1237 if (cg_context.attribute_get and not (not values or "Getter" in values)): 1238 return None 1239 elif (cg_context.attribute_set and not ("Setter" in values)): 1240 return None 1241 1242 return TextNode("${blink_receiver}->ReportCoopAccess(${property_name});") 1243 1244 1245def make_report_deprecate_as(cg_context): 1246 assert isinstance(cg_context, CodeGenContext) 1247 1248 target = cg_context.member_like or cg_context.property_ 1249 name = target.extended_attributes.value_of("DeprecateAs") 1250 if not name: 1251 return None 1252 1253 pattern = ("// [DeprecateAs]\n" 1254 "Deprecation::CountDeprecation(" 1255 "${current_execution_context}, WebFeature::k{_1});") 1256 _1 = name 1257 node = TextNode(_format(pattern, _1=_1)) 1258 node.accumulate( 1259 CodeGenAccumulator.require_include_headers( 1260 ["third_party/blink/renderer/core/frame/deprecation.h"])) 1261 return node 1262 1263 1264def _make_measure_web_feature_constant(cg_context): 1265 assert isinstance(cg_context, CodeGenContext) 1266 1267 target = cg_context.member_like or cg_context.property_ 1268 ext_attrs = target.extended_attributes 1269 1270 suffix = "" 1271 if cg_context.attribute_get: 1272 suffix = "_AttributeGetter" 1273 elif cg_context.attribute_set: 1274 suffix = "_AttributeSetter" 1275 elif cg_context.constructor: 1276 suffix = "_Constructor" 1277 elif cg_context.exposed_construct: 1278 suffix = "_ConstructorGetter" 1279 elif cg_context.operation: 1280 suffix = "_Method" 1281 1282 name = ext_attrs.value_of("MeasureAs") or ext_attrs.value_of("Measure") 1283 if name: 1284 name = "k{}".format(name) 1285 elif cg_context.constructor: 1286 name = "kV8{}{}".format(cg_context.class_like.identifier, suffix) 1287 else: 1288 name = "kV8{}_{}{}".format( 1289 cg_context.class_like.identifier, 1290 name_style.raw.upper_camel_case(cg_context.property_.identifier), 1291 suffix) 1292 1293 return "WebFeature::{}".format(name) 1294 1295 1296def make_report_high_entropy(cg_context): 1297 assert isinstance(cg_context, CodeGenContext) 1298 1299 target = cg_context.member_like or cg_context.property_ 1300 ext_attrs = target.extended_attributes 1301 if cg_context.attribute_set or "HighEntropy" not in ext_attrs: 1302 return None 1303 assert "Measure" in ext_attrs or "MeasureAs" in ext_attrs, "{}: {}".format( 1304 cg_context.idl_location_and_name, 1305 "[HighEntropy] must be specified with either [Measure] or " 1306 "[MeasureAs].") 1307 1308 if ext_attrs.value_of("HighEntropy") == "Direct": 1309 text = _format( 1310 "// [HighEntropy=Direct]\n" 1311 "Dactyloscoper::RecordDirectSurface(" 1312 "${current_execution_context}, {measure_constant}, " 1313 "${return_value});", 1314 measure_constant=_make_measure_web_feature_constant(cg_context)) 1315 else: 1316 text = _format( 1317 "// [HighEntropy]\n" 1318 "Dactyloscoper::Record(" 1319 "${current_execution_context}, {measure_constant});", 1320 measure_constant=_make_measure_web_feature_constant(cg_context)) 1321 node = TextNode(text) 1322 node.accumulate( 1323 CodeGenAccumulator.require_include_headers( 1324 ["third_party/blink/renderer/core/frame/dactyloscoper.h"])) 1325 return node 1326 1327 1328def make_report_measure_as(cg_context): 1329 assert isinstance(cg_context, CodeGenContext) 1330 1331 target = cg_context.member_like or cg_context.property_ 1332 ext_attrs = target.extended_attributes 1333 if not ("Measure" in ext_attrs or "MeasureAs" in ext_attrs): 1334 return None 1335 1336 text = _format( 1337 "// [Measure], [MeasureAs]\n" 1338 "UseCounter::Count(${current_execution_context}, {measure_constant});", 1339 measure_constant=_make_measure_web_feature_constant(cg_context)) 1340 node = TextNode(text) 1341 node.accumulate( 1342 CodeGenAccumulator.require_include_headers([ 1343 "third_party/blink/renderer/core/frame/web_feature.h", 1344 "third_party/blink/renderer/platform/instrumentation/use_counter.h", 1345 ])) 1346 return node 1347 1348 1349def make_return_value_cache_return_early(cg_context): 1350 assert isinstance(cg_context, CodeGenContext) 1351 1352 pred = cg_context.member_like.extended_attributes.value_of( 1353 "CachedAttribute") 1354 if pred: 1355 return TextNode("""\ 1356// [CachedAttribute] 1357static const V8PrivateProperty::SymbolKey kPrivatePropertyCachedAttribute; 1358auto&& v8_private_cached_attribute = 1359 V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertyCachedAttribute); 1360if (!${blink_receiver}->""" + pred + """()) { 1361 v8::Local<v8::Value> v8_value; 1362 if (!v8_private_cached_attribute.GetOrUndefined(${v8_receiver}) 1363 .ToLocal(&v8_value)) { 1364 return; 1365 } 1366 if (!v8_value->IsUndefined()) { 1367 bindings::V8SetReturnValue(${info}, v8_value); 1368 return; 1369 } 1370}""") 1371 1372 if "SaveSameObject" in cg_context.member_like.extended_attributes: 1373 return TextNode("""\ 1374// [SaveSameObject] 1375static const V8PrivateProperty::SymbolKey kPrivatePropertySaveSameObject; 1376auto&& v8_private_save_same_object = 1377 V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertySaveSameObject); 1378{ 1379 v8::Local<v8::Value> v8_value; 1380 if (!v8_private_save_same_object.GetOrUndefined(${v8_receiver}) 1381 .ToLocal(&v8_value)) { 1382 return; 1383 } 1384 if (!v8_value->IsUndefined()) { 1385 bindings::V8SetReturnValue(${info}, v8_value); 1386 return; 1387 } 1388}""") 1389 1390 1391def make_return_value_cache_update_value(cg_context): 1392 assert isinstance(cg_context, CodeGenContext) 1393 1394 if "CachedAttribute" in cg_context.member_like.extended_attributes: 1395 return TextNode("// [CachedAttribute]\n" 1396 "v8_private_cached_attribute.Set" 1397 "(${v8_receiver}, ${info}.GetReturnValue().Get());") 1398 1399 if "SaveSameObject" in cg_context.member_like.extended_attributes: 1400 return TextNode("// [SaveSameObject]\n" 1401 "v8_private_save_same_object.Set" 1402 "(${v8_receiver}, ${info}.GetReturnValue().Get());") 1403 1404 1405def make_runtime_call_timer_scope(cg_context, overriding_name=None): 1406 assert isinstance(cg_context, CodeGenContext) 1407 assert _is_none_or_str(overriding_name) 1408 1409 target = cg_context.member_like or cg_context.property_ 1410 1411 suffix = "" 1412 if cg_context.attribute_get: 1413 suffix = "_Getter" 1414 elif cg_context.attribute_set: 1415 suffix = "_Setter" 1416 elif cg_context.exposed_construct: 1417 suffix = "_ConstructorGetterCallback" 1418 1419 counter = (target and 1420 target.extended_attributes.value_of("RuntimeCallStatsCounter")) 1421 if counter: 1422 macro_name = "RUNTIME_CALL_TIMER_SCOPE" 1423 counter_name = "RuntimeCallStats::CounterId::k{}{}".format( 1424 counter, suffix) 1425 else: 1426 macro_name = "RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT" 1427 counter_name = "\"Blink_{}_{}{}\"".format( 1428 blink_class_name(cg_context.class_like), overriding_name 1429 or target.identifier, suffix) 1430 1431 return TextNode( 1432 _format( 1433 "{macro_name}(${info}.GetIsolate(), {counter_name});", 1434 macro_name=macro_name, 1435 counter_name=counter_name)) 1436 1437 1438def make_steps_of_ce_reactions(cg_context): 1439 assert isinstance(cg_context, CodeGenContext) 1440 assert (cg_context.attribute_set or cg_context.operation 1441 or cg_context.indexed_property_setter 1442 or cg_context.named_property_setter 1443 or cg_context.named_property_deleter) 1444 1445 T = TextNode 1446 1447 nodes = [] 1448 1449 ext_attrs = cg_context.member_like.extended_attributes 1450 if "CustomElementCallbacks" in ext_attrs or "Reflect" in ext_attrs: 1451 if "CustomElementCallbacks" in ext_attrs: 1452 nodes.append(T("// [CustomElementCallbacks]")) 1453 elif "Reflect" in ext_attrs: 1454 nodes.append(T("// [Reflect]")) 1455 nodes.append( 1456 T("V0CustomElementProcessingStack::CallbackDeliveryScope " 1457 "v0_custom_element_scope;")) 1458 nodes[-1].accumulate( 1459 CodeGenAccumulator.require_include_headers([ 1460 "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h" 1461 ])) 1462 1463 if "CEReactions" in ext_attrs: 1464 nodes.append(T("// [CEReactions]")) 1465 nodes.append(T("CEReactionsScope ce_reactions_scope;")) 1466 nodes[-1].accumulate( 1467 CodeGenAccumulator.require_include_headers([ 1468 "third_party/blink/renderer/core/html/custom/ce_reactions_scope.h" 1469 ])) 1470 1471 if not nodes: 1472 return None 1473 1474 # CEReactions scope is not tolerant of V8 exception, so it's necessary to 1475 # invoke custom element reactions before throwing an exception. Thus, put 1476 # an ExceptionState before CEReactions scope. 1477 nodes.insert(0, WeakDependencyNode(dep_syms=["exception_state"])) 1478 1479 return SequenceNode(nodes) 1480 1481 1482def make_steps_of_put_forwards(cg_context): 1483 assert isinstance(cg_context, CodeGenContext) 1484 1485 T = TextNode 1486 1487 return SequenceNode([ 1488 T("// [PutForwards]"), 1489 T("v8::Local<v8::Value> target;"), 1490 T("if (!${v8_receiver}->Get(${current_context}, " 1491 "V8AtomicString(${isolate}, ${property_name}))" 1492 ".ToLocal(&target)) {\n" 1493 " return;\n" 1494 "}"), 1495 CxxUnlikelyIfNode( 1496 cond="!target->IsObject()", 1497 body=[ 1498 T("${exception_state}.ThrowTypeError(" 1499 "\"The attribute value is not an object\");"), 1500 T("return;"), 1501 ]), 1502 T("bool did_set;"), 1503 T("if (!target.As<v8::Object>()->Set(${current_context}, " 1504 "V8AtomicString(${isolate}, " 1505 "\"${attribute.extended_attributes.value_of(\"PutForwards\")}\"" 1506 "), ${v8_property_value}).To(&did_set)) {{\n" 1507 " return;\n" 1508 "}}"), 1509 ]) 1510 1511 1512def make_steps_of_replaceable(cg_context): 1513 assert isinstance(cg_context, CodeGenContext) 1514 1515 T = TextNode 1516 1517 return SequenceNode([ 1518 T("// [Replaceable]"), 1519 T("bool did_create;"), 1520 T("if (!${v8_receiver}->CreateDataProperty(${current_context}, " 1521 "V8AtomicString(${isolate}, ${property_name}), " 1522 "${v8_property_value}).To(&did_create)) {\n" 1523 " return;\n" 1524 "}"), 1525 ]) 1526 1527 1528def make_v8_set_return_value(cg_context): 1529 assert isinstance(cg_context, CodeGenContext) 1530 1531 T = TextNode 1532 F = lambda *args, **kwargs: T(_format(*args, **kwargs)) 1533 1534 if cg_context.does_override_idl_return_type: 1535 return T("bindings::V8SetReturnValue(${info}, ${return_value});") 1536 1537 if not cg_context.return_type or cg_context.return_type.unwrap().is_void: 1538 # Request a SymbolNode |return_value| to define itself without 1539 # rendering any text. 1540 return T("<% return_value.request_symbol_definition() %>") 1541 1542 operation = cg_context.operation 1543 if operation and (operation.is_setter or operation.is_deleter): 1544 # Blink implementation returns in a type different from the IDL type. 1545 # Namely, IndexedPropertySetterResult, NamedPropertySetterResult, and 1546 # NamedPropertyDeleterResult are returned ignoring the operation's 1547 # return type. 1548 return T("bindings::V8SetReturnValue(${info}, ${return_value});") 1549 1550 return_type = cg_context.return_type 1551 if return_type.is_typedef: 1552 if return_type.identifier in ("EventHandler", 1553 "OnBeforeUnloadEventHandler", 1554 "OnErrorEventHandler"): 1555 return T("bindings::V8SetReturnValue(${info}, ${return_value}, " 1556 "${isolate}, ${blink_receiver});") 1557 1558 # [CheckSecurity=ReturnValue] 1559 # 1560 # The returned object must be wrapped in its own realm instead of the 1561 # receiver object's relevant realm or the current realm. 1562 # 1563 # [CheckSecurity=ReturnValue] is used only for 'contentDocument' attribute 1564 # and 'getSVGDocument' operation of HTML{IFrame,Frame,Object,Embed}Element 1565 # interfaces, and Window.frameElement attribute, so far. 1566 # 1567 # All the interfaces above except for Window support 'contentWindow' 1568 # attribute and that's the global object of the creation context of the 1569 # returned V8 wrapper. Window.frameElement is implemented with [Custom] 1570 # for now and there is no need to support it. 1571 # 1572 # Note that the global object has its own context and there is no need to 1573 # pass the creation context to ToV8. 1574 if (cg_context.member_like.extended_attributes.value_of("CheckSecurity") == 1575 "ReturnValue"): 1576 return T("""\ 1577// [CheckSecurity=ReturnValue] 1578bindings::V8SetReturnValue( 1579 ${info}, 1580 ToV8(${return_value}, 1581 ToV8(${blink_receiver}->contentWindow(), 1582 v8::Local<v8::Object>(), 1583 ${isolate}).As<v8::Object>(), 1584 ${isolate}));\ 1585""") 1586 1587 return_type = return_type.unwrap(typedef=True) 1588 return_type_body = return_type.unwrap() 1589 1590 PRIMITIVE_TYPE_TO_CXX_TYPE = { 1591 "boolean": "bool", 1592 "byte": "int8_t", 1593 "octet": "uint8_t", 1594 "short": "int16_t", 1595 "unsigned short": "uint16_t", 1596 "long": "int32_t", 1597 "unsigned long": "uint32_t", 1598 "long long": "int64_t", 1599 "unsigned long long": "uint64_t", 1600 "float": "float", 1601 "unrestricted float": "float", 1602 "double": "double", 1603 "unrestricted double": "double", 1604 } 1605 cxx_type = PRIMITIVE_TYPE_TO_CXX_TYPE.get( 1606 return_type_body.keyword_typename) 1607 if cxx_type: 1608 return F( 1609 "bindings::V8SetReturnValue(${info}, ${return_value}, " 1610 "bindings::V8ReturnValue::PrimitiveType<{cxx_type}>());", 1611 cxx_type=cxx_type) 1612 1613 # TODO(yukishiino): Remove |return_type_body.is_enumeration| below once 1614 # the migration from String to V8Enum type is done. 1615 if return_type_body.is_string or return_type_body.is_enumeration: 1616 args = ["${info}", "${return_value}", "${isolate}"] 1617 if return_type.is_nullable: 1618 args.append("bindings::V8ReturnValue::kNullable") 1619 else: 1620 args.append("bindings::V8ReturnValue::kNonNullable") 1621 return T("bindings::V8SetReturnValue({});".format(", ".join(args))) 1622 1623 if return_type_body.is_interface: 1624 args = ["${info}", "${return_value}"] 1625 if cg_context.for_world == cg_context.MAIN_WORLD: 1626 args.append("bindings::V8ReturnValue::kMainWorld") 1627 elif cg_context.constructor or cg_context.member_like.is_static: 1628 args.append("${creation_context}") 1629 else: 1630 args.append("${blink_receiver}") 1631 return T("bindings::V8SetReturnValue({});".format(", ".join(args))) 1632 1633 if return_type.is_frozen_array: 1634 return T( 1635 "bindings::V8SetReturnValue(" 1636 "${info}, " 1637 "ToV8(${return_value}, ${creation_context_object}, ${isolate}), " 1638 "bindings::V8ReturnValue::kFrozen);") 1639 1640 if return_type.is_promise: 1641 return T("bindings::V8SetReturnValue" 1642 "(${info}, ${return_value}.V8Value());") 1643 1644 return T("bindings::V8SetReturnValue(${info}, " 1645 "ToV8(${return_value}, ${creation_context_object}, ${isolate}));") 1646 1647 1648def _make_empty_callback_def(cg_context, function_name): 1649 assert isinstance(cg_context, CodeGenContext) 1650 assert isinstance(function_name, str) 1651 1652 if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK: 1653 arg_decls = ["const v8::FunctionCallbackInfo<v8::Value>& info"] 1654 arg_names = ["info"] 1655 elif (cg_context.v8_callback_type == CodeGenContext. 1656 V8_ACCESSOR_NAME_GETTER_CALLBACK): 1657 arg_decls = [ 1658 "v8::Local<v8::Name> v8_property_name", 1659 "const v8::PropertyCallbackInfo<v8::Value>& info", 1660 ] 1661 arg_names = ["v8_property_name", "info"] 1662 elif (cg_context.v8_callback_type == CodeGenContext. 1663 V8_ACCESSOR_NAME_SETTER_CALLBACK): 1664 arg_decls = [ 1665 "v8::Local<v8::Name> v8_property_name", 1666 "v8::Local<v8::Value> v8_property_value", 1667 "const v8::PropertyCallbackInfo<void>& info", 1668 ] 1669 arg_names = ["v8_property_name", "v8_property_value", "info"] 1670 elif (cg_context.v8_callback_type == CodeGenContext. 1671 V8_GENERIC_NAMED_PROPERTY_SETTER_CALLBACK): 1672 arg_decls = [ 1673 "v8::Local<v8::Name> v8_property_name", 1674 "v8::Local<v8::Value> v8_property_value", 1675 "const v8::PropertyCallbackInfo<v8::Value>& info", 1676 ] 1677 arg_names = ["v8_property_name", "v8_property_value", "info"] 1678 1679 func_def = CxxFuncDefNode( 1680 name=function_name, arg_decls=arg_decls, return_type="void") 1681 func_def.set_base_template_vars(cg_context.template_bindings()) 1682 body = func_def.body 1683 1684 for arg_name in arg_names: 1685 body.add_template_var(arg_name, arg_name) 1686 1687 bind_callback_local_vars(body, cg_context) 1688 if cg_context.attribute or cg_context.function_like: 1689 bind_blink_api_arguments(body, cg_context) 1690 bind_return_value(body, cg_context) 1691 1692 return func_def 1693 1694 1695def make_attribute_get_callback_def(cg_context, function_name): 1696 assert isinstance(cg_context, CodeGenContext) 1697 assert isinstance(function_name, str) 1698 1699 func_def = _make_empty_callback_def(cg_context, function_name) 1700 body = func_def.body 1701 1702 body.extend([ 1703 make_check_receiver(cg_context), 1704 EmptyNode(), 1705 make_runtime_call_timer_scope(cg_context), 1706 make_bindings_trace_event(cg_context), 1707 make_report_coop_access(cg_context), 1708 make_report_deprecate_as(cg_context), 1709 make_report_measure_as(cg_context), 1710 make_log_activity(cg_context), 1711 EmptyNode(), 1712 ]) 1713 1714 if "Getter" in cg_context.property_.extended_attributes.values_of( 1715 "Custom"): 1716 text = _format("${class_name}::{}(${info});", 1717 custom_function_name(cg_context)) 1718 body.append(TextNode(text)) 1719 return func_def 1720 1721 body.extend([ 1722 make_return_value_cache_return_early(cg_context), 1723 EmptyNode(), 1724 make_check_security_of_return_value(cg_context), 1725 make_v8_set_return_value(cg_context), 1726 make_report_high_entropy(cg_context), 1727 make_return_value_cache_update_value(cg_context), 1728 ]) 1729 1730 return func_def 1731 1732 1733def make_attribute_set_callback_def(cg_context, function_name): 1734 assert isinstance(cg_context, CodeGenContext) 1735 assert isinstance(function_name, str) 1736 1737 ext_attrs = cg_context.attribute.extended_attributes 1738 if cg_context.attribute.is_readonly and not any( 1739 ext_attr in ext_attrs 1740 for ext_attr in ("LegacyLenientSetter", "PutForwards", 1741 "Replaceable")): 1742 return None 1743 1744 func_def = _make_empty_callback_def(cg_context, function_name) 1745 body = func_def.body 1746 1747 if "LegacyLenientSetter" in ext_attrs: 1748 body.append(TextNode("// [LegacyLenientSetter]")) 1749 return func_def 1750 1751 body.extend([ 1752 make_check_receiver(cg_context), 1753 EmptyNode(), 1754 make_runtime_call_timer_scope(cg_context), 1755 make_bindings_trace_event(cg_context), 1756 make_report_deprecate_as(cg_context), 1757 make_report_measure_as(cg_context), 1758 make_log_activity(cg_context), 1759 EmptyNode(), 1760 ]) 1761 1762 if "Setter" in cg_context.property_.extended_attributes.values_of( 1763 "Custom"): 1764 text = _format("${class_name}::{}(${v8_property_value}, ${info});", 1765 custom_function_name(cg_context)) 1766 body.append(TextNode(text)) 1767 return func_def 1768 1769 # Binary size reduction hack 1770 # 1. Drop the check of argument length although this is a violation of 1771 # Web IDL. 1772 # 2. Leverage the nature of [LegacyTreatNonObjectAsNull] (ES to IDL 1773 # conversion never fails). 1774 if (cg_context.attribute.idl_type.is_typedef 1775 and (cg_context.attribute.idl_type.identifier in ( 1776 "EventHandler", "OnBeforeUnloadEventHandler", 1777 "OnErrorEventHandler"))): 1778 body.extend([ 1779 TextNode("""\ 1780EventListener* event_handler = JSEventHandler::CreateOrNull( 1781 ${v8_property_value}, 1782 JSEventHandler::HandlerType::k${attribute.idl_type.identifier});\ 1783"""), 1784 ]) 1785 code_generator_info = cg_context.attribute.code_generator_info 1786 func_name = name_style.api_func("set", cg_context.attribute.identifier) 1787 if code_generator_info.defined_in_partial: 1788 class_name = (code_generator_info.receiver_implemented_as 1789 or name_style.class_( 1790 cg_context.attribute.owner_mixin.identifier)) 1791 text = _format( 1792 "{class_name}::{func_name}" 1793 "(*${blink_receiver}, event_handler);", 1794 class_name=class_name, 1795 func_name=func_name) 1796 else: 1797 text = _format("${blink_receiver}->{func_name}(event_handler);", 1798 func_name=func_name) 1799 body.append(TextNode(text)) 1800 return func_def 1801 1802 # Binary size reduction hack 1803 # When the following conditions are met, the implementation is shared. 1804 # 1. The attribute is annotated with [CEReactions, Reflect] and not 1805 # annotated with other extended attributes having side effect. 1806 # 2. The interface is implementing Element. 1807 def optimize_element_cereactions_reflect(): 1808 has_cereactions = False 1809 has_reflect = False 1810 for key in ext_attrs.keys(): 1811 if key == "CEReactions": 1812 has_cereactions = True 1813 elif key == "Reflect": 1814 has_reflect = True 1815 elif key in ("Affects", "CustomElementCallbacks", "DeprecateAs", 1816 "Exposed", "LogActivity", "LogAllWorlds", "Measure", 1817 "MeasureAs", "ReflectEmpty", "ReflectInvalid", 1818 "ReflectMissing", "ReflectOnly", 1819 "RuntimeCallStatsCounter", "RuntimeEnabled", 1820 "SecureContext", "URL", "Unscopable"): 1821 pass 1822 else: 1823 return None 1824 if not (has_cereactions and has_reflect): 1825 return None 1826 if not cg_context.interface.does_implement("Element"): 1827 return None 1828 content_attribute = _make_reflect_content_attribute_key( 1829 body, cg_context) 1830 idl_type = cg_context.attribute.idl_type.unwrap(typedef=True) 1831 if idl_type.is_boolean: 1832 func_name = "PerformAttributeSetCEReactionsReflectTypeBoolean" 1833 elif idl_type.type_name == "String": 1834 func_name = "PerformAttributeSetCEReactionsReflectTypeString" 1835 elif idl_type.type_name == "StringTreatNullAs": 1836 func_name = ("PerformAttributeSetCEReactionsReflect" 1837 "TypeStringLegacyNullToEmptyString") 1838 elif idl_type.type_name == "StringOrNull": 1839 func_name = "PerformAttributeSetCEReactionsReflectTypeStringOrNull" 1840 else: 1841 return None 1842 text = _format( 1843 "bindings::{func_name}" 1844 "(${info}, {content_attribute}, " 1845 "${class_like_name}, ${property_name});", 1846 func_name=func_name, 1847 content_attribute=content_attribute) 1848 return TextNode(text) 1849 1850 node = optimize_element_cereactions_reflect() 1851 if node: 1852 body.append(node) 1853 return func_def 1854 1855 body.extend([ 1856 make_check_argument_length(cg_context), 1857 EmptyNode(), 1858 ]) 1859 1860 if "PutForwards" in ext_attrs: 1861 body.append(make_steps_of_put_forwards(cg_context)) 1862 return func_def 1863 1864 if "Replaceable" in ext_attrs: 1865 body.append(make_steps_of_replaceable(cg_context)) 1866 return func_def 1867 1868 body.extend([ 1869 make_steps_of_ce_reactions(cg_context), 1870 EmptyNode(), 1871 make_v8_set_return_value(cg_context), 1872 ]) 1873 1874 return func_def 1875 1876 1877def make_constant_callback_def(cg_context, function_name): 1878 assert isinstance(cg_context, CodeGenContext) 1879 assert isinstance(function_name, str) 1880 1881 logging_nodes = SequenceNode([ 1882 make_report_deprecate_as(cg_context), 1883 make_report_measure_as(cg_context), 1884 make_log_activity(cg_context), 1885 ]) 1886 if not logging_nodes: 1887 return None 1888 1889 func_def = _make_empty_callback_def(cg_context, function_name) 1890 body = func_def.body 1891 1892 v8_set_return_value = _format( 1893 "bindings::V8SetReturnValue(${info}, ${class_name}::Constant::{});", 1894 constant_name(cg_context)) 1895 body.extend([ 1896 make_runtime_call_timer_scope(cg_context), 1897 make_bindings_trace_event(cg_context), 1898 logging_nodes, 1899 EmptyNode(), 1900 TextNode(v8_set_return_value), 1901 make_report_high_entropy(cg_context), 1902 ]) 1903 1904 return func_def 1905 1906 1907def make_constant_constant_def(cg_context, constant_name): 1908 # IDL constant's C++ constant definition 1909 assert isinstance(cg_context, CodeGenContext) 1910 assert isinstance(constant_name, str) 1911 1912 constant_type = blink_type_info(cg_context.constant.idl_type).value_t 1913 return TextNode("static constexpr {type} {name} = {value};".format( 1914 type=constant_type, 1915 name=constant_name, 1916 value=cg_context.constant.value.literal)) 1917 1918 1919def make_overload_dispatcher_function_def(cg_context, function_name): 1920 assert isinstance(cg_context, CodeGenContext) 1921 assert isinstance(function_name, str) 1922 1923 func_def = _make_empty_callback_def(cg_context, function_name) 1924 body = func_def.body 1925 1926 if cg_context.operation_group: 1927 body.append(make_operation_entry(cg_context)) 1928 body.append(EmptyNode()) 1929 body.append(make_cooperative_scheduling_safepoint(cg_context)) 1930 body.append(EmptyNode()) 1931 1932 if cg_context.constructor_group: 1933 body.append(make_constructor_entry(cg_context)) 1934 body.append(EmptyNode()) 1935 1936 body.append(make_overload_dispatcher(cg_context)) 1937 1938 return func_def 1939 1940 1941def make_constructor_entry(cg_context): 1942 assert isinstance(cg_context, CodeGenContext) 1943 1944 return SequenceNode([ 1945 make_runtime_call_timer_scope(cg_context), 1946 make_bindings_trace_event(cg_context), 1947 EmptyNode(), 1948 make_check_constructor_call(cg_context), 1949 ]) 1950 1951 1952def make_constructor_function_def(cg_context, function_name): 1953 assert isinstance(cg_context, CodeGenContext) 1954 assert isinstance(function_name, str) 1955 1956 T = TextNode 1957 1958 func_def = _make_empty_callback_def(cg_context, function_name) 1959 body = func_def.body 1960 1961 if len(cg_context.constructor_group) == 1: 1962 body.append(make_constructor_entry(cg_context)) 1963 body.append(EmptyNode()) 1964 1965 body.extend([ 1966 make_report_deprecate_as(cg_context), 1967 make_report_measure_as(cg_context), 1968 make_log_activity(cg_context), 1969 EmptyNode(), 1970 make_check_argument_length(cg_context), 1971 EmptyNode(), 1972 ]) 1973 1974 if "HTMLConstructor" in cg_context.constructor.extended_attributes: 1975 body.append(T("// [HTMLConstructor]")) 1976 text = _format( 1977 "V8HTMLConstructor::HtmlConstructor(" 1978 "${info}, *${class_name}::GetWrapperTypeInfo(), " 1979 "HTMLElementType::{});", 1980 name_style.constant(cg_context.class_like.identifier)) 1981 body.append(T(text)) 1982 body.accumulate( 1983 CodeGenAccumulator.require_include_headers([ 1984 "third_party/blink/renderer/bindings/core/v8/v8_html_constructor.h" 1985 ])) 1986 else: 1987 body.append( 1988 T("v8::Local<v8::Object> v8_wrapper = " 1989 "${return_value}->AssociateWithWrapper(${isolate}, " 1990 "${class_name}::GetWrapperTypeInfo(), ${v8_receiver});")) 1991 body.append(T("bindings::V8SetReturnValue(${info}, v8_wrapper);")) 1992 1993 return func_def 1994 1995 1996def make_constructor_callback_def(cg_context, function_name): 1997 assert isinstance(cg_context, CodeGenContext) 1998 assert isinstance(function_name, str) 1999 2000 constructor_group = cg_context.constructor_group 2001 2002 if len(constructor_group) == 1: 2003 return make_constructor_function_def( 2004 cg_context.make_copy(constructor=constructor_group[0]), 2005 function_name) 2006 2007 node = SequenceNode() 2008 for constructor in constructor_group: 2009 cgc = cg_context.make_copy(constructor=constructor) 2010 node.extend([ 2011 make_constructor_function_def( 2012 cgc, callback_function_name(cgc, constructor.overload_index)), 2013 EmptyNode(), 2014 ]) 2015 node.append( 2016 make_overload_dispatcher_function_def(cg_context, function_name)) 2017 return node 2018 2019 2020def make_exposed_construct_callback_def(cg_context, function_name): 2021 assert isinstance(cg_context, CodeGenContext) 2022 assert isinstance(function_name, str) 2023 2024 func_def = _make_empty_callback_def(cg_context, function_name) 2025 body = func_def.body 2026 2027 if (cg_context.exposed_construct.is_interface 2028 or cg_context.exposed_construct.is_callback_interface): 2029 tag = "bindings::V8ReturnValue::kInterfaceObject" 2030 elif cg_context.exposed_construct.is_namespace: 2031 tag = "bindings::V8ReturnValue::kNamespaceObject" 2032 else: 2033 assert False 2034 v8_set_return_value = _format( 2035 "bindings::V8SetReturnValue" 2036 "(${info}, {bridge}::GetWrapperTypeInfo(), {tag});", 2037 bridge=v8_bridge_class_name(cg_context.exposed_construct), 2038 tag=tag) 2039 body.extend([ 2040 make_runtime_call_timer_scope(cg_context), 2041 make_bindings_trace_event(cg_context), 2042 make_report_deprecate_as(cg_context), 2043 make_report_measure_as(cg_context), 2044 make_log_activity(cg_context), 2045 EmptyNode(), 2046 TextNode(v8_set_return_value), 2047 ]) 2048 2049 return func_def 2050 2051 2052def make_named_constructor_property_callback_def(cg_context, function_name): 2053 assert isinstance(cg_context, CodeGenContext) 2054 assert isinstance(function_name, str) 2055 2056 func_def = _make_empty_callback_def(cg_context, function_name) 2057 body = func_def.body 2058 2059 body.extend([ 2060 make_runtime_call_timer_scope(cg_context), 2061 make_bindings_trace_event(cg_context), 2062 make_report_deprecate_as(cg_context), 2063 make_report_measure_as(cg_context), 2064 make_log_activity(cg_context), 2065 EmptyNode(), 2066 ]) 2067 2068 constructor_group = cg_context.exposed_construct 2069 assert isinstance(constructor_group, web_idl.ConstructorGroup) 2070 assert isinstance(constructor_group.owner, web_idl.Interface) 2071 named_ctor_v8_bridge = v8_bridge_class_name(constructor_group.owner) 2072 cgc = CodeGenContext( 2073 interface=constructor_group.owner, 2074 constructor_group=constructor_group, 2075 is_named_constructor=True, 2076 class_name=named_ctor_v8_bridge) 2077 named_ctor_name = callback_function_name(cgc) 2078 named_ctor_def = make_constructor_callback_def(cgc, named_ctor_name) 2079 2080 return_value_cache_return_early = """\ 2081static const V8PrivateProperty::SymbolKey kPrivatePropertyNamedConstructor; 2082auto&& v8_private_named_constructor = 2083 V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertyNamedConstructor); 2084v8::Local<v8::Value> v8_named_constructor; 2085if (!v8_private_named_constructor.GetOrUndefined(${v8_receiver}) 2086 .ToLocal(&v8_named_constructor)) { 2087 return; 2088} 2089if (!v8_named_constructor->IsUndefined()) { 2090 bindings::V8SetReturnValue(${info}, v8_named_constructor); 2091 return; 2092} 2093""" 2094 2095 pattern = """\ 2096v8::Local<v8::Value> v8_value; 2097if (!bindings::CreateNamedConstructorFunction( 2098 ${script_state}, 2099 {callback}, 2100 "{func_name}", 2101 {func_length}, 2102 {v8_bridge}::GetWrapperTypeInfo()) 2103 .ToLocal(&v8_value)) { 2104 return; 2105} 2106bindings::V8SetReturnValue(${info}, v8_value); 2107""" 2108 create_named_constructor_function = _format( 2109 pattern, 2110 callback=named_ctor_name, 2111 func_name=constructor_group.identifier, 2112 func_length=constructor_group.min_num_of_required_arguments, 2113 v8_bridge=named_ctor_v8_bridge) 2114 2115 return_value_cache_update_value = """\ 2116v8_private_named_constructor.Set(${v8_receiver}, v8_value); 2117""" 2118 2119 body.extend([ 2120 TextNode(return_value_cache_return_early), 2121 TextNode(create_named_constructor_function), 2122 TextNode(return_value_cache_update_value), 2123 ]) 2124 2125 return SequenceNode([named_ctor_def, EmptyNode(), func_def]) 2126 2127 2128def make_no_alloc_direct_call_callback_def(cg_context, function_name): 2129 assert isinstance(cg_context, CodeGenContext) 2130 assert isinstance(function_name, str) 2131 2132 assert cg_context.operation_group and len(cg_context.operation_group) == 1 2133 2134 func_like = cg_context.operation_group[0] 2135 2136 return_type = ("void" if func_like.return_type.is_void else 2137 blink_type_info(func_like.return_type).value_t) 2138 arg_type_and_names = [(blink_type_info(arg.idl_type).value_t, 2139 name_style.arg_f("arg{}_{}", index + 1, 2140 arg.identifier)) 2141 for index, arg in enumerate(func_like.arguments)] 2142 arg_decls = ["v8::ApiObject arg0_receiver"] + [ 2143 "{} {}".format(arg_type, arg_name) 2144 for arg_type, arg_name in arg_type_and_names 2145 ] 2146 arg_decls.append("v8::FastApiCallbackOptions& arg_callback_options") 2147 func_def = CxxFuncDefNode(name=function_name, 2148 arg_decls=arg_decls, 2149 return_type=return_type) 2150 body = func_def.body 2151 2152 pattern = """\ 2153ThreadState::NoAllocationScope no_alloc_scope(ThreadState::Current()); 2154v8::Object* v8_receiver = reinterpret_cast<v8::Object*>(&arg0_receiver); 2155v8::Isolate* isolate = v8_receiver->GetIsolate(); 2156v8::Isolate::DisallowJavascriptExecutionScope no_js_exec_scope( 2157 isolate, 2158 v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 2159{blink_class}* blink_receiver = 2160 ToScriptWrappable(v8_receiver)->ToImpl<{blink_class}>(); 2161return blink_receiver->{member_func}({blink_arguments}, arg_callback_options);\ 2162""" 2163 blink_class = blink_class_name(cg_context.interface) 2164 member_func = backward_compatible_api_func(cg_context) 2165 blink_arguments = ", ".join( 2166 [arg_name for arg_type, arg_name in arg_type_and_names]) 2167 body.append( 2168 TextNode( 2169 _format(pattern, 2170 blink_class=blink_class, 2171 member_func=member_func, 2172 blink_arguments=blink_arguments))) 2173 2174 return func_def 2175 2176 2177def make_operation_entry(cg_context): 2178 assert isinstance(cg_context, CodeGenContext) 2179 2180 return SequenceNode([ 2181 make_runtime_call_timer_scope(cg_context), 2182 make_bindings_trace_event(cg_context), 2183 ]) 2184 2185 2186def make_operation_function_def(cg_context, function_name): 2187 assert isinstance(cg_context, CodeGenContext) 2188 assert isinstance(function_name, str) 2189 2190 func_def = _make_empty_callback_def(cg_context, function_name) 2191 body = func_def.body 2192 2193 if not cg_context.operation_group or len(cg_context.operation_group) == 1: 2194 body.append(make_operation_entry(cg_context)) 2195 body.append(EmptyNode()) 2196 2197 body.extend([ 2198 make_check_receiver(cg_context), 2199 EmptyNode(), 2200 make_report_coop_access(cg_context), 2201 make_report_deprecate_as(cg_context), 2202 make_report_measure_as(cg_context), 2203 make_log_activity(cg_context), 2204 EmptyNode(), 2205 ]) 2206 2207 if "Custom" in cg_context.property_.extended_attributes: 2208 text = _format("${class_name}::{}(${info});", 2209 custom_function_name(cg_context)) 2210 body.append(TextNode(text)) 2211 return func_def 2212 2213 body.extend([ 2214 make_check_argument_length(cg_context), 2215 EmptyNode(), 2216 make_steps_of_ce_reactions(cg_context), 2217 EmptyNode(), 2218 make_check_security_of_return_value(cg_context), 2219 make_v8_set_return_value(cg_context), 2220 make_report_high_entropy(cg_context), 2221 ]) 2222 2223 return func_def 2224 2225 2226def make_operation_callback_def(cg_context, 2227 function_name, 2228 no_alloc_direct_callback_name=None): 2229 assert isinstance(cg_context, CodeGenContext) 2230 assert isinstance(function_name, str) 2231 2232 operation_group = cg_context.operation_group 2233 2234 assert (not ("Custom" in operation_group.extended_attributes) 2235 or len(operation_group) == 1) 2236 assert (not ("NoAllocDirectCall" in operation_group.extended_attributes) 2237 or len(operation_group) == 1) 2238 2239 if "NoAllocDirectCall" in operation_group.extended_attributes: 2240 return ListNode([ 2241 make_operation_function_def( 2242 cg_context.make_copy(operation=operation_group[0]), 2243 function_name), 2244 EmptyNode(), 2245 make_no_alloc_direct_call_callback_def( 2246 cg_context.make_copy(operation=operation_group[0]), 2247 no_alloc_direct_callback_name), 2248 ]) 2249 2250 if len(operation_group) == 1: 2251 return make_operation_function_def( 2252 cg_context.make_copy(operation=operation_group[0]), function_name) 2253 2254 node = SequenceNode() 2255 for operation in operation_group: 2256 cgc = cg_context.make_copy(operation=operation) 2257 node.extend([ 2258 make_operation_function_def( 2259 cgc, callback_function_name(cgc, operation.overload_index)), 2260 EmptyNode(), 2261 ]) 2262 node.append( 2263 make_overload_dispatcher_function_def(cg_context, function_name)) 2264 return node 2265 2266 2267def make_stringifier_callback_def(cg_context, function_name): 2268 assert isinstance(cg_context, CodeGenContext) 2269 assert isinstance(function_name, str) 2270 2271 if cg_context.stringifier.attribute: 2272 return make_attribute_get_callback_def( 2273 cg_context.make_copy( 2274 attribute=cg_context.stringifier.attribute, 2275 attribute_get=True), function_name) 2276 elif cg_context.stringifier.operation: 2277 return make_operation_function_def( 2278 cg_context.make_copy(operation=cg_context.stringifier.operation), 2279 function_name) 2280 assert False 2281 2282 2283# ---------------------------------------------------------------------------- 2284# Callback functions of indexed and named interceptors 2285# ---------------------------------------------------------------------------- 2286 2287 2288def _make_interceptor_callback(cg_context, function_name, arg_decls, arg_names, 2289 class_name, runtime_call_timer_name): 2290 assert isinstance(cg_context, CodeGenContext) 2291 assert isinstance(function_name, str) 2292 assert isinstance(arg_decls, (list, tuple)) 2293 assert all(isinstance(arg_decl, str) for arg_decl in arg_decls) 2294 assert isinstance(arg_names, (list, tuple)) 2295 assert all(isinstance(arg_name, str) for arg_name in arg_names) 2296 assert _is_none_or_str(class_name) 2297 assert isinstance(runtime_call_timer_name, str) 2298 2299 func_decl = CxxFuncDeclNode( 2300 name=function_name, 2301 arg_decls=arg_decls, 2302 return_type="void", 2303 static=True) 2304 2305 func_def = _make_interceptor_callback_def(cg_context, function_name, 2306 arg_decls, arg_names, class_name, 2307 runtime_call_timer_name) 2308 2309 return func_decl, func_def 2310 2311 2312def _make_interceptor_callback_def(cg_context, function_name, arg_decls, 2313 arg_names, class_name, 2314 runtime_call_timer_name): 2315 assert isinstance(cg_context, CodeGenContext) 2316 assert isinstance(function_name, str) 2317 assert isinstance(arg_decls, (list, tuple)) 2318 assert all(isinstance(arg_decl, str) for arg_decl in arg_decls) 2319 assert isinstance(arg_names, (list, tuple)) 2320 assert all(isinstance(arg_name, str) for arg_name in arg_names) 2321 assert _is_none_or_str(class_name) 2322 assert isinstance(runtime_call_timer_name, str) 2323 2324 func_def = CxxFuncDefNode( 2325 name=function_name, 2326 arg_decls=arg_decls, 2327 return_type="void", 2328 class_name=class_name) 2329 func_def.set_base_template_vars(cg_context.template_bindings()) 2330 body = func_def.body 2331 for arg_name in arg_names: 2332 body.add_template_var(arg_name, arg_name) 2333 bind_callback_local_vars(body, cg_context) 2334 2335 body.extend([ 2336 make_runtime_call_timer_scope(cg_context, runtime_call_timer_name), 2337 EmptyNode(), 2338 ]) 2339 2340 return func_def 2341 2342 2343def make_indexed_property_getter_callback(cg_context, function_name): 2344 assert isinstance(cg_context, CodeGenContext) 2345 assert isinstance(function_name, str) 2346 2347 arg_decls = [ 2348 "uint32_t index", 2349 "const v8::PropertyCallbackInfo<v8::Value>& info", 2350 ] 2351 arg_names = ["index", "info"] 2352 2353 func_decl, func_def = _make_interceptor_callback( 2354 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2355 "IndexedPropertyGetter") 2356 body = func_def.body 2357 2358 if not cg_context.interface.indexed_and_named_properties.indexed_getter: 2359 body.append( 2360 TextNode("""\ 2361v8::Local<v8::String> property_name = 2362 V8AtomicString(${isolate}, AtomicString::Number(${index})); 2363${class_name}::NamedPropertyGetterCallback(property_name, ${info}); 2364""")) 2365 return func_decl, func_def 2366 2367 bind_return_value(body, cg_context, overriding_args=["${index}"]) 2368 2369 body.extend([ 2370 TextNode("""\ 2371// LegacyPlatformObjectGetOwnProperty 2372// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty 2373// step 1.2. If index is a supported property index, then: 2374// step 3. Return OrdinaryGetOwnProperty(O, P). 2375if (${index} >= ${blink_receiver}->length()) 2376 return; // Do not intercept. Fallback to OrdinaryGetOwnProperty. 2377"""), 2378 make_v8_set_return_value(cg_context), 2379 ]) 2380 2381 return func_decl, func_def 2382 2383 2384def make_indexed_property_setter_callback(cg_context, function_name): 2385 assert isinstance(cg_context, CodeGenContext) 2386 assert isinstance(function_name, str) 2387 2388 arg_decls = [ 2389 "uint32_t index", 2390 "v8::Local<v8::Value> v8_property_value", 2391 "const v8::PropertyCallbackInfo<v8::Value>& info", 2392 ] 2393 arg_names = ["index", "v8_property_value", "info"] 2394 2395 func_decl, func_def = _make_interceptor_callback( 2396 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2397 "IndexedPropertySetter") 2398 body = func_def.body 2399 2400 if not cg_context.interface.indexed_and_named_properties.indexed_getter: 2401 body.append( 2402 TextNode("""\ 2403v8::Local<v8::String> property_name = 2404 V8AtomicString(${isolate}, AtomicString::Number(${index})); 2405${class_name}::NamedPropertySetterCallback( 2406 property_name, ${v8_property_value}, ${info}); 2407""")) 2408 return func_decl, func_def 2409 2410 if not cg_context.indexed_property_setter: 2411 body.append( 2412 TextNode("""\ 2413// 3.9.2. [[Set]] 2414// https://heycam.github.io/webidl/#legacy-platform-object-set 2415// OrdinarySetWithOwnDescriptor will end up calling DefineOwnProperty, 2416// which will fail when the receiver object is this legacy platform 2417// object. 2418bindings::V8SetReturnValue(${info}, nullptr); 2419if (${info}.ShouldThrowOnError()) { 2420 ExceptionState exception_state(${info}.GetIsolate(), 2421 ExceptionState::kIndexedSetterContext, 2422 "${interface.identifier}"); 2423 exception_state.ThrowTypeError( 2424 "Indexed property setter is not supported."); 2425} 2426""")) 2427 return func_decl, func_def 2428 2429 bind_return_value( 2430 body, 2431 cg_context, 2432 overriding_args=["${index}", "${blink_property_value}"]) 2433 body.register_code_symbol( 2434 make_v8_to_blink_value( 2435 "blink_property_value", 2436 "${v8_property_value}", 2437 cg_context.indexed_property_setter.arguments[1].idl_type, 2438 argument_index=2)) 2439 2440 body.extend([ 2441 TextNode("""\ 2442// 3.9.2. [[Set]] 2443// https://heycam.github.io/webidl/#legacy-platform-object-set 2444// step 1. If O and Receiver are the same object, then:\ 2445"""), 2446 CxxLikelyIfNode(cond="${info}.Holder() == ${info}.This()", 2447 body=[ 2448 TextNode("""\ 2449// step 1.1.1. Invoke the indexed property setter with P and V.\ 2450"""), 2451 make_steps_of_ce_reactions(cg_context), 2452 EmptyNode(), 2453 make_v8_set_return_value(cg_context), 2454 TextNode("""\ 2455bindings::V8SetReturnValue(${info}, nullptr); 2456return;"""), 2457 ]), 2458 EmptyNode(), 2459 TextNode("""\ 2460// Do not intercept. Fallback to OrdinarySetWithOwnDescriptor. 2461"""), 2462 ]) 2463 2464 return func_decl, func_def 2465 2466 2467def make_indexed_property_deleter_callback(cg_context, function_name): 2468 assert isinstance(cg_context, CodeGenContext) 2469 assert isinstance(function_name, str) 2470 2471 arg_decls = [ 2472 "uint32_t index", 2473 "const v8::PropertyCallbackInfo<v8::Boolean>& info", 2474 ] 2475 arg_names = ["index", "info"] 2476 2477 func_decl, func_def = _make_interceptor_callback( 2478 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2479 "IndexedPropertyDeleter") 2480 body = func_def.body 2481 2482 if not cg_context.interface.indexed_and_named_properties.indexed_getter: 2483 body.append( 2484 TextNode("""\ 2485v8::Local<v8::String> property_name = 2486 V8AtomicString(${isolate}, AtomicString::Number(${index})); 2487${class_name}::NamedPropertyDeleterCallback(property_name, ${info}); 2488""")) 2489 return func_decl, func_def 2490 2491 body.append( 2492 TextNode("""\ 2493// 3.9.4. [[Delete]] 2494// https://heycam.github.io/webidl/#legacy-platform-object-delete 2495// step 1.2. If index is not a supported property index, then return true. 2496// step 1.3. Return false. 2497const bool is_supported = ${index} < ${blink_receiver}->length(); 2498bindings::V8SetReturnValue(${info}, !is_supported); 2499if (is_supported and ${info}.ShouldThrowOnError()) { 2500 ExceptionState exception_state(${info}.GetIsolate(), 2501 ExceptionState::kIndexedDeletionContext, 2502 "${interface.identifier}"); 2503 exception_state.ThrowTypeError("Index property deleter is not supported."); 2504} 2505""")) 2506 2507 return func_decl, func_def 2508 2509 2510def make_indexed_property_definer_callback(cg_context, function_name): 2511 assert isinstance(cg_context, CodeGenContext) 2512 assert isinstance(function_name, str) 2513 2514 arg_decls = [ 2515 "uint32_t index", 2516 "const v8::PropertyDescriptor& v8_property_desc", 2517 "const v8::PropertyCallbackInfo<v8::Value>& info", 2518 ] 2519 arg_names = ["index", "v8_property_desc", "info"] 2520 2521 func_decl, func_def = _make_interceptor_callback( 2522 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2523 "IndexedPropertyDefiner") 2524 body = func_def.body 2525 2526 if not cg_context.interface.indexed_and_named_properties.indexed_getter: 2527 body.append( 2528 TextNode("""\ 2529v8::Local<v8::String> property_name = 2530 V8AtomicString(${isolate}, AtomicString::Number(${index})); 2531${class_name}::NamedPropertyDefinerCallback( 2532 property_name, ${v8_property_desc}, ${info}); 2533""")) 2534 return func_decl, func_def 2535 2536 body.append( 2537 TextNode("""\ 2538// 3.9.3. [[DefineOwnProperty]] 2539// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty 2540// step 1.1. If the result of calling IsDataDescriptor(Desc) is false, then 2541// return false. 2542if (v8_property_desc.has_get() || v8_property_desc.has_set()) { 2543 bindings::V8SetReturnValue(${info}, nullptr); 2544 if (${info}.ShouldThrowOnError()) { 2545 ExceptionState exception_state(${info}.GetIsolate(), 2546 ExceptionState::kIndexedSetterContext, 2547 "${interface.identifier}"); 2548 exception_state.ThrowTypeError("Accessor properties are not allowed."); 2549 } 2550 return; 2551} 2552""")) 2553 2554 if not cg_context.interface.indexed_and_named_properties.indexed_setter: 2555 body.append( 2556 TextNode("""\ 2557// step 1.2. If O does not implement an interface with an indexed property 2558// setter, then return false. 2559bindings::V8SetReturnValue(${info}, nullptr); 2560if (${info}.ShouldThrowOnError()) { 2561 ExceptionState exception_state(${info}.GetIsolate(), 2562 ExceptionState::kIndexedSetterContext, 2563 "${interface.identifier}"); 2564 exception_state.ThrowTypeError("Index property setter is not supported."); 2565} 2566""")) 2567 else: 2568 body.append( 2569 TextNode("""\ 2570// step 1.3. Invoke the indexed property setter with P and Desc.[[Value]]. 2571${class_name}::IndexedPropertySetterCallback( 2572 ${index}, ${v8_property_desc}.value(), ${info}); 2573""")) 2574 2575 return func_decl, func_def 2576 2577 2578def make_indexed_property_descriptor_callback(cg_context, function_name): 2579 assert isinstance(cg_context, CodeGenContext) 2580 assert isinstance(function_name, str) 2581 2582 arg_decls = [ 2583 "uint32_t index", 2584 "const v8::PropertyCallbackInfo<v8::Value>& info", 2585 ] 2586 arg_names = ["index", "info"] 2587 2588 func_decl, func_def = _make_interceptor_callback( 2589 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2590 "IndexedPropertyDescriptor") 2591 body = func_def.body 2592 2593 if not cg_context.interface.indexed_and_named_properties.indexed_getter: 2594 body.append( 2595 TextNode("""\ 2596v8::Local<v8::String> property_name = 2597 V8AtomicString(${isolate}, AtomicString::Number(${index})); 2598${class_name}::NamedPropertyDescriptorCallback(property_name, ${info}); 2599""")) 2600 return func_decl, func_def 2601 2602 pattern = """\ 2603// LegacyPlatformObjectGetOwnProperty 2604// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty 2605// step 1.2.3. If operation was defined without an identifier, then set 2606// value to the result of performing the steps listed in the interface 2607// description to determine the value of an indexed property with index 2608// as the index. 2609// step 1.2.4. Otherwise, operation was defined with an identifier. Set 2610// value to the result of performing the steps listed in the description 2611// of operation with index as the only argument value. 2612${class_name}::IndexedPropertyGetterCallback(${index}, ${info}); 2613v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get(); 2614// step 1.2. If index is a supported property index, then: 2615// step 3. Return OrdinaryGetOwnProperty(O, P). 2616if (v8_value->IsUndefined()) 2617 return; // Do not intercept. Fallback to OrdinaryGetOwnProperty. 2618 2619// step 1.2.6. Set desc.[[Value]] to the result of converting value to an 2620// ECMAScript value. 2621// step 1.2.7. If O implements an interface with an indexed property setter, 2622// then set desc.[[Writable]] to true, otherwise set it to false. 2623// step 1.2.8. Set desc.[[Enumerable]] and desc.[[Configurable]] to true. 2624v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable}); 2625desc.set_enumerable(true); 2626desc.set_configurable(true); 2627bindings::V8SetReturnValue(${info}, desc);""" 2628 writable = bool( 2629 cg_context.interface.indexed_and_named_properties.indexed_setter) 2630 cxx_writable = "true" if writable else "false" 2631 body.append(TextNode(_format(pattern, cxx_writable=cxx_writable))) 2632 2633 return func_decl, func_def 2634 2635 2636def make_indexed_property_enumerator_callback(cg_context, function_name): 2637 assert isinstance(cg_context, CodeGenContext) 2638 assert isinstance(function_name, str) 2639 2640 if not cg_context.interface.indexed_and_named_properties.indexed_getter: 2641 return None, None 2642 2643 arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"] 2644 arg_names = ["info"] 2645 2646 func_decl, func_def = _make_interceptor_callback( 2647 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2648 "IndexedPropertyEnumerator") 2649 body = func_def.body 2650 2651 body.append( 2652 TextNode("""\ 2653// 3.9.6. [[OwnPropertyKeys]] 2654// https://heycam.github.io/webidl/#legacy-platform-object-ownpropertykeys 2655// step 2. If O supports indexed properties, then for each index of O's 2656// supported property indices, in ascending numerical order, append 2657// ! ToString(index) to keys. 2658uint32_t length = ${blink_receiver}->length(); 2659v8::Local<v8::Array> array = 2660 bindings::EnumerateIndexedProperties(${isolate}, length); 2661bindings::V8SetReturnValue(${info}, array); 2662""")) 2663 body.accumulate( 2664 CodeGenAccumulator.require_include_headers([ 2665 "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h" 2666 ])) 2667 2668 return func_decl, func_def 2669 2670 2671def make_named_property_getter_callback(cg_context, function_name): 2672 assert isinstance(cg_context, CodeGenContext) 2673 assert isinstance(function_name, str) 2674 2675 arg_decls = [ 2676 "v8::Local<v8::Name> v8_property_name", 2677 "const v8::PropertyCallbackInfo<v8::Value>& info", 2678 ] 2679 arg_names = ["v8_property_name", "info"] 2680 2681 func_decl, func_def = _make_interceptor_callback( 2682 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2683 "NamedPropertyGetter") 2684 body = func_def.body 2685 2686 bind_return_value( 2687 body, cg_context, overriding_args=["${blink_property_name}"]) 2688 2689 if "Custom" in cg_context.named_property_getter.extended_attributes: 2690 text = _format("${class_name}::{}(${blink_property_name}, ${info});", 2691 custom_function_name(cg_context)) 2692 body.append(TextNode(text)) 2693 return func_decl, func_def 2694 2695 # The named property getter's implementation of Blink is not designed to 2696 # represent the property existence, and we have to determine the property 2697 # existence by heuristics. 2698 type = cg_context.return_type.unwrap() 2699 if type.is_any or type.is_object: 2700 not_found_expr = "${return_value}.IsEmpty()" 2701 elif type.is_string: 2702 not_found_expr = "${return_value}.IsNull()" 2703 elif type.is_interface: 2704 not_found_expr = "!${return_value}" 2705 elif type.is_union: 2706 not_found_expr = "${return_value}.IsNull()" 2707 else: 2708 assert False 2709 2710 body.extend([ 2711 TextNode("""\ 2712// LegacyPlatformObjectGetOwnProperty 2713// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty 2714// step 2.1. If the result of running the named property visibility 2715// algorithm with property name P and object O is true, then:\ 2716"""), 2717 CxxUnlikelyIfNode( 2718 cond=not_found_expr, 2719 body=[ 2720 TextNode("// step 3. Return OrdinaryGetOwnProperty(O, P)."), 2721 TextNode("return; // Do not intercept."), 2722 ]), 2723 TextNode("""\ 2724// step 2.1.3. If operation was defined without an identifier, then set 2725// value to the result of performing the steps listed in the interface 2726// description to determine the value of a named property with P as the 2727// name. 2728// step 2.1.4. Otherwise, operation was defined with an identifier. Set 2729// value to the result of performing the steps listed in the description 2730// of operation with P as the only argument value.\ 2731"""), 2732 make_v8_set_return_value(cg_context), 2733 ]) 2734 2735 return func_decl, func_def 2736 2737 2738def make_named_property_setter_callback(cg_context, function_name): 2739 assert isinstance(cg_context, CodeGenContext) 2740 assert isinstance(function_name, str) 2741 2742 arg_decls = [ 2743 "v8::Local<v8::Name> v8_property_name", 2744 "v8::Local<v8::Value> v8_property_value", 2745 "const v8::PropertyCallbackInfo<v8::Value>& info", 2746 ] 2747 arg_names = ["v8_property_name", "v8_property_value", "info"] 2748 2749 func_decl, func_def = _make_interceptor_callback( 2750 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2751 "NamedPropertySetter") 2752 body = func_def.body 2753 2754 if not cg_context.named_property_setter: 2755 body.append( 2756 TextNode("""\ 2757// 3.9.2. [[Set]] 2758// https://heycam.github.io/webidl/#legacy-platform-object-set 2759// step 3. Perform ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver, ownDesc).\ 2760""")) 2761 if ("LegacyOverrideBuiltIns" in 2762 cg_context.interface.extended_attributes): 2763 body.append( 2764 TextNode("""\ 2765// [LegacyOverrideBuiltIns] 2766if (${info}.Holder()->GetRealNamedPropertyAttributesInPrototypeChain( 2767 ${current_context}, ${v8_property_name}).IsJust()) { 2768 return; // Fallback to the existing property. 2769} 2770""")) 2771 body.append( 2772 TextNode("""\ 2773${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info}); 2774const bool is_creating = ${info}.GetReturnValue().Get()->IsUndefined(); 2775if (!is_creating) { 2776 bindings::V8SetReturnValue(${info}, nullptr); 2777 if (${info}.ShouldThrowOnError()) { 2778 ExceptionState exception_state(${info}.GetIsolate(), 2779 ExceptionState::kNamedSetterContext, 2780 "${interface.identifier}"); 2781 exception_state.ThrowTypeError( 2782 "Named property setter is not supported."); 2783 } 2784 return; 2785} 2786 2787// Do not intercept. Fallback and let it define a new own property. 2788""")) 2789 return func_decl, func_def 2790 2791 bind_return_value( 2792 body, 2793 cg_context, 2794 overriding_args=["${blink_property_name}", "${blink_property_value}"]) 2795 body.register_code_symbol( 2796 make_v8_to_blink_value( 2797 "blink_property_value", 2798 "${v8_property_value}", 2799 cg_context.named_property_setter.arguments[1].idl_type, 2800 argument_index=2)) 2801 2802 if "Custom" in cg_context.named_property_setter.extended_attributes: 2803 text = _format( 2804 "${class_name}::{}" 2805 "(${blink_property_name}, ${v8_property_value}, ${info});", 2806 custom_function_name(cg_context)) 2807 body.append(TextNode(text)) 2808 return func_decl, func_def 2809 2810 body.extend([ 2811 TextNode("""\ 2812// 3.9.2. [[Set]] 2813// https://heycam.github.io/webidl/#legacy-platform-object-set 2814// step 1. If O and Receiver are the same object, then:\ 2815"""), 2816 CxxLikelyIfNode(cond="${info}.Holder() == ${info}.This()", 2817 body=[ 2818 TextNode("""\ 2819// step 1.2.1. Invoke the named property setter with P and V.\ 2820"""), 2821 make_steps_of_ce_reactions(cg_context), 2822 EmptyNode(), 2823 make_v8_set_return_value(cg_context), 2824 TextNode("""\ 2825% if interface.identifier == "CSSStyleDeclaration": 2826// CSSStyleDeclaration is abusing named properties. 2827// Do not intercept if the property is not found. 2828% else: 2829bindings::V8SetReturnValue(${info}, nullptr); 2830% endif 2831return;"""), 2832 ]), 2833 EmptyNode(), 2834 TextNode("""\ 2835// Do not intercept. Fallback to OrdinarySetWithOwnDescriptor. 2836"""), 2837 ]) 2838 2839 return func_decl, func_def 2840 2841 2842def make_named_property_deleter_callback(cg_context, function_name): 2843 assert isinstance(cg_context, CodeGenContext) 2844 assert isinstance(function_name, str) 2845 2846 arg_decls = [ 2847 "v8::Local<v8::Name> v8_property_name", 2848 "const v8::PropertyCallbackInfo<v8::Boolean>& info", 2849 ] 2850 arg_names = ["v8_property_name", "info"] 2851 2852 func_decl, func_def = _make_interceptor_callback( 2853 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2854 "NamedPropertyDeleter") 2855 body = func_def.body 2856 2857 props = cg_context.interface.indexed_and_named_properties 2858 if (not cg_context.named_property_deleter 2859 and "NotEnumerable" in props.named_getter.extended_attributes): 2860 body.append( 2861 TextNode("""\ 2862// 3.9.4. [[Delete]] 2863// https://heycam.github.io/webidl/#legacy-platform-object-delete 2864// step 2. If O supports named properties, O does not implement an interface 2865// with the [Global] extended attribute and the result of calling the 2866// named property visibility algorithm with property name P and object O 2867// is true, then: 2868// 2869// There is no easy way to determine whether the named property is visible 2870// or not. Just do not intercept and fallback to the default behavior. 2871""")) 2872 return func_decl, func_def 2873 2874 if not cg_context.named_property_deleter: 2875 body.append( 2876 TextNode("""\ 2877// 3.9.4. [[Delete]] 2878// https://heycam.github.io/webidl/#legacy-platform-object-delete 2879// step 2. If O supports named properties, O does not implement an interface 2880// with the [Global] extended attribute and the result of calling the 2881// named property visibility algorithm with property name P and object O 2882// is true, then: 2883// step 2.1. If O does not implement an interface with a named property 2884// deleter, then return false. 2885ExceptionState exception_state(${info}.GetIsolate(), 2886 ExceptionState::kNamedDeletionContext, 2887 "${interface.identifier}"); 2888bool does_exist = ${blink_receiver}->NamedPropertyQuery( 2889 ${blink_property_name}, exception_state); 2890if (exception_state.HadException()) 2891 return; 2892if (does_exist) { 2893 bindings::V8SetReturnValue(${info}, false); 2894 if (${info}.ShouldThrowOnError()) { 2895 exception_state.ThrowTypeError("Named property deleter is not supported."); 2896 } 2897 return; 2898} 2899 2900// Do not intercept. 2901""")) 2902 return func_decl, func_def 2903 2904 bind_return_value( 2905 body, cg_context, overriding_args=["${blink_property_name}"]) 2906 2907 if "Custom" in cg_context.named_property_deleter.extended_attributes: 2908 text = _format("${class_name}::{}(${blink_property_name}, ${info});", 2909 custom_function_name(cg_context)) 2910 body.append(TextNode(text)) 2911 return func_decl, func_def 2912 2913 body.extend([ 2914 TextNode("""\ 2915// 3.9.4. [[Delete]] 2916// https://heycam.github.io/webidl/#legacy-platform-object-delete\ 2917"""), 2918 make_steps_of_ce_reactions(cg_context), 2919 EmptyNode(), 2920 make_v8_set_return_value(cg_context), 2921 TextNode("""\ 2922if (${return_value} == NamedPropertyDeleterResult::kDidNotDelete) { 2923 if (${info}.ShouldThrowOnError()) { 2924 ExceptionState exception_state(${info}.GetIsolate(), 2925 ExceptionState::kNamedDeletionContext, 2926 "${interface.identifier}"); 2927 exception_state.ThrowTypeError("Failed to delete a property."); 2928 } 2929 return; 2930}"""), 2931 ]) 2932 2933 return func_decl, func_def 2934 2935 2936def make_named_property_definer_callback(cg_context, function_name): 2937 assert isinstance(cg_context, CodeGenContext) 2938 assert isinstance(function_name, str) 2939 2940 arg_decls = [ 2941 "v8::Local<v8::Name> v8_property_name", 2942 "const v8::PropertyDescriptor& v8_property_desc", 2943 "const v8::PropertyCallbackInfo<v8::Value>& info", 2944 ] 2945 arg_names = ["v8_property_name", "v8_property_desc", "info"] 2946 2947 func_decl, func_def = _make_interceptor_callback( 2948 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 2949 "NamedPropertyDefiner") 2950 body = func_def.body 2951 2952 if cg_context.interface.identifier == "CSSStyleDeclaration": 2953 body.append( 2954 TextNode("""\ 2955// CSSStyleDeclaration is abusing named properties. 2956// Do not intercept. Fallback to OrdinaryDefineOwnProperty. 2957""")) 2958 elif cg_context.interface.identifier in ("HTMLEmbedElement", 2959 "HTMLObjectElement"): 2960 body.append( 2961 TextNode("""\ 2962// HTMLEmbedElement and HTMLObjectElement are abusing named properties. 2963// Do not intercept. Fallback to OrdinaryDefineOwnProperty. 2964""")) 2965 elif not cg_context.interface.indexed_and_named_properties.named_setter: 2966 body.append( 2967 TextNode("""\ 2968// 3.9.3. [[DefineOwnProperty]] 2969// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty 2970// step 2.1. Let creating be true if P is not a supported property name, and 2971// false otherwise. 2972// step 2.2.1. If creating is false and O does not implement an interface 2973// with a named property setter, then return false. 2974${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info}); 2975const bool is_creating = ${info}.GetReturnValue().Get()->IsUndefined(); 2976if (!is_creating) { 2977 bindings::V8SetReturnValue(${info}, nullptr); 2978 if (${info}.ShouldThrowOnError()) { 2979 ExceptionState exception_state(${info}.GetIsolate(), 2980 ExceptionState::kNamedSetterContext, 2981 "${interface.identifier}"); 2982 exception_state.ThrowTypeError("Named property setter is not supported."); 2983 } 2984 return; 2985} 2986 2987// Do not intercept. Fallback to OrdinaryDefineOwnProperty. 2988""")) 2989 else: 2990 body.append( 2991 TextNode("""\ 2992// 3.9.3. [[DefineOwnProperty]] 2993// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty 2994// step 2.2.2. If O implements an interface with a named property setter, 2995// then: 2996// step 2.2.2.1. If the result of calling IsDataDescriptor(Desc) is false, 2997// then return false. 2998if (v8_property_desc.has_get() || v8_property_desc.has_set()) { 2999 bindings::V8SetReturnValue(${info}, nullptr); 3000 if (${info}.ShouldThrowOnError()) { 3001 ExceptionState exception_state(${info}.GetIsolate(), 3002 ExceptionState::kNamedSetterContext, 3003 "${interface.identifier}"); 3004 exception_state.ThrowTypeError("Accessor properties are not allowed."); 3005 } 3006 return; 3007} 3008 3009// step 2.2.2.2. Invoke the named property setter with P and Desc.[[Value]]. 3010${class_name}::NamedPropertySetterCallback( 3011 ${v8_property_name}, ${v8_property_desc}.value(), ${info}); 3012bindings::V8SetReturnValue(${info}, nullptr); 3013""")) 3014 3015 return func_decl, func_def 3016 3017 3018def make_named_property_descriptor_callback(cg_context, function_name): 3019 assert isinstance(cg_context, CodeGenContext) 3020 assert isinstance(function_name, str) 3021 3022 arg_decls = [ 3023 "v8::Local<v8::Name> v8_property_name", 3024 "const v8::PropertyCallbackInfo<v8::Value>& info", 3025 ] 3026 arg_names = ["v8_property_name", "info"] 3027 3028 func_decl, func_def = _make_interceptor_callback( 3029 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 3030 "NamedPropertyDescriptor") 3031 body = func_def.body 3032 3033 body.append( 3034 TextNode("""\ 3035// LegacyPlatformObjectGetOwnProperty 3036// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty\ 3037""")) 3038 3039 if ("LegacyOverrideBuiltIns" not in 3040 cg_context.interface.extended_attributes): 3041 body.append( 3042 TextNode("""\ 3043// step 2.1. If the result of running the named property visibility algorithm 3044// with property name P and object O is true, then: 3045if (${v8_receiver}->GetRealNamedPropertyAttributesInPrototypeChain( 3046 ${current_context}, ${v8_property_name}).IsJust()) { 3047 return; // Do not intercept. Fallback to OrdinaryGetOwnProperty. 3048} 3049""")) 3050 3051 pattern = """\ 3052// step 2.1.3. If operation was defined without an identifier, then set 3053// value to the result of performing the steps listed in the interface 3054// description to determine the value of a named property with P as the 3055// name. 3056// step 2.1.4. Otherwise, operation was defined with an identifier. Set 3057// value to the result of performing the steps listed in the description 3058// of operation with P as the only argument value. 3059${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info}); 3060v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get(); 3061// step 2.1. If the result of running the named property visibility 3062// algorithm with property name P and object O is true, then: 3063// step 3. Return OrdinaryGetOwnProperty(O, P). 3064if (v8_value->IsUndefined()) 3065 return; // Do not intercept. Fallback to OrdinaryGetOwnProperty. 3066 3067// step 2.1.6. Set desc.[[Value]] to the result of converting value to an 3068// ECMAScript value. 3069// step 2.1.7. If O implements an interface with a named property setter, 3070// then set desc.[[Writable]] to true, otherwise set it to false. 3071// step 2.1.8. If O implements an interface with the 3072// [LegacyUnenumerableNamedProperties] extended attribute, then set 3073// desc.[[Enumerable]] to false, otherwise set it to true. 3074// step 2.1.9. Set desc.[[Configurable]] to true. 3075v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable}); 3076desc.set_enumerable({cxx_enumerable}); 3077desc.set_configurable(true); 3078bindings::V8SetReturnValue(${info}, desc); 3079""" 3080 props = cg_context.interface.indexed_and_named_properties 3081 writable = bool(props.named_setter) 3082 cxx_writable = "true" if writable else "false" 3083 enumerable = props.is_named_property_enumerable 3084 cxx_enumerable = "true" if enumerable else "false" 3085 body.append( 3086 TextNode( 3087 _format( 3088 pattern, 3089 cxx_writable=cxx_writable, 3090 cxx_enumerable=cxx_enumerable))) 3091 3092 return func_decl, func_def 3093 3094 3095def make_named_property_query_callback(cg_context, function_name): 3096 assert isinstance(cg_context, CodeGenContext) 3097 assert isinstance(function_name, str) 3098 3099 props = cg_context.interface.indexed_and_named_properties 3100 if "NotEnumerable" in props.named_getter.extended_attributes: 3101 return None, None 3102 3103 arg_decls = [ 3104 "v8::Local<v8::Name> v8_property_name", 3105 "const v8::PropertyCallbackInfo<v8::Integer>& info", 3106 ] 3107 arg_names = ["v8_property_name", "info"] 3108 3109 func_decl, func_def = _make_interceptor_callback( 3110 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 3111 "NamedPropertyQuery") 3112 body = func_def.body 3113 3114 flags = [] 3115 if not props.named_setter: 3116 flags.append("v8::ReadOnly") 3117 if not props.is_named_property_enumerable: 3118 flags.append("v8::DontEnum") 3119 if not flags: 3120 flags.append("v8::None") 3121 if len(flags) == 1: 3122 property_attribute = flags[0] 3123 else: 3124 property_attribute = " | ".join(flags) 3125 3126 body.extend([ 3127 TextNode("""\ 3128ExceptionState exception_state(${isolate}, 3129 ExceptionState::kNamedGetterContext, 3130 "${interface.identifier}"); 3131bool does_exist = ${blink_receiver}->NamedPropertyQuery( 3132 ${blink_property_name}, exception_state); 3133if (!does_exist) 3134 return; // Do not intercept. 3135"""), 3136 TextNode( 3137 _format( 3138 "bindings::V8SetReturnValue" 3139 "(${info}, uint32_t({property_attribute}));", 3140 property_attribute=property_attribute)), 3141 ]) 3142 3143 return func_decl, func_def 3144 3145 3146def make_named_property_enumerator_callback(cg_context, function_name): 3147 assert isinstance(cg_context, CodeGenContext) 3148 assert isinstance(function_name, str) 3149 3150 props = cg_context.interface.indexed_and_named_properties 3151 if "NotEnumerable" in props.named_getter.extended_attributes: 3152 return None, None 3153 3154 arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"] 3155 arg_names = ["info"] 3156 3157 func_decl, func_def = _make_interceptor_callback( 3158 cg_context, function_name, arg_decls, arg_names, cg_context.class_name, 3159 "NamedPropertyEnumerator") 3160 body = func_def.body 3161 3162 body.append( 3163 TextNode("""\ 3164// 3.9.6. [[OwnPropertyKeys]] 3165// https://heycam.github.io/webidl/#legacy-platform-object-ownpropertykeys 3166// step 3. If O supports named properties, then for each P of O's supported 3167// property names that is visible according to the named property 3168// visibility algorithm, append P to keys. 3169Vector<String> blink_property_names; 3170ExceptionState exception_state(${info}.GetIsolate(), 3171 ExceptionState::kEnumerationContext, 3172 "${interface.identifier}"); 3173${blink_receiver}->NamedPropertyEnumerator( 3174 blink_property_names, exception_state); 3175if (exception_state.HadException()) 3176 return; 3177bindings::V8SetReturnValue( 3178 ${info}, 3179 ToV8(blink_property_names, ${creation_context_object}, ${isolate})); 3180""")) 3181 3182 return func_decl, func_def 3183 3184 3185# ---------------------------------------------------------------------------- 3186# Callback functions of interceptors on named properties object 3187# ---------------------------------------------------------------------------- 3188 3189 3190def make_named_props_obj_indexed_getter_callback(cg_context, function_name): 3191 assert isinstance(cg_context, CodeGenContext) 3192 assert isinstance(function_name, str) 3193 3194 arg_decls = [ 3195 "uint32_t index", 3196 "const v8::PropertyCallbackInfo<v8::Value>& info", 3197 ] 3198 arg_names = ["index", "info"] 3199 3200 func_def = _make_interceptor_callback_def( 3201 cg_context, function_name, arg_decls, arg_names, None, 3202 "NamedPropertiesObject_IndexedPropertyGetter") 3203 body = func_def.body 3204 3205 body.append( 3206 TextNode("""\ 3207v8::Local<v8::String> property_name = 3208 V8AtomicString(${isolate}, AtomicString::Number(${index})); 3209NamedPropsObjNamedGetterCallback(property_name, ${info}); 3210""")) 3211 3212 return func_def 3213 3214 3215def make_named_props_obj_indexed_deleter_callback(cg_context, function_name): 3216 assert isinstance(cg_context, CodeGenContext) 3217 assert isinstance(function_name, str) 3218 3219 arg_decls = [ 3220 "uint32_t index", 3221 "const v8::PropertyCallbackInfo<v8::Boolean>& info", 3222 ] 3223 arg_names = ["index", "info"] 3224 3225 func_def = _make_interceptor_callback_def( 3226 cg_context, function_name, arg_decls, arg_names, None, 3227 "NamedPropertiesObject_IndexedPropertyDeleter") 3228 body = func_def.body 3229 3230 body.append( 3231 TextNode("""\ 3232bindings::V8SetReturnValue(${info}, false); 3233if (${info}.ShouldThrowOnError()) { 3234 ExceptionState exception_state(${info}.GetIsolate(), 3235 ExceptionState::kIndexedDeletionContext, 3236 "${interface.identifier}"); 3237 exception_state.ThrowTypeError("Named property deleter is not supported."); 3238} 3239""")) 3240 3241 return func_def 3242 3243 3244def make_named_props_obj_indexed_definer_callback(cg_context, function_name): 3245 assert isinstance(cg_context, CodeGenContext) 3246 assert isinstance(function_name, str) 3247 3248 arg_decls = [ 3249 "uint32_t index", 3250 "const v8::PropertyDescriptor& v8_property_desc", 3251 "const v8::PropertyCallbackInfo<v8::Value>& info", 3252 ] 3253 arg_names = ["index", "v8_property_desc", "info"] 3254 3255 func_def = _make_interceptor_callback_def( 3256 cg_context, function_name, arg_decls, arg_names, None, 3257 "NamedPropertiesObject_IndexedPropertyDefiner") 3258 body = func_def.body 3259 3260 body.append( 3261 TextNode("""\ 3262// 3.6.4.2. [[DefineOwnProperty]] 3263// https://heycam.github.io/webidl/#named-properties-object-defineownproperty 3264bindings::V8SetReturnValue(${info}, nullptr); 3265if (${info}.ShouldThrowOnError()) { 3266 ExceptionState exception_state(${info}.GetIsolate(), 3267 ExceptionState::kIndexedSetterContext, 3268 "${interface.identifier}"); 3269 exception_state.ThrowTypeError("Named property deleter is not supported."); 3270} 3271""")) 3272 3273 return func_def 3274 3275 3276def make_named_props_obj_indexed_descriptor_callback(cg_context, 3277 function_name): 3278 assert isinstance(cg_context, CodeGenContext) 3279 assert isinstance(function_name, str) 3280 3281 arg_decls = [ 3282 "uint32_t index", 3283 "const v8::PropertyCallbackInfo<v8::Value>& info", 3284 ] 3285 arg_names = ["index", "info"] 3286 3287 func_def = _make_interceptor_callback_def( 3288 cg_context, function_name, arg_decls, arg_names, None, 3289 "NamedPropertiesObject_IndexedPropertyDescriptor") 3290 body = func_def.body 3291 3292 body.append( 3293 TextNode("""\ 3294v8::Local<v8::String> property_name = 3295 V8AtomicString(${isolate}, AtomicString::Number(${index})); 3296NamedPropsObjNamedDescriptorCallback(property_name, ${info}); 3297""")) 3298 3299 return func_def 3300 3301 3302def make_named_props_obj_named_getter_callback(cg_context, function_name): 3303 assert isinstance(cg_context, CodeGenContext) 3304 assert isinstance(function_name, str) 3305 3306 arg_decls = [ 3307 "v8::Local<v8::Name> v8_property_name", 3308 "const v8::PropertyCallbackInfo<v8::Value>& info", 3309 ] 3310 arg_names = ["v8_property_name", "info"] 3311 3312 func_def = _make_interceptor_callback_def( 3313 cg_context, function_name, arg_decls, arg_names, None, 3314 "NamedPropertiesObject_NamedPropertyGetter") 3315 body = func_def.body 3316 3317 body.append( 3318 TextNode("""\ 3319// 3.6.4.1. [[GetOwnProperty]] 3320// https://heycam.github.io/webidl/#named-properties-object-getownproperty 3321// 3322// TODO(yukishiino): Update the following hard-coded call to an appropriate 3323// one. 3324V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info}); 3325""")) 3326 3327 return func_def 3328 3329 3330def make_named_props_obj_named_deleter_callback(cg_context, function_name): 3331 assert isinstance(cg_context, CodeGenContext) 3332 assert isinstance(function_name, str) 3333 3334 arg_decls = [ 3335 "v8::Local<v8::Name> v8_property_name", 3336 "const v8::PropertyCallbackInfo<v8::Boolean>& info", 3337 ] 3338 arg_names = ["v8_property_name", "info"] 3339 3340 func_def = _make_interceptor_callback_def( 3341 cg_context, function_name, arg_decls, arg_names, None, 3342 "NamedPropertiesObject_NamedPropertyDeleter") 3343 body = func_def.body 3344 3345 body.append( 3346 TextNode("""\ 3347// 3.6.4.3. [[Delete]] 3348// https://heycam.github.io/webidl/#named-properties-object-delete 3349bindings::V8SetReturnValue(${info}, false); 3350if (${info}.ShouldThrowOnError()) { 3351 ExceptionState exception_state(${info}.GetIsolate(), 3352 ExceptionState::kNamedDeletionContext, 3353 "${interface.identifier}"); 3354 exception_state.ThrowTypeError("Named property deleter is not supported."); 3355} 3356""")) 3357 3358 return func_def 3359 3360 3361def make_named_props_obj_named_definer_callback(cg_context, function_name): 3362 assert isinstance(cg_context, CodeGenContext) 3363 assert isinstance(function_name, str) 3364 3365 arg_decls = [ 3366 "v8::Local<v8::Name> v8_property_name", 3367 "const v8::PropertyDescriptor& v8_property_desc", 3368 "const v8::PropertyCallbackInfo<v8::Value>& info", 3369 ] 3370 arg_names = ["v8_property_name", "v8_property_desc", "info"] 3371 3372 func_def = _make_interceptor_callback_def( 3373 cg_context, function_name, arg_decls, arg_names, None, 3374 "NamedPropertiesObject_NamedPropertyDefiner") 3375 body = func_def.body 3376 3377 body.append( 3378 TextNode("""\ 3379// 3.6.4.2. [[DefineOwnProperty]] 3380// https://heycam.github.io/webidl/#named-properties-object-defineownproperty 3381bindings::V8SetReturnValue(${info}, nullptr); 3382if (${info}.ShouldThrowOnError()) { 3383 ExceptionState exception_state(${info}.GetIsolate(), 3384 ExceptionState::kNamedSetterContext, 3385 "${interface.identifier}"); 3386 exception_state.ThrowTypeError("Named property setter is not supported."); 3387} 3388""")) 3389 3390 return func_def 3391 3392 3393def make_named_props_obj_named_descriptor_callback(cg_context, function_name): 3394 assert isinstance(cg_context, CodeGenContext) 3395 assert isinstance(function_name, str) 3396 3397 arg_decls = [ 3398 "v8::Local<v8::Name> v8_property_name", 3399 "const v8::PropertyCallbackInfo<v8::Value>& info", 3400 ] 3401 arg_names = ["v8_property_name", "info"] 3402 3403 func_def = _make_interceptor_callback_def( 3404 cg_context, function_name, arg_decls, arg_names, None, 3405 "NamedPropertiesObject_NamedPropertyDescriptor") 3406 body = func_def.body 3407 3408 body.append( 3409 TextNode("""\ 3410// 3.6.4.1. [[GetOwnProperty]] 3411// https://heycam.github.io/webidl/#named-properties-object-getownproperty 3412// step 4. If the result of running the named property visibility algorithm 3413// with property name P and object object is true, then: 3414if (${v8_receiver}->GetRealNamedPropertyAttributesInPrototypeChain( 3415 ${current_context}, ${v8_property_name}).IsJust()) { 3416 return; // Do not intercept. Fallback to OrdinaryGetOwnProperty. 3417} 3418 3419// TODO(yukishiino): Update the following hard-coded call to an appropriate 3420// one. 3421V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info}); 3422v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get(); 3423if (v8_value->IsUndefined()) 3424 return; // Do not intercept. Fallback to OrdinaryGetOwnProperty. 3425 3426// step 4.7. If A implements an interface with the 3427// [LegacyUnenumerableNamedProperties] extended attribute, then set 3428// desc.[[Enumerable]] to false, otherwise set it to true. 3429// step 4.8. Set desc.[[Writable]] to true and desc.[[Configurable]] to 3430// true. 3431v8::PropertyDescriptor desc(v8_value, /*writable=*/true); 3432desc.set_enumerable(false); 3433desc.set_configurable(true); 3434bindings::V8SetReturnValue(${info}, desc); 3435""")) 3436 3437 return func_def 3438 3439 3440# ---------------------------------------------------------------------------- 3441# Callback functions of cross origin interceptors 3442# ---------------------------------------------------------------------------- 3443 3444 3445def make_cross_origin_access_check_callback(cg_context, function_name): 3446 assert isinstance(cg_context, CodeGenContext) 3447 assert isinstance(function_name, str) 3448 3449 func_def = CxxFuncDefNode( 3450 name=function_name, 3451 arg_decls=[ 3452 "v8::Local<v8::Context> accessing_context", 3453 "v8::Local<v8::Object> accessed_object", 3454 "v8::Local<v8::Value> unused_data", 3455 ], 3456 return_type="bool") 3457 func_def.set_base_template_vars(cg_context.template_bindings()) 3458 body = func_def.body 3459 body.add_template_var("accessing_context", "accessing_context") 3460 body.add_template_var("accessed_object", "accessed_object") 3461 bind_callback_local_vars(body, cg_context) 3462 3463 if cg_context.interface.identifier == "Window": 3464 blink_class = "DOMWindow" 3465 else: 3466 blink_class = blink_class_name(cg_context.interface) 3467 body.extend([ 3468 TextNode( 3469 _format( 3470 "{blink_class}* blink_accessed_object = " 3471 "${class_name}::ToWrappableUnsafe(${accessed_object});", 3472 blink_class=blink_class)), 3473 TextNode("return BindingSecurity::ShouldAllowAccessTo(" 3474 "ToLocalDOMWindow(${accessing_context}), " 3475 "blink_accessed_object, " 3476 "BindingSecurity::ErrorReportOption::kDoNotReport);"), 3477 ]) 3478 3479 return func_def 3480 3481 3482def make_cross_origin_indexed_getter_callback(cg_context, function_name): 3483 assert isinstance(cg_context, CodeGenContext) 3484 assert isinstance(function_name, str) 3485 3486 arg_decls = [ 3487 "uint32_t index", 3488 "const v8::PropertyCallbackInfo<v8::Value>& info", 3489 ] 3490 arg_names = ["index", "info"] 3491 3492 func_def = _make_interceptor_callback_def( 3493 cg_context, function_name, arg_decls, arg_names, None, 3494 "CrossOriginProperty_IndexedPropertyGetter") 3495 body = func_def.body 3496 3497 if cg_context.interface.identifier != "Window": 3498 body.append(TextNode("${throw_security_error}")) 3499 return func_def 3500 3501 bind_return_value(body, cg_context, overriding_args=["${index}"]) 3502 3503 body.extend([ 3504 TextNode("""\ 3505if (${index} >= ${blink_receiver}->length()) { 3506 ${throw_security_error} 3507 return; 3508} 3509"""), 3510 make_v8_set_return_value(cg_context), 3511 ]) 3512 3513 return func_def 3514 3515 3516def make_cross_origin_indexed_setter_callback(cg_context, function_name): 3517 assert isinstance(cg_context, CodeGenContext) 3518 assert isinstance(function_name, str) 3519 3520 arg_decls = [ 3521 "uint32_t index", 3522 "v8::Local<v8::Value> v8_property_value", 3523 "const v8::PropertyCallbackInfo<v8::Value>& info", 3524 ] 3525 arg_names = ["index", "v8_property_value", "info"] 3526 3527 func_def = _make_interceptor_callback_def( 3528 cg_context, function_name, arg_decls, arg_names, None, 3529 "CrossOriginProperty_IndexedPropertySetter") 3530 body = func_def.body 3531 3532 body.append(TextNode("${throw_security_error}")) 3533 3534 return func_def 3535 3536 3537def make_cross_origin_indexed_deleter_callback(cg_context, function_name): 3538 assert isinstance(cg_context, CodeGenContext) 3539 assert isinstance(function_name, str) 3540 3541 arg_decls = [ 3542 "uint32_t index", 3543 "const v8::PropertyCallbackInfo<v8::Boolean>& info", 3544 ] 3545 arg_names = ["index", "info"] 3546 3547 func_def = _make_interceptor_callback_def( 3548 cg_context, function_name, arg_decls, arg_names, None, 3549 "CrossOriginProperty_IndexedPropertyDeleter") 3550 body = func_def.body 3551 3552 body.append(TextNode("${throw_security_error}")) 3553 3554 return func_def 3555 3556 3557def make_cross_origin_indexed_definer_callback(cg_context, function_name): 3558 assert isinstance(cg_context, CodeGenContext) 3559 assert isinstance(function_name, str) 3560 3561 arg_decls = [ 3562 "uint32_t index", 3563 "const v8::PropertyDescriptor& v8_property_desc", 3564 "const v8::PropertyCallbackInfo<v8::Value>& info", 3565 ] 3566 arg_names = ["index", "v8_property_desc", "info"] 3567 3568 func_def = _make_interceptor_callback_def( 3569 cg_context, function_name, arg_decls, arg_names, None, 3570 "CrossOriginProperty_IndexedPropertyDefiner") 3571 body = func_def.body 3572 3573 body.append(TextNode("${throw_security_error}")) 3574 3575 return func_def 3576 3577 3578def make_cross_origin_indexed_descriptor_callback(cg_context, function_name): 3579 assert isinstance(cg_context, CodeGenContext) 3580 assert isinstance(function_name, str) 3581 3582 arg_decls = [ 3583 "uint32_t index", 3584 "const v8::PropertyCallbackInfo<v8::Value>& info", 3585 ] 3586 arg_names = ["index", "info"] 3587 3588 func_def = _make_interceptor_callback_def( 3589 cg_context, function_name, arg_decls, arg_names, None, 3590 "CrossOriginProperty_IndexedPropertyDescriptor") 3591 body = func_def.body 3592 3593 if cg_context.interface.identifier != "Window": 3594 body.append(TextNode("${throw_security_error}")) 3595 return func_def 3596 3597 body.append( 3598 TextNode("""\ 3599CrossOriginIndexedGetterCallback(${index}, ${info}); 3600v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get(); 3601if (v8_value->IsUndefined()) { 3602 // Must have already thrown a SecurityError. 3603 return; 3604} 3605 3606v8::PropertyDescriptor desc(v8_value, /*writable=*/false); 3607desc.set_enumerable(true); 3608desc.set_configurable(true); 3609bindings::V8SetReturnValue(${info}, desc); 3610""")) 3611 3612 return func_def 3613 3614 3615def make_cross_origin_indexed_enumerator_callback(cg_context, function_name): 3616 assert isinstance(cg_context, CodeGenContext) 3617 assert isinstance(function_name, str) 3618 3619 arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"] 3620 arg_names = ["info"] 3621 3622 func_def = _make_interceptor_callback_def( 3623 cg_context, function_name, arg_decls, arg_names, None, 3624 "CrossOriginProperty_IndexedPropertyEnumerator") 3625 body = func_def.body 3626 3627 if cg_context.interface.identifier != "Window": 3628 return func_def 3629 3630 body.append( 3631 TextNode("""\ 3632uint32_t length = ${blink_receiver}->length(); 3633v8::Local<v8::Array> array = 3634 bindings::EnumerateIndexedProperties(${isolate}, length); 3635bindings::V8SetReturnValue(${info}, array); 3636""")) 3637 3638 return func_def 3639 3640 3641def make_cross_origin_named_getter_callback(cg_context, function_name): 3642 assert isinstance(cg_context, CodeGenContext) 3643 assert isinstance(function_name, str) 3644 3645 arg_decls = [ 3646 "v8::Local<v8::Name> v8_property_name", 3647 "const v8::PropertyCallbackInfo<v8::Value>& info", 3648 ] 3649 arg_names = ["v8_property_name", "info"] 3650 3651 func_def = _make_interceptor_callback_def( 3652 cg_context, function_name, arg_decls, arg_names, None, 3653 "CrossOriginProperty_NamedPropertyGetter") 3654 body = func_def.body 3655 3656 string_case_body = [] 3657 string_case_body.append( 3658 TextNode("""\ 3659for (const auto& attribute : kCrossOriginAttributeTable) { 3660 if (${blink_property_name} != attribute.name) 3661 continue; 3662 if (UNLIKELY(!attribute.get_value)) { 3663 ${throw_security_error} 3664 return; 3665 } 3666 attribute.get_value(${v8_property_name}, ${info}); 3667 return; 3668} 3669for (const auto& operation : kCrossOriginOperationTable) { 3670 if (${blink_property_name} != operation.name) 3671 continue; 3672 v8::Local<v8::Function> function; 3673 if (bindings::GetCrossOriginFunction( 3674 ${info}.GetIsolate(), operation.callback, operation.func_length, 3675 ${class_name}::GetWrapperTypeInfo()) 3676 .ToLocal(&function)) { 3677 bindings::V8SetReturnValue(${info}, function); 3678 } 3679 return; 3680} 3681""")) 3682 if cg_context.interface.identifier == "Window": 3683 string_case_body.append( 3684 TextNode("""\ 3685// Window object's document-tree child browsing context name property set 3686// 3687// TODO(yukishiino): Update the following hard-coded call to an appropriate 3688// one. 3689V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info}); 3690if (!${info}.GetReturnValue().Get()->IsUndefined()) 3691 return; 3692""")) 3693 3694 body.extend([ 3695 CxxLikelyIfNode( 3696 cond="${v8_property_name}->IsString()", body=string_case_body), 3697 EmptyNode(), 3698 TextNode("""\ 3699// 7.2.3.2 CrossOriginPropertyFallback ( P ) 3700// https://html.spec.whatwg.org/C/#crossoriginpropertyfallback-(-p-) 3701if (bindings::IsSupportedInCrossOriginPropertyFallback( 3702 ${info}.GetIsolate(), ${v8_property_name})) { 3703 return ${info}.GetReturnValue().SetUndefined(); 3704} 3705${throw_security_error} 3706"""), 3707 ]) 3708 3709 return func_def 3710 3711 3712def make_cross_origin_named_setter_callback(cg_context, function_name): 3713 assert isinstance(cg_context, CodeGenContext) 3714 assert isinstance(function_name, str) 3715 3716 arg_decls = [ 3717 "v8::Local<v8::Name> v8_property_name", 3718 "v8::Local<v8::Value> v8_property_value", 3719 "const v8::PropertyCallbackInfo<v8::Value>& info", 3720 ] 3721 arg_names = ["v8_property_name", "v8_property_value", "info"] 3722 3723 func_def = _make_interceptor_callback_def( 3724 cg_context, function_name, arg_decls, arg_names, None, 3725 "CrossOriginProperty_NamedPropertySetter") 3726 body = func_def.body 3727 3728 string_case_body = [] 3729 string_case_body.append( 3730 TextNode("""\ 3731for (const auto& attribute : kCrossOriginAttributeTable) { 3732 if (${blink_property_name} == attribute.name && attribute.set_value) { 3733 attribute.set_value(${v8_property_name}, ${v8_property_value}, ${info}); 3734 return; 3735 } 3736} 3737""")) 3738 3739 body.extend([ 3740 CxxLikelyIfNode( 3741 cond="${v8_property_name}->IsString()", body=string_case_body), 3742 EmptyNode(), 3743 TextNode("${throw_security_error}"), 3744 ]) 3745 3746 return func_def 3747 3748 3749def make_cross_origin_named_deleter_callback(cg_context, function_name): 3750 assert isinstance(cg_context, CodeGenContext) 3751 assert isinstance(function_name, str) 3752 3753 arg_decls = [ 3754 "v8::Local<v8::Name> v8_property_name", 3755 "const v8::PropertyCallbackInfo<v8::Boolean>& info", 3756 ] 3757 arg_names = ["v8_property_name", "info"] 3758 3759 func_def = _make_interceptor_callback_def( 3760 cg_context, function_name, arg_decls, arg_names, None, 3761 "CrossOriginProperty_NamedPropertyDeleter") 3762 body = func_def.body 3763 3764 body.append(TextNode("${throw_security_error}")) 3765 3766 return func_def 3767 3768 3769def make_cross_origin_named_definer_callback(cg_context, function_name): 3770 assert isinstance(cg_context, CodeGenContext) 3771 assert isinstance(function_name, str) 3772 3773 arg_decls = [ 3774 "v8::Local<v8::Name> v8_property_name", 3775 "const v8::PropertyDescriptor& v8_property_desc", 3776 "const v8::PropertyCallbackInfo<v8::Value>& info", 3777 ] 3778 arg_names = ["v8_property_name", "v8_property_desc", "info"] 3779 3780 func_def = _make_interceptor_callback_def( 3781 cg_context, function_name, arg_decls, arg_names, None, 3782 "CrossOriginProperty_NamedPropertyDefiner") 3783 body = func_def.body 3784 3785 body.append(TextNode("${throw_security_error}")) 3786 3787 return func_def 3788 3789 3790def make_cross_origin_named_descriptor_callback(cg_context, function_name): 3791 assert isinstance(cg_context, CodeGenContext) 3792 assert isinstance(function_name, str) 3793 3794 arg_decls = [ 3795 "v8::Local<v8::Name> v8_property_name", 3796 "const v8::PropertyCallbackInfo<v8::Value>& info", 3797 ] 3798 arg_names = ["v8_property_name", "info"] 3799 3800 func_def = _make_interceptor_callback_def( 3801 cg_context, function_name, arg_decls, arg_names, None, 3802 "CrossOriginProperty_NamedPropertyDescriptor") 3803 body = func_def.body 3804 3805 string_case_body = [] 3806 string_case_body.append( 3807 TextNode("""\ 3808// 7.2.3.4 CrossOriginGetOwnPropertyHelper ( O, P ) 3809// https://html.spec.whatwg.org/C/#crossorigingetownpropertyhelper-(-o,-p-) 3810for (const auto& attribute : kCrossOriginAttributeTable) { 3811 if (${blink_property_name} != attribute.name) 3812 continue; 3813 v8::Local<v8::Value> get; 3814 v8::Local<v8::Value> set; 3815 if (!bindings::GetCrossOriginFunctionOrUndefined( 3816 ${info}.GetIsolate(), attribute.get_callback, 0, 3817 ${class_name}::GetWrapperTypeInfo()) 3818 .ToLocal(&get) || 3819 !bindings::GetCrossOriginFunctionOrUndefined( 3820 ${info}.GetIsolate(), attribute.set_callback, 1, 3821 ${class_name}::GetWrapperTypeInfo()) 3822 .ToLocal(&set)) { 3823 return; 3824 } 3825 v8::PropertyDescriptor desc(get, set); 3826 desc.set_enumerable(false); 3827 desc.set_configurable(true); 3828 bindings::V8SetReturnValue(${info}, desc); 3829 return; 3830} 3831for (const auto& operation : kCrossOriginOperationTable) { 3832 if (${blink_property_name} != operation.name) 3833 continue; 3834 v8::Local<v8::Function> function; 3835 if (!bindings::GetCrossOriginFunction( 3836 ${info}.GetIsolate(), operation.callback, operation.func_length, 3837 ${class_name}::GetWrapperTypeInfo()) 3838 .ToLocal(&function)) { 3839 return; 3840 } 3841 v8::PropertyDescriptor desc(function, /*writable=*/false); 3842 desc.set_enumerable(false); 3843 desc.set_configurable(true); 3844 bindings::V8SetReturnValue(${info}, desc); 3845 return; 3846} 3847""")) 3848 if cg_context.interface.identifier == "Window": 3849 string_case_body.append( 3850 TextNode("""\ 3851// Window object's document-tree child browsing context name property set 3852// 3853// TODO(yukishiino): Update the following hard-coded call to an appropriate 3854// one. 3855V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info}); 3856if (!${info}.GetReturnValue().Get()->IsUndefined()) { 3857 v8::PropertyDescriptor desc(${info}.GetReturnValue().Get(), 3858 /*writable=*/false); 3859 desc.set_enumerable(false); 3860 desc.set_configurable(true); 3861 bindings::V8SetReturnValue(${info}, desc); 3862 return; 3863} 3864""")) 3865 3866 body.extend([ 3867 CxxLikelyIfNode( 3868 cond="${v8_property_name}->IsString()", body=string_case_body), 3869 EmptyNode(), 3870 TextNode("""\ 3871// 7.2.3.2 CrossOriginPropertyFallback ( P ) 3872// https://html.spec.whatwg.org/C/#crossoriginpropertyfallback-(-p-) 3873if (bindings::IsSupportedInCrossOriginPropertyFallback( 3874 ${info}.GetIsolate(), ${v8_property_name})) { 3875 v8::PropertyDescriptor desc(v8::Undefined(${info}.GetIsolate()), 3876 /*writable=*/false); 3877 desc.set_enumerable(false); 3878 desc.set_configurable(true); 3879 bindings::V8SetReturnValue(${info}, desc); 3880 return; 3881} 3882${throw_security_error} 3883"""), 3884 ]) 3885 3886 return func_def 3887 3888 3889def make_cross_origin_named_query_callback(cg_context, function_name): 3890 assert isinstance(cg_context, CodeGenContext) 3891 assert isinstance(function_name, str) 3892 3893 arg_decls = [ 3894 "v8::Local<v8::Name> v8_property_name", 3895 "const v8::PropertyCallbackInfo<v8::Integer>& info", 3896 ] 3897 arg_names = ["v8_property_name", "info"] 3898 3899 func_def = _make_interceptor_callback_def( 3900 cg_context, function_name, arg_decls, arg_names, None, 3901 "CrossOriginProperty_NamedPropertyQuery") 3902 body = func_def.body 3903 3904 string_case_body = [] 3905 string_case_body.append( 3906 TextNode("""\ 3907// 7.2.3.4 CrossOriginGetOwnPropertyHelper ( O, P ) 3908// https://html.spec.whatwg.org/C/#crossorigingetownpropertyhelper-(-o,-p-) 3909for (const auto& attribute : kCrossOriginAttributeTable) { 3910 if (${blink_property_name} != attribute.name) 3911 continue; 3912 int32_t v8_property_attribute = v8::DontEnum; 3913 if (!attribute.set_callback) 3914 v8_property_attribute |= v8::ReadOnly; 3915 bindings::V8SetReturnValue(${info}, v8_property_attribute); 3916 return; 3917} 3918for (const auto& operation : kCrossOriginOperationTable) { 3919 if (${blink_property_name} != operation.name) 3920 continue; 3921 int32_t v8_property_attribute = v8::DontEnum | v8::ReadOnly; 3922 bindings::V8SetReturnValue(${info}, v8_property_attribute); 3923 return; 3924} 3925""")) 3926 3927 body.extend([ 3928 CxxLikelyIfNode( 3929 cond="${v8_property_name}->IsString()", body=string_case_body), 3930 EmptyNode(), 3931 TextNode("""\ 3932// 7.2.3.2 CrossOriginPropertyFallback ( P ) 3933// https://html.spec.whatwg.org/C/#crossoriginpropertyfallback-(-p-) 3934if (bindings::IsSupportedInCrossOriginPropertyFallback( 3935 ${info}.GetIsolate(), ${v8_property_name})) { 3936 int32_t v8_property_attribute = v8::DontEnum | v8::ReadOnly; 3937 bindings::V8SetReturnValue(${info}, v8_property_attribute); 3938 return; 3939} 3940"""), 3941 ]) 3942 3943 return func_def 3944 3945 3946def make_cross_origin_named_enumerator_callback(cg_context, function_name): 3947 assert isinstance(cg_context, CodeGenContext) 3948 assert isinstance(function_name, str) 3949 3950 arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"] 3951 arg_names = ["info"] 3952 3953 func_def = _make_interceptor_callback_def( 3954 cg_context, function_name, arg_decls, arg_names, None, 3955 "CrossOriginProperty_NamedPropertyEnumerator") 3956 body = func_def.body 3957 3958 body.append( 3959 TextNode("""\ 3960bindings::V8SetReturnValue( 3961 ${info}, 3962 bindings::EnumerateCrossOriginProperties( 3963 ${isolate}, 3964 kCrossOriginAttributeTable, 3965 kCrossOriginOperationTable)); 3966""")) 3967 3968 return func_def 3969 3970 3971# ---------------------------------------------------------------------------- 3972# Callback functions of same origin interceptors 3973# ---------------------------------------------------------------------------- 3974 3975 3976def make_same_origin_indexed_getter_callback(cg_context, function_name): 3977 assert isinstance(cg_context, CodeGenContext) 3978 assert isinstance(function_name, str) 3979 3980 arg_decls = [ 3981 "uint32_t index", 3982 "const v8::PropertyCallbackInfo<v8::Value>& info", 3983 ] 3984 arg_names = ["index", "info"] 3985 3986 func_def = _make_interceptor_callback_def( 3987 cg_context, function_name, arg_decls, arg_names, None, 3988 "SameOriginProperty_IndexedPropertyGetter") 3989 body = func_def.body 3990 3991 bind_return_value(body, cg_context, overriding_args=["${index}"]) 3992 3993 body.extend([ 3994 TextNode("""\ 3995if (${index} >= ${blink_receiver}->length()) { 3996 return; 3997} 3998"""), 3999 make_v8_set_return_value(cg_context), 4000 ]) 4001 4002 return func_def 4003 4004 4005def make_same_origin_indexed_setter_callback(cg_context, function_name): 4006 assert isinstance(cg_context, CodeGenContext) 4007 assert isinstance(function_name, str) 4008 4009 arg_decls = [ 4010 "uint32_t index", 4011 "v8::Local<v8::Value> v8_property_value", 4012 "const v8::PropertyCallbackInfo<v8::Value>& info", 4013 ] 4014 arg_names = ["index", "v8_property_value", "info"] 4015 4016 func_def = _make_interceptor_callback_def( 4017 cg_context, function_name, arg_decls, arg_names, None, 4018 "SameOriginProperty_IndexedPropertySetter") 4019 body = func_def.body 4020 4021 body.append( 4022 TextNode("""\ 4023bindings::V8SetReturnValue(${info}, nullptr); 4024if (${info}.ShouldThrowOnError()) { 4025 ExceptionState exception_state(${info}.GetIsolate(), 4026 ExceptionState::kIndexedSetterContext, 4027 "${interface.identifier}"); 4028 exception_state.ThrowTypeError( 4029 "Indexed property setter is not supported."); 4030} 4031""")) 4032 4033 return func_def 4034 4035 4036def make_same_origin_indexed_deleter_callback(cg_context, function_name): 4037 assert isinstance(cg_context, CodeGenContext) 4038 assert isinstance(function_name, str) 4039 4040 arg_decls = [ 4041 "uint32_t index", 4042 "const v8::PropertyCallbackInfo<v8::Boolean>& info", 4043 ] 4044 arg_names = ["index", "info"] 4045 4046 func_def = _make_interceptor_callback_def( 4047 cg_context, function_name, arg_decls, arg_names, None, 4048 "SameOriginProperty_IndexedPropertyDeleter") 4049 body = func_def.body 4050 4051 body.append( 4052 TextNode("""\ 4053// 7.4.9 [[Delete]] ( P ) 4054// https://html.spec.whatwg.org/C/#windowproxy-delete 4055const bool is_supported = ${index} < ${blink_receiver}->length(); 4056bindings::V8SetReturnValue(${info}, !is_supported); 4057if (is_supported and ${info}.ShouldThrowOnError()) { 4058 ExceptionState exception_state(${info}.GetIsolate(), 4059 ExceptionState::kIndexedDeletionContext, 4060 "${interface.identifier}"); 4061 exception_state.ThrowTypeError("Index property deleter is not supported."); 4062} 4063""")) 4064 4065 return func_def 4066 4067 4068def make_same_origin_indexed_definer_callback(cg_context, function_name): 4069 assert isinstance(cg_context, CodeGenContext) 4070 assert isinstance(function_name, str) 4071 4072 arg_decls = [ 4073 "uint32_t index", 4074 "const v8::PropertyDescriptor& v8_property_desc", 4075 "const v8::PropertyCallbackInfo<v8::Value>& info", 4076 ] 4077 arg_names = ["index", "v8_property_desc", "info"] 4078 4079 func_def = _make_interceptor_callback_def( 4080 cg_context, function_name, arg_decls, arg_names, None, 4081 "SameOriginProperty_IndexedPropertyDefiner") 4082 body = func_def.body 4083 4084 body.append( 4085 TextNode("""\ 4086// 7.4.6 [[DefineOwnProperty]] ( P, Desc ) 4087// https://html.spec.whatwg.org/C/#windowproxy-defineownproperty 4088bindings::V8SetReturnValue(${info}, nullptr); 4089if (${info}.ShouldThrowOnError()) { 4090 ExceptionState exception_state(${info}.GetIsolate(), 4091 ExceptionState::kIndexedSetterContext, 4092 "${interface.identifier}"); 4093 exception_state.ThrowTypeError("Index property setter is not supported."); 4094} 4095""")) 4096 4097 return func_def 4098 4099 4100def make_same_origin_indexed_descriptor_callback(cg_context, function_name): 4101 assert isinstance(cg_context, CodeGenContext) 4102 assert isinstance(function_name, str) 4103 4104 arg_decls = [ 4105 "uint32_t index", 4106 "const v8::PropertyCallbackInfo<v8::Value>& info", 4107 ] 4108 arg_names = ["index", "info"] 4109 4110 func_def = _make_interceptor_callback_def( 4111 cg_context, function_name, arg_decls, arg_names, None, 4112 "SameOriginProperty_IndexedPropertyDescriptor") 4113 body = func_def.body 4114 4115 body.append( 4116 TextNode("""\ 4117// 7.4.5 [[GetOwnProperty]] ( P ) 4118// https://html.spec.whatwg.org/C/#windowproxy-getownproperty 4119SameOriginIndexedGetterCallback(${index}, ${info}); 4120v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get(); 4121if (v8_value->IsUndefined()) { 4122 return; // Do not intercept. 4123} 4124 4125v8::PropertyDescriptor desc(v8_value, /*writable=*/false); 4126desc.set_enumerable(true); 4127desc.set_configurable(true); 4128bindings::V8SetReturnValue(${info}, desc); 4129""")) 4130 4131 return func_def 4132 4133 4134def make_same_origin_indexed_enumerator_callback(cg_context, function_name): 4135 assert isinstance(cg_context, CodeGenContext) 4136 assert isinstance(function_name, str) 4137 4138 arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"] 4139 arg_names = ["info"] 4140 4141 func_def = _make_interceptor_callback_def( 4142 cg_context, function_name, arg_decls, arg_names, None, 4143 "SameOriginProperty_IndexedPropertyEnumerator") 4144 body = func_def.body 4145 4146 body.append( 4147 TextNode("""\ 4148uint32_t length = ${blink_receiver}->length(); 4149v8::Local<v8::Array> array = 4150 bindings::EnumerateIndexedProperties(${isolate}, length); 4151bindings::V8SetReturnValue(${info}, array); 4152""")) 4153 4154 return func_def 4155 4156 4157# ---------------------------------------------------------------------------- 4158# Installer functions 4159# ---------------------------------------------------------------------------- 4160 4161# FN = function name 4162FN_INSTALL_INTERFACE_TEMPLATE = name_style.func("InstallInterfaceTemplate") 4163FN_INSTALL_UNCONDITIONAL_PROPS = name_style.func( 4164 "InstallUnconditionalProperties") 4165FN_INSTALL_CONTEXT_INDEPENDENT_PROPS = name_style.func( 4166 "InstallContextIndependentProperties") 4167FN_INSTALL_CONTEXT_DEPENDENT_PROPS = name_style.func( 4168 "InstallContextDependentProperties") 4169 4170# TP = trampoline name 4171TP_INSTALL_INTERFACE_TEMPLATE = name_style.member_var( 4172 "install_interface_template_func") 4173TP_INSTALL_UNCONDITIONAL_PROPS = name_style.member_var( 4174 "install_unconditional_props_func") 4175TP_INSTALL_CONTEXT_INDEPENDENT_PROPS = name_style.member_var( 4176 "install_context_independent_props_func") 4177TP_INSTALL_CONTEXT_DEPENDENT_PROPS = name_style.member_var( 4178 "install_context_dependent_props_func") 4179 4180 4181def bind_installer_local_vars(code_node, cg_context): 4182 assert isinstance(code_node, SymbolScopeNode) 4183 assert isinstance(cg_context, CodeGenContext) 4184 4185 S = SymbolNode 4186 4187 local_vars = [] 4188 4189 local_vars.extend([ 4190 S("is_in_secure_context", 4191 ("const bool ${is_in_secure_context} = " 4192 "${execution_context}->IsSecureContext();")), 4193 S("isolate", "v8::Isolate* ${isolate} = ${v8_context}->GetIsolate();"), 4194 S("script_state", 4195 "ScriptState* ${script_state} = ScriptState::From(${v8_context});"), 4196 S("wrapper_type_info", 4197 ("const WrapperTypeInfo* const ${wrapper_type_info} = " 4198 "${class_name}::GetWrapperTypeInfo();")), 4199 ]) 4200 4201 if cg_context.interface: 4202 local_vars.extend([ 4203 S("interface_function_template", 4204 ("v8::Local<v8::FunctionTemplate> " 4205 "${interface_function_template} = " 4206 "${interface_template}.As<v8::FunctionTemplate>();")), 4207 S("instance_object_template", 4208 ("v8::Local<v8::ObjectTemplate> ${instance_object_template} = " 4209 "${interface_function_template}->InstanceTemplate();")), 4210 S("instance_template", 4211 ("v8::Local<v8::Template> ${instance_template} = " 4212 "${instance_object_template};")), 4213 S("prototype_object_template", 4214 ("v8::Local<v8::ObjectTemplate> ${prototype_object_template} = " 4215 "${interface_function_template}->PrototypeTemplate();")), 4216 S("prototype_template", 4217 ("v8::Local<v8::Template> ${prototype_template} = " 4218 "${prototype_object_template};")), 4219 S("signature", ("v8::Local<v8::Signature> ${signature} = " 4220 "v8::Signature::New(${isolate}, " 4221 "${interface_function_template});")), 4222 ]) 4223 elif cg_context.namespace: 4224 local_vars.extend([ 4225 S("namespace_object_template", 4226 ("v8::Local<v8::ObjectTemplate> " 4227 "${namespace_object_template} = " 4228 "${interface_template}.As<v8::ObjectTemplate>();")), 4229 S("instance_template", 4230 "v8::Local<v8::Template> ${instance_template};"), 4231 S("prototype_template", 4232 "v8::Local<v8::Template> ${prototype_template};"), 4233 S("signature", "v8::Local<v8::Signature> ${signature};"), 4234 ]) 4235 elif cg_context.callback_interface: 4236 local_vars.extend([ 4237 S("interface_function_template", 4238 ("v8::Local<v8::FunctionTemplate> " 4239 "${interface_function_template} = " 4240 "${interface_template}.As<v8::FunctionTemplate>();")), 4241 S("instance_template", 4242 "v8::Local<v8::Template> ${instance_template};"), 4243 S("prototype_template", 4244 "v8::Local<v8::Template> ${prototype_template};"), 4245 S("signature", "v8::Local<v8::Signature> ${signature};"), 4246 ]) 4247 4248 # context_feature_settings 4249 node = S("context_feature_settings", 4250 ("const ContextFeatureSettings* ${context_feature_settings} = " 4251 "ContextFeatureSettings::From(" 4252 "${execution_context}, " 4253 "ContextFeatureSettings::CreationMode::kDontCreateIfNotExists" 4254 ");")) 4255 node.accumulate( 4256 CodeGenAccumulator.require_include_headers([ 4257 "third_party/blink/renderer/core/context_features/context_feature_settings.h" 4258 ])) 4259 local_vars.append(node) 4260 4261 # execution_context 4262 node = S("execution_context", ("ExecutionContext* ${execution_context} = " 4263 "ExecutionContext::From(${script_state});")) 4264 node.accumulate( 4265 CodeGenAccumulator.require_include_headers([ 4266 "third_party/blink/renderer/core/execution_context/execution_context.h" 4267 ])) 4268 local_vars.append(node) 4269 4270 # parent_interface_template 4271 pattern = ( 4272 "v8::Local<v8::FunctionTemplate> ${parent_interface_template}{_1};") 4273 interface = cg_context.interface 4274 if not interface: 4275 _1 = "" 4276 elif (interface and "Global" in interface.extended_attributes 4277 and interface.indexed_and_named_properties 4278 and interface.indexed_and_named_properties.has_named_properties): 4279 # https://heycam.github.io/webidl/#named-properties-object 4280 _1 = " = ${npo_interface_template}" # npo = named properties object 4281 elif interface.inherited: 4282 _1 = (" = ${wrapper_type_info}->parent_class" 4283 "->GetV8ClassTemplate(${isolate}, ${world})" 4284 ".As<v8::FunctionTemplate>()") 4285 else: 4286 _1 = "" 4287 local_vars.append(S("parent_interface_template", _format(pattern, _1=_1))) 4288 4289 # npo_interface_template 4290 # npo = named properties object 4291 text = """\ 4292// Named properties object 4293v8::Local<v8::FunctionTemplate> ${npo_interface_template} = 4294 v8::FunctionTemplate::New(${isolate}); 4295v8::Local<v8::ObjectTemplate> ${npo_prototype_template} = 4296 ${npo_interface_template}->PrototypeTemplate(); 4297${npo_interface_template}->Inherit( 4298 ${wrapper_type_info}->parent_class 4299 ->GetV8ClassTemplate(${isolate}, ${world}).As<v8::FunctionTemplate>()); 4300${npo_prototype_template}->SetImmutableProto(); 4301${npo_prototype_template}->Set( 4302 v8::Symbol::GetToStringTag(${isolate}), 4303 V8AtomicString(${isolate}, "${interface.identifier}Properties"), 4304 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)); 4305// Make the named properties object look like the global object. Note that 4306// the named properties object is _not_ a prototype object, plus, we'd like 4307// the named properties object to behave just like the global object (= the 4308// wrapper object of the global object) from the point of view of named 4309// properties. 4310// https://heycam.github.io/webidl/#named-properties-object 4311${npo_prototype_template}->SetInternalFieldCount( 4312 kV8DefaultWrapperInternalFieldCount); 4313""" 4314 local_vars.append(S("npo_interface_template", text)) 4315 local_vars.append( 4316 S("npo_prototype_template", 4317 "<% npo_interface_template.request_symbol_definition() %>")) 4318 4319 # Arguments have priority over local vars. 4320 template_vars = code_node.template_vars 4321 for symbol_node in local_vars: 4322 if symbol_node.name not in template_vars: 4323 code_node.register_code_symbol(symbol_node) 4324 4325 4326def _make_property_entry_cross_origin_check(property_, 4327 is_get=False, 4328 is_set=False): 4329 constants = { 4330 False: "unsigned(IDLMemberInstaller::FlagCrossOriginCheck::kCheck)", 4331 True: 4332 "unsigned(IDLMemberInstaller::FlagCrossOriginCheck::kDoNotCheck)", 4333 } 4334 if property_.is_static: 4335 return constants[True] 4336 if "CrossOrigin" not in property_.extended_attributes: 4337 return constants[False] 4338 values = property_.extended_attributes.values_of("CrossOrigin") 4339 if is_get: 4340 return constants[not values or "Getter" in values] 4341 elif is_set: 4342 return constants["Setter" in values] 4343 else: 4344 return constants[True] 4345 4346 4347def _make_property_entry_location(property_): 4348 if hasattr(property_, "is_static") and property_.is_static: 4349 return "unsigned(IDLMemberInstaller::FlagLocation::kInterface)" 4350 if "Global" in property_.owner.extended_attributes: 4351 return "unsigned(IDLMemberInstaller::FlagLocation::kInstance)" 4352 if "LegacyUnforgeable" in property_.extended_attributes: 4353 return "unsigned(IDLMemberInstaller::FlagLocation::kInstance)" 4354 return "unsigned(IDLMemberInstaller::FlagLocation::kPrototype)" 4355 4356 4357def _make_property_entry_receiver_check(property_): 4358 if ("LegacyLenientThis" in property_.extended_attributes 4359 or property_.is_static 4360 or (isinstance(property_, web_idl.Attribute) 4361 and property_.idl_type.unwrap().is_promise) 4362 or (isinstance(property_, web_idl.OverloadGroup) 4363 and property_[0].return_type.unwrap().is_promise)): 4364 return "unsigned(IDLMemberInstaller::FlagReceiverCheck::kDoNotCheck)" 4365 else: 4366 return "unsigned(IDLMemberInstaller::FlagReceiverCheck::kCheck)" 4367 4368 4369def _make_property_entry_v8_c_function(entry): 4370 if entry.no_alloc_direct_callback_name is None: 4371 return None 4372 return "v8::CFunction::MakeWithFallbackSupport({})".format( 4373 entry.no_alloc_direct_callback_name) 4374 4375 4376def _make_property_entry_v8_cached_accessor(property_): 4377 return "unsigned(V8PrivateProperty::CachedAccessor::{})".format( 4378 property_.extended_attributes.value_of("CachedAccessor") or "kNone") 4379 4380 4381def _make_property_entry_v8_property_attribute(property_): 4382 values = [] 4383 if "NotEnumerable" in property_.extended_attributes: 4384 values.append("v8::DontEnum") 4385 if "LegacyUnforgeable" in property_.extended_attributes: 4386 if not isinstance(property_, web_idl.Attribute): 4387 values.append("v8::ReadOnly") 4388 values.append("v8::DontDelete") 4389 if not values: 4390 values.append("v8::None") 4391 if len(values) == 1: 4392 return "unsigned({})".format(values[0]) 4393 else: 4394 return "unsigned({})".format(" | ".join(values)) 4395 4396 4397def _make_property_entry_v8_side_effect(property_): 4398 if property_.extended_attributes.value_of("Affects") == "Nothing": 4399 return "unsigned(v8::SideEffectType::kHasNoSideEffect)" 4400 else: 4401 return "unsigned(v8::SideEffectType::kHasSideEffect)" 4402 4403 4404def _make_property_entry_world(world): 4405 if world == CodeGenContext.MAIN_WORLD: 4406 return "unsigned(IDLMemberInstaller::FlagWorld::kMainWorld)" 4407 if world == CodeGenContext.NON_MAIN_WORLDS: 4408 return "unsigned(IDLMemberInstaller::FlagWorld::kNonMainWorlds)" 4409 if world == CodeGenContext.ALL_WORLDS: 4410 return "unsigned(IDLMemberInstaller::FlagWorld::kAllWorlds)" 4411 assert False 4412 4413 4414def _make_attribute_registration_table(table_name, attribute_entries): 4415 assert isinstance(table_name, str) 4416 assert isinstance(attribute_entries, (list, tuple)) 4417 assert all( 4418 isinstance(entry, _PropEntryAttribute) for entry in attribute_entries) 4419 4420 T = TextNode 4421 4422 entry_nodes = [] 4423 for entry in attribute_entries: 4424 pattern = ("{{" 4425 "\"{property_name}\", " 4426 "{attribute_get_callback}, " 4427 "{attribute_set_callback}, " 4428 "{v8_property_attribute}, " 4429 "{location}, " 4430 "{world}, " 4431 "{receiver_check}, " 4432 "{cross_origin_check_for_get}, " 4433 "{cross_origin_check_for_set}, " 4434 "{v8_side_effect}, " 4435 "{v8_cached_accessor}" 4436 "}},") 4437 text = _format( 4438 pattern, 4439 property_name=entry.property_.identifier, 4440 attribute_get_callback=entry.attr_get_callback_name, 4441 attribute_set_callback=(entry.attr_set_callback_name or "nullptr"), 4442 v8_property_attribute=_make_property_entry_v8_property_attribute( 4443 entry.property_), 4444 location=_make_property_entry_location(entry.property_), 4445 world=_make_property_entry_world(entry.world), 4446 receiver_check=_make_property_entry_receiver_check( 4447 entry.property_), 4448 cross_origin_check_for_get=( 4449 _make_property_entry_cross_origin_check(entry.property_, 4450 is_get=True)), 4451 cross_origin_check_for_set=( 4452 _make_property_entry_cross_origin_check(entry.property_, 4453 is_set=True)), 4454 v8_side_effect=_make_property_entry_v8_side_effect( 4455 entry.property_), 4456 v8_cached_accessor=_make_property_entry_v8_cached_accessor( 4457 entry.property_)) 4458 entry_nodes.append(T(text)) 4459 4460 return ListNode([ 4461 T("static const IDLMemberInstaller::AttributeConfig " + table_name + 4462 "[] = {"), 4463 ListNode(entry_nodes), 4464 T("};"), 4465 ]) 4466 4467 4468def _make_constant_callback_registration_table(table_name, constant_entries): 4469 assert isinstance(table_name, str) 4470 assert isinstance(constant_entries, (list, tuple)) 4471 assert all( 4472 isinstance(entry, _PropEntryConstant) 4473 and isinstance(entry.const_callback_name, str) 4474 for entry in constant_entries) 4475 4476 T = TextNode 4477 4478 entry_nodes = [] 4479 for entry in constant_entries: 4480 pattern = ("{{" "\"{property_name}\", " "{constant_callback}" "}},") 4481 text = _format( 4482 pattern, 4483 property_name=entry.property_.identifier, 4484 constant_callback=entry.const_callback_name) 4485 entry_nodes.append(T(text)) 4486 4487 return ListNode([ 4488 T("static const IDLMemberInstaller::ConstantCallbackConfig " + 4489 table_name + "[] = {"), 4490 ListNode(entry_nodes), 4491 T("};"), 4492 ]) 4493 4494 4495def _make_constant_value_registration_table(table_name, constant_entries): 4496 assert isinstance(table_name, str) 4497 assert isinstance(constant_entries, (list, tuple)) 4498 assert all( 4499 isinstance(entry, _PropEntryConstant) 4500 and entry.const_callback_name is None for entry in constant_entries) 4501 4502 T = TextNode 4503 4504 entry_nodes = [] 4505 for entry in constant_entries: 4506 pattern = ("{{" 4507 "\"{property_name}\", " 4508 "{constant_value}" 4509 "}},") 4510 text = _format(pattern, 4511 property_name=entry.property_.identifier, 4512 constant_value=entry.const_constant_name) 4513 entry_nodes.append(T(text)) 4514 4515 return ListNode([ 4516 T("static const IDLMemberInstaller::ConstantValueConfig " + 4517 table_name + "[] = {"), 4518 ListNode(entry_nodes), 4519 T("};"), 4520 ]) 4521 4522 4523def _make_exposed_construct_registration_table(table_name, 4524 exposed_construct_entries): 4525 assert isinstance(table_name, str) 4526 assert isinstance(exposed_construct_entries, (list, tuple)) 4527 assert all( 4528 isinstance(entry, _PropEntryExposedConstruct) 4529 for entry in exposed_construct_entries) 4530 4531 T = TextNode 4532 4533 entry_nodes = [] 4534 for entry in exposed_construct_entries: 4535 pattern = ("{{" 4536 "\"{property_name}\", " 4537 "{exposed_construct_callback}" 4538 "}}, ") 4539 text = _format(pattern, 4540 property_name=entry.property_.identifier, 4541 exposed_construct_callback=entry.prop_callback_name) 4542 entry_nodes.append(T(text)) 4543 4544 return ListNode([ 4545 T("static const IDLMemberInstaller::ExposedConstructConfig " + 4546 table_name + "[] = {"), 4547 ListNode(entry_nodes), 4548 T("};"), 4549 ]) 4550 4551 4552def _make_operation_registration_table(table_name, operation_entries): 4553 assert isinstance(table_name, str) 4554 assert isinstance(operation_entries, (list, tuple)) 4555 assert all( 4556 isinstance(entry, _PropEntryOperationGroup) 4557 for entry in operation_entries) 4558 4559 T = TextNode 4560 4561 no_alloc_direct_call_count = 0 4562 for entry in operation_entries: 4563 if entry.no_alloc_direct_callback_name: 4564 no_alloc_direct_call_count += 1 4565 assert (no_alloc_direct_call_count == 0 4566 or no_alloc_direct_call_count == len(operation_entries)) 4567 no_alloc_direct_call_enabled = no_alloc_direct_call_count > 0 4568 4569 entry_nodes = [] 4570 for entry in operation_entries: 4571 pattern = ("{{" 4572 "\"{property_name}\", " 4573 "{operation_callback}, " 4574 "{function_length}, " 4575 "{v8_property_attribute}, " 4576 "{location}, " 4577 "{world}, " 4578 "{receiver_check}, " 4579 "{cross_origin_check}, " 4580 "{v8_side_effect}" 4581 "}}, ") 4582 if no_alloc_direct_call_enabled: 4583 pattern = "{{" + pattern + "{v8_c_function}}}, " 4584 text = _format( 4585 pattern, 4586 property_name=entry.property_.identifier, 4587 operation_callback=entry.op_callback_name, 4588 function_length=entry.op_func_length, 4589 v8_property_attribute=_make_property_entry_v8_property_attribute( 4590 entry.property_), 4591 location=_make_property_entry_location(entry.property_), 4592 world=_make_property_entry_world(entry.world), 4593 receiver_check=_make_property_entry_receiver_check( 4594 entry.property_), 4595 cross_origin_check=_make_property_entry_cross_origin_check( 4596 entry.property_), 4597 v8_side_effect=_make_property_entry_v8_side_effect( 4598 entry.property_), 4599 v8_c_function=_make_property_entry_v8_c_function(entry)) 4600 entry_nodes.append(T(text)) 4601 4602 table_decl_before_name = ( 4603 "static const IDLMemberInstaller::OperationConfig") 4604 if no_alloc_direct_call_enabled: 4605 table_decl_before_name = ( 4606 "static const " 4607 "IDLMemberInstaller::NoAllocDirectCallOperationConfig") 4608 return ListNode([ 4609 T(table_decl_before_name + " " + table_name + "[] = {"), 4610 ListNode(entry_nodes), 4611 T("};"), 4612 ]) 4613 4614 4615class _PropEntryBase(object): 4616 def __init__(self, is_context_dependent, exposure_conditional, world, 4617 property_): 4618 assert isinstance(is_context_dependent, bool) 4619 assert isinstance(exposure_conditional, CodeGenExpr) 4620 4621 self.is_context_dependent = is_context_dependent 4622 self.exposure_conditional = exposure_conditional 4623 self.world = world 4624 self.property_ = property_ 4625 4626 4627class _PropEntryAttribute(_PropEntryBase): 4628 def __init__(self, is_context_dependent, exposure_conditional, world, 4629 attribute, attr_get_callback_name, attr_set_callback_name): 4630 assert isinstance(attr_get_callback_name, str) 4631 assert _is_none_or_str(attr_set_callback_name) 4632 4633 _PropEntryBase.__init__(self, is_context_dependent, 4634 exposure_conditional, world, attribute) 4635 self.attr_get_callback_name = attr_get_callback_name 4636 self.attr_set_callback_name = attr_set_callback_name 4637 4638 4639class _PropEntryConstant(_PropEntryBase): 4640 def __init__(self, is_context_dependent, exposure_conditional, world, 4641 constant, const_callback_name, const_constant_name): 4642 assert _is_none_or_str(const_callback_name) 4643 assert isinstance(const_constant_name, str) 4644 4645 _PropEntryBase.__init__(self, is_context_dependent, 4646 exposure_conditional, world, constant) 4647 self.const_callback_name = const_callback_name 4648 self.const_constant_name = const_constant_name 4649 4650 4651class _PropEntryConstructorGroup(_PropEntryBase): 4652 def __init__(self, is_context_dependent, exposure_conditional, world, 4653 constructor_group, ctor_callback_name, ctor_func_length): 4654 assert isinstance(ctor_callback_name, str) 4655 assert isinstance(ctor_func_length, (int, long)) 4656 4657 _PropEntryBase.__init__(self, is_context_dependent, 4658 exposure_conditional, world, constructor_group) 4659 self.ctor_callback_name = ctor_callback_name 4660 self.ctor_func_length = ctor_func_length 4661 4662 4663class _PropEntryExposedConstruct(_PropEntryBase): 4664 def __init__(self, is_context_dependent, exposure_conditional, world, 4665 exposed_construct, prop_callback_name): 4666 assert isinstance(prop_callback_name, str) 4667 4668 _PropEntryBase.__init__(self, is_context_dependent, 4669 exposure_conditional, world, exposed_construct) 4670 self.prop_callback_name = prop_callback_name 4671 4672 4673class _PropEntryOperationGroup(_PropEntryBase): 4674 def __init__(self, 4675 is_context_dependent, 4676 exposure_conditional, 4677 world, 4678 operation_group, 4679 op_callback_name, 4680 op_func_length, 4681 no_alloc_direct_callback_name=None): 4682 assert isinstance(op_callback_name, str) 4683 assert isinstance(op_func_length, (int, long)) 4684 4685 _PropEntryBase.__init__(self, is_context_dependent, 4686 exposure_conditional, world, operation_group) 4687 self.op_callback_name = op_callback_name 4688 self.op_func_length = op_func_length 4689 self.no_alloc_direct_callback_name = no_alloc_direct_callback_name 4690 4691 4692def make_property_entries_and_callback_defs(cg_context, attribute_entries, 4693 constant_entries, 4694 constructor_entries, 4695 exposed_construct_entries, 4696 operation_entries): 4697 """ 4698 Creates intermediate objects to help property installation and also makes 4699 code nodes of callback functions. 4700 4701 Args: 4702 attribute_entries: 4703 constructor_entries: 4704 exposed_construct_entries: 4705 operation_entries: 4706 Output parameters to store the intermediate objects. 4707 """ 4708 assert isinstance(cg_context, CodeGenContext) 4709 assert isinstance(attribute_entries, list) 4710 assert isinstance(constant_entries, list) 4711 assert isinstance(constructor_entries, list) 4712 assert isinstance(exposed_construct_entries, list) 4713 assert isinstance(operation_entries, list) 4714 4715 class_like = cg_context.class_like 4716 interface = cg_context.interface 4717 global_names = class_like.extended_attributes.values_of("Global") 4718 4719 callback_def_nodes = ListNode() 4720 4721 def iterate(members, callback): 4722 for member in members: 4723 is_context_dependent = member.exposure.is_context_dependent( 4724 global_names) 4725 exposure_conditional = expr_from_exposure( 4726 member.exposure, 4727 global_names=global_names, 4728 may_use_feature_selector=True) 4729 4730 if "PerWorldBindings" in member.extended_attributes: 4731 worlds = (CodeGenContext.MAIN_WORLD, 4732 CodeGenContext.NON_MAIN_WORLDS) 4733 else: 4734 worlds = (CodeGenContext.ALL_WORLDS, ) 4735 4736 for world in worlds: 4737 callback(member, is_context_dependent, exposure_conditional, 4738 world) 4739 4740 def process_attribute(attribute, is_context_dependent, 4741 exposure_conditional, world): 4742 if "CSSProperty" in attribute.extended_attributes: 4743 return # [CSSProperty] will be installed in a special manner. 4744 4745 cgc_attr = cg_context.make_copy(attribute=attribute, for_world=world) 4746 cgc = cgc_attr.make_copy(attribute_get=True) 4747 attr_get_callback_name = callback_function_name(cgc) 4748 attr_get_callback_node = make_attribute_get_callback_def( 4749 cgc, attr_get_callback_name) 4750 cgc = cgc_attr.make_copy(attribute_set=True) 4751 attr_set_callback_name = callback_function_name(cgc) 4752 attr_set_callback_node = make_attribute_set_callback_def( 4753 cgc, attr_set_callback_name) 4754 if attr_set_callback_node is None: 4755 attr_set_callback_name = None 4756 4757 callback_def_nodes.extend([ 4758 attr_get_callback_node, 4759 EmptyNode(), 4760 attr_set_callback_node, 4761 EmptyNode(), 4762 ]) 4763 4764 attribute_entries.append( 4765 _PropEntryAttribute( 4766 is_context_dependent=is_context_dependent, 4767 exposure_conditional=exposure_conditional, 4768 world=world, 4769 attribute=attribute, 4770 attr_get_callback_name=attr_get_callback_name, 4771 attr_set_callback_name=attr_set_callback_name)) 4772 4773 def process_constant(constant, is_context_dependent, exposure_conditional, 4774 world): 4775 cgc = cg_context.make_copy( 4776 constant=constant, 4777 for_world=world, 4778 v8_callback_type=CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK) 4779 const_callback_name = callback_function_name(cgc) 4780 const_callback_node = make_constant_callback_def( 4781 cgc, const_callback_name) 4782 if const_callback_node is None: 4783 const_callback_name = None 4784 # IDL constant's C++ constant name 4785 const_constant_name = _format("${class_name}::Constant::{}", 4786 constant_name(cgc)) 4787 4788 callback_def_nodes.extend([ 4789 const_callback_node, 4790 EmptyNode(), 4791 ]) 4792 4793 constant_entries.append( 4794 _PropEntryConstant( 4795 is_context_dependent=is_context_dependent, 4796 exposure_conditional=exposure_conditional, 4797 world=world, 4798 constant=constant, 4799 const_callback_name=const_callback_name, 4800 const_constant_name=const_constant_name)) 4801 4802 def process_constructor_group(constructor_group, is_context_dependent, 4803 exposure_conditional, world): 4804 cgc = cg_context.make_copy( 4805 constructor_group=constructor_group, for_world=world) 4806 ctor_callback_name = callback_function_name(cgc) 4807 ctor_callback_node = make_constructor_callback_def( 4808 cgc, ctor_callback_name) 4809 4810 callback_def_nodes.extend([ 4811 ctor_callback_node, 4812 EmptyNode(), 4813 ]) 4814 4815 constructor_entries.append( 4816 _PropEntryConstructorGroup( 4817 is_context_dependent=is_context_dependent, 4818 exposure_conditional=exposure_conditional, 4819 world=world, 4820 constructor_group=constructor_group, 4821 ctor_callback_name=ctor_callback_name, 4822 ctor_func_length=( 4823 constructor_group.min_num_of_required_arguments))) 4824 4825 def process_exposed_construct(exposed_construct, is_context_dependent, 4826 exposure_conditional, world): 4827 if isinstance(exposed_construct, web_idl.LegacyWindowAlias): 4828 cgc = cg_context.make_copy( 4829 exposed_construct=exposed_construct.original, 4830 legacy_window_alias=exposed_construct, 4831 for_world=world, 4832 v8_callback_type=CodeGenContext. 4833 V8_ACCESSOR_NAME_GETTER_CALLBACK) 4834 elif ("LegacyNoInterfaceObject" in 4835 exposed_construct.extended_attributes): 4836 return # Skip due to [LegacyNoInterfaceObject]. 4837 else: 4838 cgc = cg_context.make_copy( 4839 exposed_construct=exposed_construct, 4840 for_world=world, 4841 v8_callback_type=CodeGenContext. 4842 V8_ACCESSOR_NAME_GETTER_CALLBACK) 4843 prop_callback_name = callback_function_name(cgc) 4844 prop_callback_node = make_exposed_construct_callback_def( 4845 cgc, prop_callback_name) 4846 4847 callback_def_nodes.extend([ 4848 prop_callback_node, 4849 EmptyNode(), 4850 ]) 4851 4852 exposed_construct_entries.append( 4853 _PropEntryExposedConstruct( 4854 is_context_dependent=is_context_dependent, 4855 exposure_conditional=exposure_conditional, 4856 world=world, 4857 exposed_construct=exposed_construct, 4858 prop_callback_name=prop_callback_name)) 4859 4860 def process_named_constructor_group(named_constructor_group, 4861 is_context_dependent, 4862 exposure_conditional, world): 4863 cgc = cg_context.make_copy( 4864 exposed_construct=named_constructor_group, 4865 is_named_constructor=True, 4866 for_world=world, 4867 v8_callback_type=CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK) 4868 prop_callback_name = callback_function_name(cgc) 4869 prop_callback_node = make_named_constructor_property_callback_def( 4870 cgc, prop_callback_name) 4871 4872 callback_def_nodes.extend([ 4873 prop_callback_node, 4874 EmptyNode(), 4875 ]) 4876 4877 exposed_construct_entries.append( 4878 _PropEntryExposedConstruct( 4879 is_context_dependent=is_context_dependent, 4880 exposure_conditional=exposure_conditional, 4881 world=world, 4882 exposed_construct=named_constructor_group, 4883 prop_callback_name=prop_callback_name)) 4884 4885 def process_operation_group(operation_group, is_context_dependent, 4886 exposure_conditional, world): 4887 cgc = cg_context.make_copy( 4888 operation_group=operation_group, for_world=world) 4889 op_callback_name = callback_function_name(cgc) 4890 no_alloc_direct_callback_name = ( 4891 callback_function_name(cgc, no_alloc_direct_call=True) 4892 if "NoAllocDirectCall" in operation_group.extended_attributes else 4893 None) 4894 op_callback_node = make_operation_callback_def( 4895 cgc, 4896 op_callback_name, 4897 no_alloc_direct_callback_name=no_alloc_direct_callback_name) 4898 4899 callback_def_nodes.extend([ 4900 op_callback_node, 4901 EmptyNode(), 4902 ]) 4903 4904 operation_entries.append( 4905 _PropEntryOperationGroup( 4906 is_context_dependent=is_context_dependent, 4907 exposure_conditional=exposure_conditional, 4908 world=world, 4909 operation_group=operation_group, 4910 op_callback_name=op_callback_name, 4911 op_func_length=operation_group.min_num_of_required_arguments, 4912 no_alloc_direct_callback_name=no_alloc_direct_callback_name)) 4913 4914 def process_stringifier(_, is_context_dependent, exposure_conditional, 4915 world): 4916 cgc = cg_context.make_copy( 4917 stringifier=interface.stringifier, for_world=world) 4918 op_callback_name = callback_function_name(cgc) 4919 op_callback_node = make_stringifier_callback_def(cgc, op_callback_name) 4920 4921 callback_def_nodes.extend([ 4922 op_callback_node, 4923 EmptyNode(), 4924 ]) 4925 4926 operation_entries.append( 4927 _PropEntryOperationGroup( 4928 is_context_dependent=is_context_dependent, 4929 exposure_conditional=exposure_conditional, 4930 world=world, 4931 operation_group=cgc.property_, 4932 op_callback_name=op_callback_name, 4933 op_func_length=0)) 4934 4935 iterate(class_like.attributes, process_attribute) 4936 iterate(class_like.constants, process_constant) 4937 if interface: 4938 iterate(interface.constructor_groups, process_constructor_group) 4939 iterate(interface.exposed_constructs, process_exposed_construct) 4940 iterate(interface.legacy_window_aliases, process_exposed_construct) 4941 named_constructor_groups = [ 4942 group for construct in interface.exposed_constructs 4943 for group in construct.named_constructor_groups 4944 if construct.named_constructor_groups 4945 ] 4946 iterate(named_constructor_groups, process_named_constructor_group) 4947 if not class_like.is_callback_interface: 4948 iterate(class_like.operation_groups, process_operation_group) 4949 if interface and interface.stringifier: 4950 iterate([interface.stringifier.operation], process_stringifier) 4951 collectionlike = interface and (interface.iterable or interface.maplike 4952 or interface.setlike) 4953 if collectionlike: 4954 4955 def should_define(target): 4956 if not target[0].is_optionally_defined: 4957 return True 4958 return all(target.identifier != member.identifier 4959 for member in itertools.chain( 4960 interface.attributes, interface.constants, 4961 interface.operation_groups)) 4962 4963 iterate(collectionlike.attributes, process_attribute) 4964 iterate( 4965 filter(should_define, collectionlike.operation_groups), 4966 process_operation_group) 4967 4968 return callback_def_nodes 4969 4970 4971def _make_install_prototype_object(cg_context): 4972 assert isinstance(cg_context, CodeGenContext) 4973 4974 nodes = [] 4975 4976 class_like = cg_context.class_like 4977 interface = cg_context.interface 4978 4979 unscopables = [] 4980 is_unscopable = lambda member: "Unscopable" in member.extended_attributes 4981 unscopables.extend(filter(is_unscopable, class_like.attributes)) 4982 unscopables.extend(filter(is_unscopable, class_like.operations)) 4983 if unscopables: 4984 nodes.extend([ 4985 TextNode("""\ 4986// [Unscopable] 4987// 3.7.3. Interface prototype object 4988// https://heycam.github.io/webidl/#interface-prototype-object 4989// step 10. If interface has any member declared with the [Unscopable] 4990// extended attribute, then:\ 4991"""), 4992 ListNode([ 4993 TextNode("static constexpr const char* " 4994 "kUnscopablePropertyNames[] = {"), 4995 ListNode([ 4996 TextNode("\"{}\", ".format(member.identifier)) 4997 for member in unscopables 4998 ]), 4999 TextNode("};"), 5000 ]), 5001 TextNode("""\ 5002bindings::InstallUnscopablePropertyNames( 5003 ${isolate}, ${v8_context}, ${prototype_object}, kUnscopablePropertyNames); 5004"""), 5005 ]) 5006 5007 if "LegacyNoInterfaceObject" in class_like.extended_attributes: 5008 nodes.append( 5009 TextNode("""\ 5010// [LegacyNoInterfaceObject] 5011// 3.7.3. Interface prototype object 5012// https://heycam.github.io/webidl/#interface-prototype-object 5013// step 13. If the [LegacyNoInterfaceObject] extended attribute was not 5014// specified on interface, then: 5015// 5016// V8 defines "constructor" property on the prototype object by default. 5017${prototype_object}->Delete( 5018 ${v8_context}, V8AtomicString(${isolate}, "constructor")).ToChecked(); 5019""")) 5020 5021 collectionlike = interface and (interface.iterable or interface.maplike 5022 or interface.setlike) 5023 if collectionlike: 5024 property_name = None 5025 for operation_group in collectionlike.operation_groups: 5026 if operation_group[0].is_iterator: 5027 property_name = operation_group.identifier 5028 break 5029 if property_name: 5030 pattern = """\ 5031// @@iterator == "{property_name}" 5032{{ 5033 v8::Local<v8::Value> v8_value = ${prototype_object}->Get( 5034 ${v8_context}, V8AtomicString(${isolate}, "{property_name}")) 5035 .ToLocalChecked(); 5036 ${prototype_object}->DefineOwnProperty( 5037 ${v8_context}, v8::Symbol::GetIterator(${isolate}), v8_value, 5038 v8::DontEnum).ToChecked(); 5039}} 5040""" 5041 nodes.append( 5042 TextNode(_format(pattern, property_name=property_name))) 5043 5044 if class_like.identifier == "FileSystemDirectoryHandle": 5045 pattern = """\ 5046// Temporary @@asyncIterator support for FileSystemDirectoryHandle 5047// TODO(https://crbug.com/1087157): Replace with proper bindings support. 5048// @@asyncIterator == "{property_name}" 5049{{ 5050 v8::Local<v8::Value> v8_value = ${prototype_object}->Get( 5051 ${v8_context}, V8AtomicString(${isolate}, "{property_name}")) 5052 .ToLocalChecked(); 5053 ${prototype_object}->DefineOwnProperty( 5054 ${v8_context}, v8::Symbol::GetAsyncIterator(${isolate}), v8_value, 5055 v8::DontEnum).ToChecked(); 5056}} 5057""" 5058 nodes.append(TextNode(_format(pattern, property_name="entries"))) 5059 5060 if ("Global" in class_like.extended_attributes 5061 and class_like.indexed_and_named_properties 5062 and class_like.indexed_and_named_properties.has_named_properties): 5063 nodes.append( 5064 TextNode("""\ 5065// https://heycam.github.io/webidl/#named-properties-object 5066// V8 defines "constructor" property on the prototype object by default. 5067// Named properties object is currently implemented as a prototype object 5068// (implemented with v8::FunctionTemplate::PrototypeTemplate()). 5069${prototype_object}->GetPrototype().As<v8::Object>()->Delete( 5070 ${v8_context}, V8AtomicString(${isolate}, "constructor")).ToChecked(); 5071""")) 5072 5073 return SequenceNode(nodes) if nodes else None 5074 5075 5076def make_install_interface_template(cg_context, function_name, class_name, 5077 trampoline_var_name, constructor_entries, 5078 supplemental_install_node, 5079 install_unconditional_func_name, 5080 install_context_independent_func_name): 5081 """ 5082 Returns: 5083 A triplet of CodeNode of: 5084 - function declaration 5085 - function definition 5086 - trampoline function definition (from the API class to the 5087 implementation class), which is supposed to be defined inline 5088 """ 5089 assert isinstance(cg_context, CodeGenContext) 5090 assert isinstance(function_name, str) 5091 assert _is_none_or_str(class_name) 5092 assert _is_none_or_str(trampoline_var_name) 5093 assert isinstance(constructor_entries, (list, tuple)) 5094 assert all( 5095 isinstance(entry, _PropEntryConstructorGroup) 5096 for entry in constructor_entries) 5097 assert isinstance(supplemental_install_node, SequenceNode) 5098 assert _is_none_or_str(install_unconditional_func_name) 5099 assert _is_none_or_str(install_context_independent_func_name) 5100 5101 T = TextNode 5102 5103 class_like = cg_context.class_like 5104 interface = cg_context.interface 5105 5106 arg_decls = [ 5107 "v8::Isolate* isolate", 5108 "const DOMWrapperWorld& world", 5109 "v8::Local<v8::Template> interface_template", 5110 ] 5111 return_type = "void" 5112 5113 if trampoline_var_name is None: 5114 trampoline_def = None 5115 else: 5116 trampoline_def = CxxFuncDefNode( 5117 name=function_name, 5118 arg_decls=arg_decls, 5119 return_type=return_type, 5120 static=True) 5121 trampoline_def.body.append( 5122 TextNode( 5123 _format("return {}(isolate, world, interface_template);", 5124 trampoline_var_name))) 5125 5126 func_decl = CxxFuncDeclNode( 5127 name=function_name, 5128 arg_decls=arg_decls, 5129 return_type=return_type, 5130 static=True) 5131 5132 func_def = CxxFuncDefNode( 5133 name=function_name, 5134 arg_decls=arg_decls, 5135 return_type=return_type, 5136 class_name=class_name) 5137 func_def.set_base_template_vars(cg_context.template_bindings()) 5138 5139 body = func_def.body 5140 body.add_template_vars({ 5141 "isolate": "isolate", 5142 "world": "world", 5143 "interface_template": "interface_template", 5144 }) 5145 bind_installer_local_vars(body, cg_context) 5146 5147 if cg_context.interface: 5148 body.extend([ 5149 T("bindings::SetupIDLInterfaceTemplate(" 5150 "${isolate}, ${wrapper_type_info}, " 5151 "${instance_object_template}, " 5152 "${prototype_object_template}, " 5153 "${interface_function_template}, " 5154 "${parent_interface_template});"), 5155 EmptyNode(), 5156 ]) 5157 elif cg_context.namespace: 5158 body.extend([ 5159 T("bindings::SetupIDLNamespaceTemplate(" 5160 "${isolate}, ${wrapper_type_info}, " 5161 "${namespace_object_template});"), 5162 EmptyNode(), 5163 ]) 5164 elif cg_context.callback_interface: 5165 body.extend([ 5166 T("bindings::SetupIDLCallbackInterfaceTemplate(" 5167 "${isolate}, ${wrapper_type_info}, " 5168 "${interface_function_template});"), 5169 EmptyNode(), 5170 ]) 5171 else: 5172 assert False 5173 5174 for entry in constructor_entries: 5175 set_callback = _format( 5176 "${interface_function_template}->SetCallHandler({});", 5177 entry.ctor_callback_name) 5178 set_length = _format("${interface_function_template}->SetLength({});", 5179 entry.ctor_func_length) 5180 if entry.world == CodeGenContext.MAIN_WORLD: 5181 body.append( 5182 CxxLikelyIfNode( 5183 cond="${world}.IsMainWorld()", 5184 body=[T(set_callback), T(set_length)])) 5185 elif entry.world == CodeGenContext.NON_MAIN_WORLDS: 5186 body.append( 5187 CxxLikelyIfNode( 5188 cond="!${world}.IsMainWorld()", 5189 body=[T(set_callback), T(set_length)])) 5190 elif entry.world == CodeGenContext.ALL_WORLDS: 5191 body.extend([T(set_callback), T(set_length)]) 5192 else: 5193 assert False 5194 body.append(EmptyNode()) 5195 5196 body.extend([ 5197 supplemental_install_node, 5198 EmptyNode(), 5199 ]) 5200 5201 if class_like.identifier == "CSSStyleDeclaration": 5202 css_properties = filter( 5203 lambda attr: "CSSProperty" in attr.extended_attributes, 5204 class_like.attributes) 5205 if css_properties: 5206 prop_name_list = "".join( 5207 map(lambda attr: "\"{}\", ".format(attr.identifier), 5208 css_properties)) 5209 body.append( 5210 T("""\ 5211// CSSStyleDeclaration-specific settings 5212// [CSSProperty] 5213{ 5214 static constexpr const char* kCssProperties[] = { 5215""" + prop_name_list + """ 5216 }; 5217 bindings::InstallCSSPropertyAttributes( 5218 ${isolate}, ${world}, 5219 ${instance_template}, ${prototype_template}, ${interface_template}, 5220 ${signature}, kCssProperties); 5221} 5222""")) 5223 5224 if class_like.identifier == "DOMException": 5225 body.append( 5226 T("""\ 5227// DOMException-specific settings 5228// https://heycam.github.io/webidl/#es-DOMException-specialness 5229{ 5230 v8::Local<v8::FunctionTemplate> intrinsic_error_prototype_interface_template = 5231 v8::FunctionTemplate::New(${isolate}); 5232 intrinsic_error_prototype_interface_template->RemovePrototype(); 5233 intrinsic_error_prototype_interface_template->SetIntrinsicDataProperty( 5234 V8AtomicString(${isolate}, "prototype"), v8::kErrorPrototype); 5235 ${interface_function_template}->Inherit( 5236 intrinsic_error_prototype_interface_template); 5237} 5238""")) 5239 5240 if class_like.identifier == "NativeFileSystemDirectoryIterator": 5241 body.append( 5242 T("""\ 5243// Temporary @@asyncIterator support for FileSystemDirectoryHandle 5244// TODO(https://crbug.com/1087157): Replace with proper bindings support. 5245{ 5246 v8::Local<v8::FunctionTemplate> 5247 intrinsic_iterator_prototype_interface_template = 5248 v8::FunctionTemplate::New(${isolate}); 5249 intrinsic_iterator_prototype_interface_template->RemovePrototype(); 5250 intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty( 5251 V8AtomicString(${isolate}, "prototype"), v8::kAsyncIteratorPrototype); 5252 ${interface_function_template}->Inherit( 5253 intrinsic_iterator_prototype_interface_template); 5254} 5255""")) 5256 5257 if class_like.identifier == "HTMLAllCollection": 5258 body.append( 5259 T("""\ 5260// HTMLAllCollection-specific settings 5261// https://html.spec.whatwg.org/C/#the-htmlallcollection-interface 5262${instance_object_template}->SetCallAsFunctionHandler( 5263 ${class_name}::LegacyCallCustom); 5264${instance_object_template}->MarkAsUndetectable(); 5265""")) 5266 5267 if class_like.identifier == "Iterator": 5268 body.append( 5269 T("""\ 5270// Iterator-specific settings 5271// https://heycam.github.io/webidl/#es-iterator-prototype-object 5272{ 5273 v8::Local<v8::FunctionTemplate> 5274 intrinsic_iterator_prototype_interface_template = 5275 v8::FunctionTemplate::New(${isolate}); 5276 intrinsic_iterator_prototype_interface_template->RemovePrototype(); 5277 intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty( 5278 V8AtomicString(${isolate}, "prototype"), v8::kIteratorPrototype); 5279 ${interface_function_template}->Inherit( 5280 intrinsic_iterator_prototype_interface_template); 5281} 5282""")) 5283 5284 if class_like.identifier == "Location": 5285 body.append( 5286 T("""\ 5287// Location-specific settings 5288// https://html.spec.whatwg.org/C/#the-location-interface 5289// To create a Location object, run these steps: 5290// step 3. Let valueOf be location's relevant 5291// Realm.[[Intrinsics]].[[%ObjProto_valueOf%]]. 5292// step 3. Perform ! location.[[DefineOwnProperty]]("valueOf", 5293// { [[Value]]: valueOf, [[Writable]]: false, [[Enumerable]]: false, 5294// [[Configurable]]: false }). 5295${instance_template}->SetIntrinsicDataProperty( 5296 V8AtomicString(${isolate}, "valueOf"), 5297 v8::kObjProto_valueOf, 5298 static_cast<v8::PropertyAttribute>( 5299 v8::ReadOnly | v8::DontEnum | v8::DontDelete)); 5300// step 4. Perform ! location.[[DefineOwnProperty]](@@toPrimitive, 5301// { [[Value]]: undefined, [[Writable]]: false, [[Enumerable]]: false, 5302// [[Configurable]]: false }). 5303${instance_template}->Set( 5304 v8::Symbol::GetToPrimitive(${isolate}), 5305 v8::Undefined(${isolate}), 5306 static_cast<v8::PropertyAttribute>( 5307 v8::ReadOnly | v8::DontEnum | v8::DontDelete)); 5308// 7.7.4.2 [[SetPrototypeOf]] ( V ) 5309// https://html.spec.whatwg.org/C/#location-setprototypeof 5310${instance_object_template}->SetImmutableProto(); 5311${prototype_object_template}->SetImmutableProto(); 5312""")) 5313 5314 if (interface and interface.indexed_and_named_properties 5315 and interface.indexed_and_named_properties.indexed_getter 5316 and "Global" not in interface.extended_attributes): 5317 body.append( 5318 T("""\ 5319// @@iterator for indexed properties 5320// https://heycam.github.io/webidl/#define-the-iteration-methods 5321${prototype_template}->SetIntrinsicDataProperty( 5322 v8::Symbol::GetIterator(${isolate}), v8::kArrayProto_values, v8::DontEnum); 5323""")) 5324 if interface and interface.iterable and not interface.iterable.key_type: 5325 body.append( 5326 T("""\ 5327// Value iterator's properties 5328// https://heycam.github.io/webidl/#define-the-iteration-methods 5329${prototype_template}->SetIntrinsicDataProperty( 5330 V8AtomicString(${isolate}, "entries"), v8::kArrayProto_entries, v8::None); 5331${prototype_template}->SetIntrinsicDataProperty( 5332 V8AtomicString(${isolate}, "keys"), v8::kArrayProto_keys, v8::None); 5333${prototype_template}->SetIntrinsicDataProperty( 5334 V8AtomicString(${isolate}, "values"), v8::kArrayProto_values, v8::None); 5335${prototype_template}->SetIntrinsicDataProperty( 5336 V8AtomicString(${isolate}, "forEach"), v8::kArrayProto_forEach, v8::None); 5337""")) 5338 5339 if interface and "IsCodeLike" in interface.extended_attributes: 5340 body.append( 5341 CxxUnlikelyIfNode( 5342 cond="RuntimeEnabledFeatures::TrustedTypesUseCodeLikeEnabled()", 5343 body=[ 5344 TextNode("// [IsCodeLike]"), 5345 TextNode("${instance_object_template}->SetCodeLike();"), 5346 ])) 5347 5348 if "Global" in class_like.extended_attributes: 5349 body.append( 5350 TextNode("""\ 5351// [Global] 5352// 3.7.1. [[SetPrototypeOf]] 5353// https://heycam.github.io/webidl/#platform-object-setprototypeof 5354${instance_object_template}->SetImmutableProto(); 5355${prototype_object_template}->SetImmutableProto(); 5356""")) 5357 elif interface and any("Global" in derived.extended_attributes 5358 for derived in interface.deriveds): 5359 body.append( 5360 TextNode("""\ 5361// [Global] - prototype object in the prototype chain of global objects 5362// 3.7.1. [[SetPrototypeOf]] 5363// https://heycam.github.io/webidl/#platform-object-setprototypeof 5364${prototype_object_template}->SetImmutableProto(); 5365""")) 5366 5367 func_call_pattern = ("{}(${isolate}, ${world}, ${instance_template}, " 5368 "${prototype_template}, ${interface_template});") 5369 if install_unconditional_func_name: 5370 func_call = _format(func_call_pattern, install_unconditional_func_name) 5371 body.append(T(func_call)) 5372 if install_context_independent_func_name: 5373 func_call = _format(func_call_pattern, 5374 install_context_independent_func_name) 5375 body.append(T(func_call)) 5376 5377 return func_decl, func_def, trampoline_def 5378 5379 5380class PropInstallMode(object): 5381 class Mode(int): 5382 pass 5383 5384 UNCONDITIONAL = Mode(0) 5385 CONTEXT_INDEPENDENT = Mode(1) 5386 CONTEXT_DEPENDENT = Mode(2) 5387 V8_CONTEXT_SNAPSHOT = Mode(3) 5388 5389 5390def make_install_properties(cg_context, function_name, class_name, 5391 prop_install_mode, trampoline_var_name, 5392 attribute_entries, constant_entries, 5393 exposed_construct_entries, operation_entries): 5394 """ 5395 Returns: 5396 A triplet of CodeNode of: 5397 - function declaration 5398 - function definition 5399 - trampoline function definition (from the API class to the 5400 implementation class), which is supposed to be defined inline 5401 """ 5402 assert isinstance(cg_context, CodeGenContext) 5403 assert isinstance(function_name, str) 5404 assert _is_none_or_str(class_name) 5405 assert isinstance(prop_install_mode, PropInstallMode.Mode) 5406 assert _is_none_or_str(trampoline_var_name) 5407 assert isinstance(attribute_entries, (list, tuple)) 5408 assert all( 5409 isinstance(entry, _PropEntryAttribute) for entry in attribute_entries) 5410 assert isinstance(constant_entries, (list, tuple)) 5411 assert all( 5412 isinstance(entry, _PropEntryConstant) for entry in constant_entries) 5413 assert isinstance(exposed_construct_entries, (list, tuple)) 5414 assert all( 5415 isinstance(entry, _PropEntryExposedConstruct) 5416 for entry in exposed_construct_entries) 5417 assert isinstance(operation_entries, (list, tuple)) 5418 assert all( 5419 isinstance(entry, _PropEntryOperationGroup) 5420 for entry in operation_entries) 5421 5422 if prop_install_mode == PropInstallMode.CONTEXT_DEPENDENT: 5423 install_prototype_object_node = _make_install_prototype_object( 5424 cg_context) 5425 else: 5426 install_prototype_object_node = None 5427 5428 if not (attribute_entries or constant_entries or exposed_construct_entries 5429 or operation_entries or install_prototype_object_node): 5430 if prop_install_mode != PropInstallMode.V8_CONTEXT_SNAPSHOT: 5431 return None, None, None 5432 5433 if prop_install_mode in (PropInstallMode.UNCONDITIONAL, 5434 PropInstallMode.CONTEXT_INDEPENDENT): 5435 arg_decls = [ 5436 "v8::Isolate* isolate", 5437 "const DOMWrapperWorld& world", 5438 "v8::Local<v8::Template> instance_template", 5439 "v8::Local<v8::Template> prototype_template", 5440 "v8::Local<v8::Template> interface_template", 5441 ] 5442 arg_names = [ 5443 "isolate", 5444 "world", 5445 "instance_template", 5446 "prototype_template", 5447 "interface_template", 5448 ] 5449 elif prop_install_mode == PropInstallMode.CONTEXT_DEPENDENT: 5450 arg_decls = [ 5451 "v8::Local<v8::Context> context", 5452 "const DOMWrapperWorld& world", 5453 "v8::Local<v8::Object> instance_object", 5454 "v8::Local<v8::Object> prototype_object", 5455 "v8::Local<v8::Object> interface_object", 5456 "v8::Local<v8::Template> interface_template", 5457 "FeatureSelector feature_selector", 5458 ] 5459 arg_names = [ 5460 "context", 5461 "world", 5462 "instance_object", 5463 "prototype_object", 5464 "interface_object", 5465 "interface_template", 5466 "feature_selector", 5467 ] 5468 elif prop_install_mode == PropInstallMode.V8_CONTEXT_SNAPSHOT: 5469 arg_decls = [ 5470 "v8::Local<v8::Context> context", 5471 "const DOMWrapperWorld& world", 5472 "v8::Local<v8::Object> instance_object", 5473 "v8::Local<v8::Object> prototype_object", 5474 "v8::Local<v8::Object> interface_object", 5475 "v8::Local<v8::Template> interface_template", 5476 ] 5477 arg_names = [ 5478 "context", 5479 "world", 5480 "instance_object", 5481 "prototype_object", 5482 "interface_object", 5483 "interface_template", 5484 ] 5485 return_type = "void" 5486 5487 is_per_context_install = ( 5488 prop_install_mode in (PropInstallMode.CONTEXT_DEPENDENT, 5489 PropInstallMode.V8_CONTEXT_SNAPSHOT)) 5490 5491 if trampoline_var_name is None: 5492 trampoline_def = None 5493 else: 5494 trampoline_def = CxxFuncDefNode( 5495 name=function_name, 5496 arg_decls=arg_decls, 5497 return_type=return_type, 5498 static=True) 5499 text = _format( 5500 "return {func}({args});", 5501 func=trampoline_var_name, 5502 args=", ".join(arg_names)) 5503 trampoline_def.body.append(TextNode(text)) 5504 5505 func_decl = CxxFuncDeclNode(name=function_name, 5506 arg_decls=arg_decls, 5507 return_type=return_type, 5508 static=bool(class_name)) 5509 5510 func_def = CxxFuncDefNode( 5511 name=function_name, 5512 arg_decls=arg_decls, 5513 return_type=return_type, 5514 class_name=class_name) 5515 func_def.set_base_template_vars(cg_context.template_bindings()) 5516 5517 body = func_def.body 5518 for arg_name in arg_names: 5519 if arg_name == "context": # 'context' is reserved by Mako. 5520 body.add_template_var("v8_context", "context") 5521 else: 5522 body.add_template_var(arg_name, arg_name) 5523 bind_installer_local_vars(body, cg_context) 5524 5525 body.extend([ 5526 TextNode("using bindings::IDLMemberInstaller;"), 5527 EmptyNode(), 5528 ]) 5529 5530 if (is_per_context_install 5531 and "Global" in cg_context.class_like.extended_attributes): 5532 body.extend([ 5533 CxxLikelyIfNode(cond="${instance_object}.IsEmpty()", 5534 body=[ 5535 TextNode("""\ 5536${instance_object} = ${v8_context}->Global()->GetPrototype().As<v8::Object>();\ 5537"""), 5538 ]), 5539 EmptyNode(), 5540 ]) 5541 5542 if install_prototype_object_node: 5543 body.extend([ 5544 CxxLikelyIfNode(cond="${feature_selector}.IsAll()", 5545 body=[install_prototype_object_node]), 5546 EmptyNode(), 5547 ]) 5548 5549 def group_by_condition(entries): 5550 unconditional_entries = [] 5551 conditional_to_entries = {} 5552 for entry in entries: 5553 if entry.exposure_conditional.is_always_true: 5554 unconditional_entries.append(entry) 5555 else: 5556 conditional_to_entries.setdefault(entry.exposure_conditional, 5557 []).append(entry) 5558 return unconditional_entries, conditional_to_entries 5559 5560 def install_properties(table_name, target_entries, make_table_func, 5561 installer_call_text): 5562 unconditional_entries, conditional_to_entries = group_by_condition( 5563 target_entries) 5564 if unconditional_entries: 5565 body.append( 5566 CxxBlockNode([ 5567 make_table_func(table_name, unconditional_entries), 5568 TextNode(installer_call_text), 5569 ])) 5570 body.append(EmptyNode()) 5571 for conditional, entries in conditional_to_entries.items(): 5572 body.append( 5573 CxxUnlikelyIfNode( 5574 cond=conditional, 5575 body=[ 5576 make_table_func(table_name, entries), 5577 TextNode(installer_call_text), 5578 ])) 5579 body.append(EmptyNode()) 5580 5581 if is_per_context_install: 5582 pattern = ("{install_func}(" 5583 "${isolate}, ${world}, " 5584 "${instance_object}, " 5585 "${prototype_object}, " 5586 "${interface_object}, " 5587 "${signature}, {table_name});") 5588 else: 5589 pattern = ("{install_func}(" 5590 "${isolate}, ${world}, " 5591 "${instance_template}, " 5592 "${prototype_template}, " 5593 "${interface_template}, " 5594 "${signature}, {table_name});") 5595 5596 table_name = "kAttributeTable" 5597 installer_call_text = _format( 5598 pattern, 5599 install_func="IDLMemberInstaller::InstallAttributes", 5600 table_name=table_name) 5601 install_properties(table_name, attribute_entries, 5602 _make_attribute_registration_table, installer_call_text) 5603 5604 table_name = "kConstantCallbackTable" 5605 installer_call_text = _format( 5606 pattern, 5607 install_func="IDLMemberInstaller::InstallConstants", 5608 table_name=table_name) 5609 constant_callback_entries = filter(lambda entry: entry.const_callback_name, 5610 constant_entries) 5611 install_properties(table_name, constant_callback_entries, 5612 _make_constant_callback_registration_table, 5613 installer_call_text) 5614 5615 table_name = "kConstantValueTable" 5616 installer_call_text = _format( 5617 pattern, 5618 install_func="IDLMemberInstaller::InstallConstants", 5619 table_name=table_name) 5620 constant_value_entries = filter( 5621 lambda entry: not entry.const_callback_name, constant_entries) 5622 install_properties(table_name, constant_value_entries, 5623 _make_constant_value_registration_table, 5624 installer_call_text) 5625 5626 table_name = "kExposedConstructTable" 5627 installer_call_text = _format( 5628 pattern, 5629 install_func="IDLMemberInstaller::InstallExposedConstructs", 5630 table_name=table_name) 5631 install_properties(table_name, exposed_construct_entries, 5632 _make_exposed_construct_registration_table, 5633 installer_call_text) 5634 5635 table_name = "kOperationTable" 5636 installer_call_text = _format( 5637 pattern, 5638 install_func="IDLMemberInstaller::InstallOperations", 5639 table_name=table_name) 5640 entries = filter(lambda entry: not entry.no_alloc_direct_callback_name, 5641 operation_entries) 5642 install_properties(table_name, entries, _make_operation_registration_table, 5643 installer_call_text) 5644 entries = filter(lambda entry: entry.no_alloc_direct_callback_name, 5645 operation_entries) 5646 install_properties(table_name, entries, _make_operation_registration_table, 5647 installer_call_text) 5648 5649 return func_decl, func_def, trampoline_def 5650 5651 5652def make_indexed_and_named_property_callbacks_and_install_node(cg_context): 5653 """ 5654 Implements non-ordinary internal methods of legacy platform objects. 5655 https://heycam.github.io/webidl/#es-legacy-platform-objects 5656 5657 Also implements the same origin case of indexed access to WindowProxy 5658 objects just same as indexed properties of legacy platform objects. 5659 https://html.spec.whatwg.org/C/#the-windowproxy-exotic-object 5660 """ 5661 5662 assert isinstance(cg_context, CodeGenContext) 5663 5664 F = lambda *args, **kwargs: TextNode(_format(*args, **kwargs)) 5665 5666 func_decls = ListNode() 5667 func_defs = ListNode() 5668 install_node = SequenceNode() 5669 5670 interface = cg_context.interface 5671 if not (interface and interface.indexed_and_named_properties 5672 and "Global" not in interface.extended_attributes): 5673 return func_decls, func_defs, install_node 5674 props = interface.indexed_and_named_properties 5675 5676 def add_callback(func_decl, func_def): 5677 func_decls.append(func_decl) 5678 if func_def: 5679 func_defs.append(func_def) 5680 func_defs.append(EmptyNode()) 5681 5682 def most_derived_interface(*interfaces): 5683 key = lambda interface: len(interface.inclusive_inherited_interfaces) 5684 return sorted(filter(None, interfaces), key=key)[-1] 5685 5686 cg_context = cg_context.make_copy( 5687 v8_callback_type=CodeGenContext.V8_OTHER_CALLBACK) 5688 5689 if props.own_named_getter: 5690 add_callback(*make_named_property_getter_callback( 5691 cg_context.make_copy(named_property_getter=props.named_getter), 5692 "NamedPropertyGetterCallback")) 5693 add_callback(*make_named_property_setter_callback( 5694 cg_context.make_copy(named_property_setter=props.named_setter), 5695 "NamedPropertySetterCallback")) 5696 add_callback(*make_named_property_deleter_callback( 5697 cg_context.make_copy(named_property_deleter=props.named_deleter), 5698 "NamedPropertyDeleterCallback")) 5699 add_callback(*make_named_property_definer_callback( 5700 cg_context, "NamedPropertyDefinerCallback")) 5701 add_callback(*make_named_property_descriptor_callback( 5702 cg_context, "NamedPropertyDescriptorCallback")) 5703 add_callback(*make_named_property_query_callback( 5704 cg_context, "NamedPropertyQueryCallback")) 5705 add_callback(*make_named_property_enumerator_callback( 5706 cg_context, "NamedPropertyEnumeratorCallback")) 5707 5708 if props.named_getter: 5709 impl_bridge = v8_bridge_class_name( 5710 most_derived_interface( 5711 props.named_getter.owner, props.named_setter 5712 and props.named_setter.owner, props.named_deleter 5713 and props.named_deleter.owner)) 5714 flags = ["v8::PropertyHandlerFlags::kOnlyInterceptStrings"] 5715 if "LegacyOverrideBuiltIns" not in interface.extended_attributes: 5716 flags.append("v8::PropertyHandlerFlags::kNonMasking") 5717 if (props.named_getter.extended_attributes.value_of("Affects") == 5718 "Nothing"): 5719 flags.append("v8::PropertyHandlerFlags::kHasNoSideEffect") 5720 property_handler_flags = ( 5721 "static_cast<v8::PropertyHandlerFlags>({})".format(" | ".join( 5722 map(lambda flag: "int32_t({})".format(flag), flags)))) 5723 pattern = """\ 5724// Named interceptors 5725${instance_object_template}->SetHandler( 5726 v8::NamedPropertyHandlerConfiguration( 5727 {impl_bridge}::NamedPropertyGetterCallback, 5728 {impl_bridge}::NamedPropertySetterCallback, 5729% if "NotEnumerable" not in \ 5730interface.indexed_and_named_properties.named_getter.extended_attributes: 5731 {impl_bridge}::NamedPropertyQueryCallback, 5732% else: 5733 nullptr, // query 5734% endif 5735 {impl_bridge}::NamedPropertyDeleterCallback, 5736% if "NotEnumerable" not in \ 5737interface.indexed_and_named_properties.named_getter.extended_attributes: 5738 {impl_bridge}::NamedPropertyEnumeratorCallback, 5739% else: 5740 nullptr, // enumerator 5741% endif 5742 {impl_bridge}::NamedPropertyDefinerCallback, 5743 {impl_bridge}::NamedPropertyDescriptorCallback, 5744 v8::Local<v8::Value>(), 5745 {property_handler_flags}));""" 5746 install_node.append( 5747 F(pattern, 5748 impl_bridge=impl_bridge, 5749 property_handler_flags=property_handler_flags)) 5750 5751 if props.own_indexed_getter or props.own_named_getter: 5752 add_callback(*make_indexed_property_getter_callback( 5753 cg_context.make_copy(indexed_property_getter=props.indexed_getter), 5754 "IndexedPropertyGetterCallback")) 5755 add_callback(*make_indexed_property_setter_callback( 5756 cg_context.make_copy(indexed_property_setter=props.indexed_setter), 5757 "IndexedPropertySetterCallback")) 5758 add_callback(*make_indexed_property_deleter_callback( 5759 cg_context, "IndexedPropertyDeleterCallback")) 5760 add_callback(*make_indexed_property_definer_callback( 5761 cg_context, "IndexedPropertyDefinerCallback")) 5762 add_callback(*make_indexed_property_descriptor_callback( 5763 cg_context, "IndexedPropertyDescriptorCallback")) 5764 add_callback(*make_indexed_property_enumerator_callback( 5765 cg_context, "IndexedPropertyEnumeratorCallback")) 5766 5767 if props.indexed_getter or props.named_getter: 5768 impl_bridge = v8_bridge_class_name( 5769 most_derived_interface( 5770 props.indexed_getter and props.indexed_getter.owner, 5771 props.indexed_setter and props.indexed_setter.owner, 5772 props.named_getter and props.named_getter.owner, 5773 props.named_setter and props.named_setter.owner, 5774 props.named_deleter and props.named_deleter.owner)) 5775 flags = [] 5776 if (props.indexed_getter and props.indexed_getter.extended_attributes. 5777 value_of("Affects") == "Nothing"): 5778 flags.append("v8::PropertyHandlerFlags::kHasNoSideEffect") 5779 else: 5780 flags.append("v8::PropertyHandlerFlags::kNone") 5781 property_handler_flags = flags[0] 5782 pattern = """\ 5783// Indexed interceptors 5784${instance_object_template}->SetHandler( 5785 v8::IndexedPropertyHandlerConfiguration( 5786 {impl_bridge}::IndexedPropertyGetterCallback, 5787 {impl_bridge}::IndexedPropertySetterCallback, 5788 nullptr, // query 5789 {impl_bridge}::IndexedPropertyDeleterCallback, 5790% if interface.indexed_and_named_properties.indexed_getter: 5791 {impl_bridge}::IndexedPropertyEnumeratorCallback, 5792% else: 5793 nullptr, // enumerator 5794% endif 5795 {impl_bridge}::IndexedPropertyDefinerCallback, 5796 {impl_bridge}::IndexedPropertyDescriptorCallback, 5797 v8::Local<v8::Value>(), 5798 {property_handler_flags}));""" 5799 install_node.append( 5800 F(pattern, 5801 impl_bridge=impl_bridge, 5802 property_handler_flags=property_handler_flags)) 5803 5804 func_defs.accumulate( 5805 CodeGenAccumulator.require_include_headers([ 5806 "third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h" 5807 ])) 5808 5809 return func_decls, func_defs, install_node 5810 5811 5812def make_named_properties_object_callbacks_and_install_node(cg_context): 5813 """ 5814 Implements non-ordinary internal methods of named properties objects. 5815 https://heycam.github.io/webidl/#named-properties-object 5816 """ 5817 5818 assert isinstance(cg_context, CodeGenContext) 5819 5820 callback_defs = [] 5821 install_node = SequenceNode() 5822 5823 interface = cg_context.interface 5824 if not (interface and interface.indexed_and_named_properties 5825 and interface.indexed_and_named_properties.named_getter 5826 and "Global" in interface.extended_attributes): 5827 return callback_defs, install_node 5828 5829 cg_context = cg_context.make_copy( 5830 v8_callback_type=CodeGenContext.V8_OTHER_CALLBACK) 5831 5832 func_defs = [ 5833 make_named_props_obj_named_getter_callback( 5834 cg_context, "NamedPropsObjNamedGetterCallback"), 5835 make_named_props_obj_named_deleter_callback( 5836 cg_context, "NamedPropsObjNamedDeleterCallback"), 5837 make_named_props_obj_named_definer_callback( 5838 cg_context, "NamedPropsObjNamedDefinerCallback"), 5839 make_named_props_obj_named_descriptor_callback( 5840 cg_context, "NamedPropsObjNamedDescriptorCallback"), 5841 make_named_props_obj_indexed_getter_callback( 5842 cg_context, "NamedPropsObjIndexedGetterCallback"), 5843 make_named_props_obj_indexed_deleter_callback( 5844 cg_context, "NamedPropsObjIndexedDeleterCallback"), 5845 make_named_props_obj_indexed_definer_callback( 5846 cg_context, "NamedPropsObjIndexedDefinerCallback"), 5847 make_named_props_obj_indexed_descriptor_callback( 5848 cg_context, "NamedPropsObjIndexedDescriptorCallback"), 5849 ] 5850 for func_def in func_defs: 5851 callback_defs.append(func_def) 5852 callback_defs.append(EmptyNode()) 5853 5854 text = """\ 5855// Named interceptors 5856${npo_prototype_template}->SetHandler( 5857 v8::NamedPropertyHandlerConfiguration( 5858 NamedPropsObjNamedGetterCallback, 5859 nullptr, // setter 5860 nullptr, // query 5861 NamedPropsObjNamedDeleterCallback, 5862 nullptr, // enumerator 5863 NamedPropsObjNamedDefinerCallback, 5864 NamedPropsObjNamedDescriptorCallback, 5865 v8::Local<v8::Value>(), 5866 static_cast<v8::PropertyHandlerFlags>( 5867 int32_t(v8::PropertyHandlerFlags::kNonMasking) | 5868 int32_t(v8::PropertyHandlerFlags::kOnlyInterceptStrings)))); 5869// Indexed interceptors 5870${npo_prototype_template}->SetHandler( 5871 v8::IndexedPropertyHandlerConfiguration( 5872 NamedPropsObjIndexedGetterCallback, 5873 nullptr, // setter 5874 nullptr, // query 5875 NamedPropsObjIndexedDeleterCallback, 5876 nullptr, // enumerator 5877 NamedPropsObjIndexedDefinerCallback, 5878 NamedPropsObjIndexedDescriptorCallback, 5879 v8::Local<v8::Value>(), 5880 v8::PropertyHandlerFlags::kNone));""" 5881 install_node.append(TextNode(text)) 5882 5883 return callback_defs, install_node 5884 5885 5886def make_cross_origin_property_callbacks_and_install_node( 5887 cg_context, attribute_entries, operation_entries): 5888 """ 5889 Implements non-ordinary internal methods of WindowProxy and Location 5890 objects. 5891 https://html.spec.whatwg.org/C/#the-windowproxy-exotic-object 5892 https://html.spec.whatwg.org/C/#the-location-interface 5893 """ 5894 5895 assert isinstance(cg_context, CodeGenContext) 5896 5897 callback_defs = [] 5898 install_node = SequenceNode() 5899 5900 CROSS_ORIGIN_INTERFACES = ("Window", "Location") 5901 if cg_context.class_like.identifier not in CROSS_ORIGIN_INTERFACES: 5902 return callback_defs, install_node 5903 props = cg_context.interface.indexed_and_named_properties 5904 5905 entry_nodes = [] 5906 for entry in attribute_entries: 5907 attribute = entry.property_ 5908 if "CrossOrigin" not in attribute.extended_attributes: 5909 continue 5910 assert entry.world == CodeGenContext.ALL_WORLDS 5911 values = attribute.extended_attributes.values_of("CrossOrigin") 5912 get_func = "nullptr" 5913 set_func = "nullptr" 5914 get_value = "nullptr" 5915 set_value = "nullptr" 5916 if not values or "Getter" in values: 5917 get_func = entry.attr_get_callback_name 5918 cgc = cg_context.make_copy( 5919 attribute=attribute, 5920 attribute_get=True, 5921 v8_callback_type=( 5922 CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK)) 5923 get_value = callback_function_name(cgc, for_cross_origin=True) 5924 func_def = make_attribute_get_callback_def(cgc, get_value) 5925 callback_defs.extend([func_def, EmptyNode()]) 5926 if values and "Setter" in values: 5927 set_func = entry.attr_set_callback_name 5928 cgc = cg_context.make_copy( 5929 attribute=attribute, 5930 attribute_set=True, 5931 v8_callback_type=( 5932 CodeGenContext.V8_GENERIC_NAMED_PROPERTY_SETTER_CALLBACK)) 5933 set_value = callback_function_name(cgc, for_cross_origin=True) 5934 func_def = make_attribute_set_callback_def(cgc, set_value) 5935 callback_defs.extend([func_def, EmptyNode()]) 5936 pattern = ("{{\"{property_name}\", " 5937 "{get_func}, {set_func}, {get_value}, {set_value}}},") 5938 entry_nodes.append( 5939 TextNode( 5940 _format( 5941 pattern, 5942 property_name=attribute.identifier, 5943 get_func=get_func, 5944 set_func=set_func, 5945 get_value=get_value, 5946 set_value=set_value))) 5947 callback_defs.append( 5948 ListNode([ 5949 TextNode("constexpr bindings::CrossOriginAttributeTableEntry " 5950 "kCrossOriginAttributeTable[] = {"), 5951 ListNode(entry_nodes), 5952 TextNode("};"), 5953 EmptyNode(), 5954 ])) 5955 5956 entry_nodes = [] 5957 for entry in operation_entries: 5958 operation_group = entry.property_ 5959 if "CrossOrigin" not in operation_group.extended_attributes: 5960 continue 5961 assert entry.world == CodeGenContext.ALL_WORLDS 5962 entry_nodes.append( 5963 TextNode( 5964 _format( 5965 "{{\"{property_name}\", {op_callback}, {op_func_length}}},", 5966 property_name=operation_group.identifier, 5967 op_callback=entry.op_callback_name, 5968 op_func_length=entry.op_func_length))) 5969 callback_defs.append( 5970 ListNode([ 5971 TextNode("constexpr bindings::CrossOriginOperationTableEntry " 5972 "kCrossOriginOperationTable[] = {"), 5973 ListNode(entry_nodes), 5974 TextNode("};"), 5975 EmptyNode(), 5976 ])) 5977 5978 cg_context = cg_context.make_copy( 5979 v8_callback_type=CodeGenContext.V8_OTHER_CALLBACK) 5980 5981 func_defs = [ 5982 make_cross_origin_access_check_callback( 5983 cg_context, "CrossOriginAccessCheckCallback"), 5984 make_cross_origin_named_getter_callback( 5985 cg_context, "CrossOriginNamedGetterCallback"), 5986 make_cross_origin_named_setter_callback( 5987 cg_context, "CrossOriginNamedSetterCallback"), 5988 make_cross_origin_named_deleter_callback( 5989 cg_context, "CrossOriginNamedDeleterCallback"), 5990 make_cross_origin_named_definer_callback( 5991 cg_context, "CrossOriginNamedDefinerCallback"), 5992 make_cross_origin_named_descriptor_callback( 5993 cg_context, "CrossOriginNamedDescriptorCallback"), 5994 make_cross_origin_named_query_callback( 5995 cg_context, "CrossOriginNamedQueryCallback"), 5996 make_cross_origin_named_enumerator_callback( 5997 cg_context, "CrossOriginNamedEnumeratorCallback"), 5998 make_cross_origin_indexed_getter_callback( 5999 cg_context.make_copy( 6000 indexed_property_getter=(props and props.indexed_getter)), 6001 "CrossOriginIndexedGetterCallback"), 6002 make_cross_origin_indexed_setter_callback( 6003 cg_context, "CrossOriginIndexedSetterCallback"), 6004 make_cross_origin_indexed_deleter_callback( 6005 cg_context, "CrossOriginIndexedDeleterCallback"), 6006 make_cross_origin_indexed_definer_callback( 6007 cg_context, "CrossOriginIndexedDefinerCallback"), 6008 make_cross_origin_indexed_descriptor_callback( 6009 cg_context, "CrossOriginIndexedDescriptorCallback"), 6010 make_cross_origin_indexed_enumerator_callback( 6011 cg_context, "CrossOriginIndexedEnumeratorCallback"), 6012 ] 6013 for func_def in func_defs: 6014 callback_defs.append(func_def) 6015 callback_defs.append(EmptyNode()) 6016 6017 text = """\ 6018// Cross origin properties 6019${instance_object_template}->SetAccessCheckCallbackAndHandler( 6020 CrossOriginAccessCheckCallback, 6021 v8::NamedPropertyHandlerConfiguration( 6022 CrossOriginNamedGetterCallback, 6023 CrossOriginNamedSetterCallback, 6024 CrossOriginNamedQueryCallback, 6025 CrossOriginNamedDeleterCallback, 6026 CrossOriginNamedEnumeratorCallback, 6027 CrossOriginNamedDefinerCallback, 6028 CrossOriginNamedDescriptorCallback, 6029 v8::Local<v8::Value>(), 6030 v8::PropertyHandlerFlags::kNone), 6031 v8::IndexedPropertyHandlerConfiguration( 6032 CrossOriginIndexedGetterCallback, 6033 CrossOriginIndexedSetterCallback, 6034 nullptr, // query 6035 CrossOriginIndexedDeleterCallback, 6036 CrossOriginIndexedEnumeratorCallback, 6037 CrossOriginIndexedDefinerCallback, 6038 CrossOriginIndexedDescriptorCallback, 6039 v8::Local<v8::Value>(), 6040 v8::PropertyHandlerFlags::kNone), 6041 v8::External::New( 6042 ${isolate}, 6043 const_cast<WrapperTypeInfo*>(${class_name}::GetWrapperTypeInfo()))); 6044""" 6045 install_node.append(TextNode(text)) 6046 install_node.accumulate( 6047 CodeGenAccumulator.require_include_headers([ 6048 "third_party/blink/renderer/bindings/core/v8/binding_security.h", 6049 "third_party/blink/renderer/platform/bindings/v8_cross_origin_property_support.h", 6050 ])) 6051 6052 if cg_context.interface.identifier != "Window": 6053 return callback_defs, install_node 6054 6055 func_defs = [ 6056 make_same_origin_indexed_getter_callback( 6057 cg_context.make_copy( 6058 indexed_property_getter=(props and props.indexed_getter)), 6059 "SameOriginIndexedGetterCallback"), 6060 make_same_origin_indexed_setter_callback( 6061 cg_context, "SameOriginIndexedSetterCallback"), 6062 make_same_origin_indexed_deleter_callback( 6063 cg_context, "SameOriginIndexedDeleterCallback"), 6064 make_same_origin_indexed_definer_callback( 6065 cg_context, "SameOriginIndexedDefinerCallback"), 6066 make_same_origin_indexed_descriptor_callback( 6067 cg_context, "SameOriginIndexedDescriptorCallback"), 6068 make_same_origin_indexed_enumerator_callback( 6069 cg_context, "SameOriginIndexedEnumeratorCallback"), 6070 ] 6071 for func_def in func_defs: 6072 callback_defs.append(func_def) 6073 callback_defs.append(EmptyNode()) 6074 6075 text = """\ 6076// Same origin interceptors 6077${instance_object_template}->SetHandler( 6078 v8::IndexedPropertyHandlerConfiguration( 6079 SameOriginIndexedGetterCallback, 6080 SameOriginIndexedSetterCallback, 6081 nullptr, // query 6082 SameOriginIndexedDeleterCallback, 6083 SameOriginIndexedEnumeratorCallback, 6084 SameOriginIndexedDefinerCallback, 6085 SameOriginIndexedDescriptorCallback, 6086 v8::Local<v8::Value>(), 6087 v8::PropertyHandlerFlags::kNone)); 6088""" 6089 install_node.append(TextNode(text)) 6090 6091 return callback_defs, install_node 6092 6093 6094def make_cross_component_init( 6095 cg_context, function_name, class_name, has_unconditional_props, 6096 has_context_independent_props, has_context_dependent_props): 6097 """ 6098 Returns: 6099 A triplet of CodeNode of: 6100 - function declaration 6101 - function definition 6102 - trampoline member variable definitions 6103 """ 6104 assert isinstance(cg_context, CodeGenContext) 6105 assert isinstance(function_name, str) 6106 assert isinstance(class_name, str) 6107 assert isinstance(has_unconditional_props, bool) 6108 assert isinstance(has_context_independent_props, bool) 6109 assert isinstance(has_context_dependent_props, bool) 6110 6111 T = TextNode 6112 F = lambda *args, **kwargs: T(_format(*args, **kwargs)) 6113 6114 def filter_four_trampolines(nodes): 6115 assert len(nodes) == 4 6116 flags = (True, has_unconditional_props, has_context_independent_props, 6117 has_context_dependent_props) 6118 return [node for node, flag in zip(nodes, flags) if flag] 6119 6120 trampoline_var_decls = ListNode( 6121 filter_four_trampolines([ 6122 F("static InstallInterfaceTemplateFuncType {};", 6123 TP_INSTALL_INTERFACE_TEMPLATE), 6124 F("static InstallUnconditionalPropertiesFuncType {};", 6125 TP_INSTALL_UNCONDITIONAL_PROPS), 6126 F("static InstallContextIndependentPropertiesFuncType {};", 6127 TP_INSTALL_CONTEXT_INDEPENDENT_PROPS), 6128 F("static InstallContextDependentPropertiesFuncType {};", 6129 TP_INSTALL_CONTEXT_DEPENDENT_PROPS), 6130 ])) 6131 6132 trampoline_var_defs = ListNode( 6133 filter_four_trampolines([ 6134 F(("${class_name}::InstallInterfaceTemplateFuncType " 6135 "${class_name}::{} = nullptr;"), TP_INSTALL_INTERFACE_TEMPLATE), 6136 F(("${class_name}::InstallUnconditionalPropertiesFuncType " 6137 "${class_name}::{} = nullptr;"), 6138 TP_INSTALL_UNCONDITIONAL_PROPS), 6139 F(("${class_name}::InstallContextIndependentPropertiesFuncType " 6140 "${class_name}::{} = nullptr;"), 6141 TP_INSTALL_CONTEXT_INDEPENDENT_PROPS), 6142 F(("${class_name}::InstallContextDependentPropertiesFuncType " 6143 "${class_name}::{} = nullptr;"), 6144 TP_INSTALL_CONTEXT_DEPENDENT_PROPS), 6145 ])) 6146 trampoline_var_defs.set_base_template_vars(cg_context.template_bindings()) 6147 6148 func_decl = CxxFuncDeclNode( 6149 name=function_name, arg_decls=[], return_type="void", static=True) 6150 6151 func_def = CxxFuncDefNode( 6152 name=function_name, 6153 arg_decls=[], 6154 return_type="void", 6155 class_name=class_name) 6156 func_def.set_base_template_vars(cg_context.template_bindings()) 6157 6158 body = func_def.body 6159 body.extend( 6160 filter_four_trampolines([ 6161 F("${class_name}::{} = {};", TP_INSTALL_INTERFACE_TEMPLATE, 6162 FN_INSTALL_INTERFACE_TEMPLATE), 6163 F("${class_name}::{} = {};", TP_INSTALL_UNCONDITIONAL_PROPS, 6164 FN_INSTALL_UNCONDITIONAL_PROPS), 6165 F("${class_name}::{} = {};", TP_INSTALL_CONTEXT_INDEPENDENT_PROPS, 6166 FN_INSTALL_CONTEXT_INDEPENDENT_PROPS), 6167 F("${class_name}::{} = {};", TP_INSTALL_CONTEXT_DEPENDENT_PROPS, 6168 FN_INSTALL_CONTEXT_DEPENDENT_PROPS), 6169 ])) 6170 6171 return func_decl, func_def, trampoline_var_decls, trampoline_var_defs 6172 6173 6174# ---------------------------------------------------------------------------- 6175# WrapperTypeInfo 6176# ---------------------------------------------------------------------------- 6177 6178 6179def make_wrapper_type_info(cg_context, function_name, 6180 has_context_dependent_props): 6181 assert isinstance(cg_context, CodeGenContext) 6182 assert function_name == "GetWrapperTypeInfo" 6183 assert isinstance(has_context_dependent_props, bool) 6184 6185 F = lambda *args, **kwargs: TextNode(_format(*args, **kwargs)) 6186 6187 func_def = CxxFuncDefNode( 6188 name=function_name, 6189 arg_decls=[], 6190 return_type="constexpr const WrapperTypeInfo*", 6191 static=True) 6192 func_def.set_base_template_vars(cg_context.template_bindings()) 6193 func_def.body.append(TextNode("return &wrapper_type_info_;")) 6194 6195 member_var_def = TextNode( 6196 "static const WrapperTypeInfo wrapper_type_info_;") 6197 6198 wrapper_type_info_def = ListNode() 6199 wrapper_type_info_def.set_base_template_vars( 6200 cg_context.template_bindings()) 6201 6202 pattern = """\ 6203// Construction of WrapperTypeInfo may require non-trivial initialization due 6204// to cross-component address resolution in order to load the pointer to the 6205// parent interface's WrapperTypeInfo. We ignore this issue because the issue 6206// happens only on component builds and the official release builds 6207// (statically-linked builds) are never affected by this issue. 6208#if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__) 6209#pragma clang diagnostic push 6210#pragma clang diagnostic ignored "-Wglobal-constructors" 6211#endif 6212 6213const WrapperTypeInfo ${class_name}::wrapper_type_info_{{ 6214 gin::kEmbedderBlink, 6215 ${class_name}::{install_interface_template_func}, 6216 {install_context_dependent_func}, 6217 "${{class_like.identifier}}", 6218 {wrapper_type_info_of_inherited}, 6219 {wrapper_type_prototype}, 6220 {wrapper_class_id}, 6221 {active_script_wrappable_inheritance}, 6222 {idl_definition_kind}, 6223}}; 6224 6225#if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__) 6226#pragma clang diagnostic pop 6227#endif 6228""" 6229 class_like = cg_context.class_like 6230 if has_context_dependent_props: 6231 install_context_dependent_func = _format( 6232 "${class_name}::{}", FN_INSTALL_CONTEXT_DEPENDENT_PROPS) 6233 else: 6234 install_context_dependent_func = "nullptr" 6235 if class_like.is_interface and class_like.inherited: 6236 wrapper_type_info_of_inherited = "{}::GetWrapperTypeInfo()".format( 6237 v8_bridge_class_name(class_like.inherited)) 6238 else: 6239 wrapper_type_info_of_inherited = "nullptr" 6240 if class_like.is_interface: 6241 wrapper_type_prototype = "WrapperTypeInfo::kWrapperTypeObjectPrototype" 6242 else: 6243 wrapper_type_prototype = "WrapperTypeInfo::kWrapperTypeNoPrototype" 6244 if class_like.is_interface and class_like.does_implement("Node"): 6245 wrapper_class_id = "WrapperTypeInfo::kNodeClassId" 6246 else: 6247 wrapper_class_id = "WrapperTypeInfo::kObjectClassId" 6248 if class_like.code_generator_info.is_active_script_wrappable: 6249 active_script_wrappable_inheritance = ( 6250 "WrapperTypeInfo::kInheritFromActiveScriptWrappable") 6251 else: 6252 active_script_wrappable_inheritance = ( 6253 "WrapperTypeInfo::kNotInheritFromActiveScriptWrappable") 6254 if class_like.is_interface: 6255 idl_definition_kind = "WrapperTypeInfo::kIdlInterface" 6256 elif class_like.is_namespace: 6257 idl_definition_kind = "WrapperTypeInfo::kIdlNamespace" 6258 elif class_like.is_callback_interface: 6259 idl_definition_kind = "WrapperTypeInfo::kIdlCallbackInterface" 6260 wrapper_type_info_def.append( 6261 F(pattern, 6262 install_interface_template_func=FN_INSTALL_INTERFACE_TEMPLATE, 6263 install_context_dependent_func=install_context_dependent_func, 6264 wrapper_type_info_of_inherited=wrapper_type_info_of_inherited, 6265 wrapper_type_prototype=wrapper_type_prototype, 6266 wrapper_class_id=wrapper_class_id, 6267 active_script_wrappable_inheritance=( 6268 active_script_wrappable_inheritance), 6269 idl_definition_kind=idl_definition_kind)) 6270 6271 if class_like.is_interface: 6272 blink_class = blink_class_name(class_like) 6273 pattern = """\ 6274const WrapperTypeInfo& {blink_class}::wrapper_type_info_ = 6275 ${class_name}::wrapper_type_info_; 6276""" 6277 wrapper_type_info_def.append(F(pattern, blink_class=blink_class)) 6278 6279 if class_like.code_generator_info.is_active_script_wrappable: 6280 pattern = """\ 6281// [ActiveScriptWrappable] 6282static_assert( 6283 std::is_base_of<ActiveScriptWrappableBase, {blink_class}>::value, 6284 "{blink_class} does not inherit from ActiveScriptWrappable<> despite " 6285 "the IDL has [ActiveScriptWrappable] extended attribute."); 6286static_assert( 6287 !std::is_same<decltype(&{blink_class}::HasPendingActivity), 6288 decltype(&ScriptWrappable::HasPendingActivity)>::value, 6289 "{blink_class} is not overriding hasPendingActivity() despite " 6290 "the IDL has [ActiveScriptWrappable] extended attribute.");""" 6291 else: 6292 pattern = """\ 6293// non-[ActiveScriptWrappable] 6294static_assert( 6295 !std::is_base_of<ActiveScriptWrappableBase, {blink_class}>::value, 6296 "{blink_class} inherits from ActiveScriptWrappable<> without " 6297 "[ActiveScriptWrappable] extended attribute."); 6298static_assert( 6299 std::is_same<decltype(&{blink_class}::HasPendingActivity), 6300 decltype(&ScriptWrappable::HasPendingActivity)>::value, 6301 "{blink_class} is overriding hasPendingActivity() without " 6302 "[ActiveScriptWrappable] extended attribute.");""" 6303 if class_like.is_interface: 6304 wrapper_type_info_def.append(F(pattern, blink_class=blink_class)) 6305 6306 return func_def, member_var_def, wrapper_type_info_def 6307 6308 6309# ---------------------------------------------------------------------------- 6310# V8 Context Snapshot 6311# ---------------------------------------------------------------------------- 6312 6313 6314def make_v8_context_snapshot_api(cg_context, component, attribute_entries, 6315 constant_entries, constructor_entries, 6316 exposed_construct_entries, operation_entries, 6317 named_properties_object_callback_defs, 6318 cross_origin_property_callback_defs, 6319 install_context_independent_func_name): 6320 assert isinstance(cg_context, CodeGenContext) 6321 assert isinstance(component, web_idl.Component) 6322 6323 if not cg_context.interface: 6324 return None, None 6325 6326 derived_interfaces = cg_context.interface.deriveds 6327 derived_names = map(lambda interface: interface.identifier, 6328 derived_interfaces) 6329 derived_names.append(cg_context.interface.identifier) 6330 if not ("Window" in derived_names or "HTMLDocument" in derived_names): 6331 return None, None 6332 6333 header_ns = CxxNamespaceNode(name_style.namespace("v8_context_snapshot")) 6334 source_ns = CxxNamespaceNode(name_style.namespace("v8_context_snapshot")) 6335 6336 export_text = component_export(component, False) 6337 6338 def add_func(func_decl, func_def): 6339 header_ns.body.extend([ 6340 TextNode(export_text), 6341 func_decl, 6342 EmptyNode(), 6343 ]) 6344 source_ns.body.extend([ 6345 func_def, 6346 EmptyNode(), 6347 ]) 6348 6349 add_func(*_make_v8_context_snapshot_get_reference_table_function( 6350 cg_context, name_style.func("GetRefTableOf", 6351 cg_context.class_name), attribute_entries, 6352 constant_entries, constructor_entries, exposed_construct_entries, 6353 operation_entries, named_properties_object_callback_defs, 6354 cross_origin_property_callback_defs)) 6355 6356 add_func(*_make_v8_context_snapshot_install_props_per_context_function( 6357 cg_context, name_style.func("InstallPropsOf", 6358 cg_context.class_name), attribute_entries, 6359 constant_entries, exposed_construct_entries, operation_entries)) 6360 6361 add_func(*_make_v8_context_snapshot_install_props_per_isolate_function( 6362 cg_context, name_style.func("InstallPropsOf", cg_context.class_name), 6363 install_context_independent_func_name)) 6364 6365 return header_ns, source_ns 6366 6367 6368def _make_v8_context_snapshot_get_reference_table_function( 6369 cg_context, function_name, attribute_entries, constant_entries, 6370 constructor_entries, exposed_construct_entries, operation_entries, 6371 named_properties_object_callback_defs, 6372 cross_origin_property_callback_defs): 6373 callback_names = ["${class_name}::GetWrapperTypeInfo()"] 6374 6375 for entry in attribute_entries: 6376 if entry.exposure_conditional.is_always_true: 6377 callback_names.append(entry.attr_get_callback_name) 6378 callback_names.append(entry.attr_set_callback_name) 6379 for entry in constant_entries: 6380 if entry.exposure_conditional.is_always_true: 6381 callback_names.append(entry.const_callback_name) 6382 for entry in constructor_entries: 6383 if entry.exposure_conditional.is_always_true: 6384 callback_names.append(entry.ctor_callback_name) 6385 for entry in exposed_construct_entries: 6386 if entry.exposure_conditional.is_always_true: 6387 callback_names.append(entry.prop_callback_name) 6388 for entry in operation_entries: 6389 if entry.exposure_conditional.is_always_true: 6390 callback_names.append(entry.op_callback_name) 6391 6392 def collect_callbacks(node): 6393 if isinstance(node, CxxFuncDefNode): 6394 callback_names.append(node.function_name) 6395 elif hasattr(node, "__iter__"): 6396 for child_node in node: 6397 collect_callbacks(child_node) 6398 6399 collect_callbacks(named_properties_object_callback_defs) 6400 collect_callbacks(cross_origin_property_callback_defs) 6401 6402 entry_nodes = map( 6403 lambda name: TextNode("reinterpret_cast<intptr_t>({}),".format(name)), 6404 filter(None, callback_names)) 6405 table_node = ListNode([ 6406 TextNode("static const intptr_t kReferenceTable[] = {"), 6407 ListNode(entry_nodes), 6408 TextNode("};"), 6409 ]) 6410 6411 func_decl = CxxFuncDeclNode(name=function_name, 6412 arg_decls=[], 6413 return_type="base::span<const intptr_t>") 6414 6415 func_def = CxxFuncDefNode(name=function_name, 6416 arg_decls=[], 6417 return_type="base::span<const intptr_t>") 6418 func_def.set_base_template_vars(cg_context.template_bindings()) 6419 body = func_def.body 6420 body.extend([table_node, TextNode("return kReferenceTable;")]) 6421 6422 return func_decl, func_def 6423 6424 6425def _make_v8_context_snapshot_install_props_per_context_function( 6426 cg_context, function_name, attribute_entries, constant_entries, 6427 exposed_construct_entries, operation_entries): 6428 def selector(entry): 6429 if entry.exposure_conditional.is_always_true: 6430 return False 6431 if entry.is_context_dependent: 6432 return False 6433 return True 6434 6435 func_decl, func_def, _ = make_install_properties( 6436 cg_context, 6437 function_name, 6438 class_name=None, 6439 prop_install_mode=PropInstallMode.V8_CONTEXT_SNAPSHOT, 6440 trampoline_var_name=None, 6441 attribute_entries=filter(selector, attribute_entries), 6442 constant_entries=filter(selector, constant_entries), 6443 exposed_construct_entries=filter(selector, exposed_construct_entries), 6444 operation_entries=filter(selector, operation_entries)) 6445 6446 return func_decl, func_def 6447 6448 6449def _make_v8_context_snapshot_install_props_per_isolate_function( 6450 cg_context, function_name, install_context_independent_func_name): 6451 arg_decls = [ 6452 "v8::Isolate* isolate", 6453 "const DOMWrapperWorld& world", 6454 "v8::Local<v8::Template> instance_template", 6455 "v8::Local<v8::Template> prototype_template", 6456 "v8::Local<v8::Template> interface_template", 6457 ] 6458 arg_names = [ 6459 "isolate", 6460 "world", 6461 "instance_template", 6462 "prototype_template", 6463 "interface_template", 6464 ] 6465 return_type = "void" 6466 6467 func_decl = CxxFuncDeclNode(name=function_name, 6468 arg_decls=arg_decls, 6469 return_type=return_type) 6470 func_def = CxxFuncDefNode(name=function_name, 6471 arg_decls=arg_decls, 6472 return_type=return_type) 6473 6474 if not install_context_independent_func_name: 6475 return func_decl, func_def 6476 6477 func_def.set_base_template_vars(cg_context.template_bindings()) 6478 body = func_def.body 6479 for arg_name in arg_names: 6480 body.add_template_var(arg_name, arg_name) 6481 pattern = """\ 6482return ${class_name}::{func}( 6483 ${isolate}, ${world}, 6484 ${instance_template}, 6485 ${prototype_template}, 6486 ${interface_template});\ 6487""" 6488 body.append( 6489 TextNode(_format(pattern, func=install_context_independent_func_name))) 6490 return func_decl, func_def 6491 6492 6493# ---------------------------------------------------------------------------- 6494# Main functions 6495# ---------------------------------------------------------------------------- 6496 6497 6498def _collect_include_headers(class_like): 6499 assert isinstance(class_like, (web_idl.Interface, web_idl.Namespace)) 6500 6501 headers = set(class_like.code_generator_info.blink_headers) 6502 6503 def collect_from_idl_type(idl_type): 6504 idl_type.apply_to_all_composing_elements(add_include_headers) 6505 6506 def add_include_headers(idl_type): 6507 # ScriptPromise doesn't require any header for the result type. 6508 if idl_type.is_promise: 6509 raise StopIteration(idl_type.syntactic_form) 6510 6511 type_def_obj = idl_type.type_definition_object 6512 if type_def_obj is not None: 6513 if (type_def_obj.identifier in ( 6514 "OnErrorEventHandlerNonNull", 6515 "OnBeforeUnloadEventHandlerNonNull")): 6516 raise StopIteration(idl_type.syntactic_form) 6517 6518 headers.add(PathManager(type_def_obj).api_path(ext="h")) 6519 if type_def_obj.is_interface or type_def_obj.is_namespace: 6520 headers.add(PathManager(type_def_obj).blink_path(ext="h")) 6521 raise StopIteration(idl_type.syntactic_form) 6522 6523 union_def_obj = idl_type.union_definition_object 6524 if union_def_obj is not None: 6525 headers.add(PathManager(union_def_obj).api_path(ext="h")) 6526 6527 for attribute in class_like.attributes: 6528 collect_from_idl_type(attribute.idl_type) 6529 for constructor in class_like.constructors: 6530 for argument in constructor.arguments: 6531 collect_from_idl_type(argument.idl_type) 6532 for operation in class_like.operations: 6533 collect_from_idl_type(operation.return_type) 6534 for argument in operation.arguments: 6535 collect_from_idl_type(argument.idl_type) 6536 6537 if class_like.is_interface: 6538 for exposed_construct in class_like.exposed_constructs: 6539 headers.add(PathManager(exposed_construct).api_path(ext="h")) 6540 for legacy_window_alias in class_like.legacy_window_aliases: 6541 headers.add( 6542 PathManager(legacy_window_alias.original).api_path(ext="h")) 6543 6544 path_manager = PathManager(class_like) 6545 headers.discard(path_manager.api_path(ext="h")) 6546 headers.discard(path_manager.impl_path(ext="h")) 6547 6548 # TODO(yukishiino): Window interface should be 6549 # [ImplementedAs=LocalDOMWindow] instead of [ImplementedAs=DOMWindow], and 6550 # [CrossOrigin] properties should be implemented specifically with 6551 # DOMWindow class. Then, we'll have less hacks. 6552 if class_like.identifier == "Window": 6553 headers.add("third_party/blink/renderer/core/frame/local_dom_window.h") 6554 6555 return headers 6556 6557 6558def generate_class_like(class_like): 6559 assert isinstance(class_like, (web_idl.Interface, web_idl.Namespace)) 6560 6561 path_manager = PathManager(class_like) 6562 api_component = path_manager.api_component 6563 impl_component = path_manager.impl_component 6564 is_cross_components = path_manager.is_cross_components 6565 for_testing = class_like.code_generator_info.for_testing 6566 6567 # Class names 6568 api_class_name = v8_bridge_class_name(class_like) 6569 if is_cross_components: 6570 impl_class_name = "{}::Impl".format(api_class_name) 6571 else: 6572 impl_class_name = api_class_name 6573 6574 interface = None 6575 namespace = None 6576 if class_like.is_interface: 6577 interface = class_like 6578 cg_context = CodeGenContext(interface=interface, 6579 class_name=api_class_name) 6580 elif class_like.is_namespace: 6581 namespace = class_like 6582 cg_context = CodeGenContext(namespace=namespace, 6583 class_name=api_class_name) 6584 6585 # Filepaths 6586 api_header_path = path_manager.api_path(ext="h") 6587 api_source_path = path_manager.api_path(ext="cc") 6588 if is_cross_components: 6589 impl_header_path = path_manager.impl_path(ext="h") 6590 impl_source_path = path_manager.impl_path(ext="cc") 6591 6592 # Root nodes 6593 api_header_node = ListNode(tail="\n") 6594 api_header_node.set_accumulator(CodeGenAccumulator()) 6595 api_header_node.set_renderer(MakoRenderer()) 6596 api_source_node = ListNode(tail="\n") 6597 api_source_node.set_accumulator(CodeGenAccumulator()) 6598 api_source_node.set_renderer(MakoRenderer()) 6599 if is_cross_components: 6600 impl_header_node = ListNode(tail="\n") 6601 impl_header_node.set_accumulator(CodeGenAccumulator()) 6602 impl_header_node.set_renderer(MakoRenderer()) 6603 impl_source_node = ListNode(tail="\n") 6604 impl_source_node.set_accumulator(CodeGenAccumulator()) 6605 impl_source_node.set_renderer(MakoRenderer()) 6606 else: 6607 impl_header_node = api_header_node 6608 impl_source_node = api_source_node 6609 6610 # Namespaces 6611 api_header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) 6612 api_source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) 6613 if is_cross_components: 6614 impl_header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) 6615 impl_source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) 6616 else: 6617 impl_header_blink_ns = api_header_blink_ns 6618 impl_source_blink_ns = api_source_blink_ns 6619 6620 # Class definitions 6621 api_class_def = CxxClassDefNode( 6622 cg_context.class_name, 6623 base_class_names=[ 6624 _format("bindings::V8InterfaceBridge<${class_name}, {}>", 6625 blink_class_name(class_like)), 6626 ], 6627 final=True, 6628 export=component_export(api_component, for_testing)) 6629 api_class_def.set_base_template_vars(cg_context.template_bindings()) 6630 api_class_def.bottom_section.append( 6631 TextNode("friend class {};".format(blink_class_name(class_like)))) 6632 if is_cross_components: 6633 impl_class_def = CxxClassDefNode(impl_class_name, 6634 final=True, 6635 export=component_export( 6636 impl_component, for_testing)) 6637 impl_class_def.set_base_template_vars(cg_context.template_bindings()) 6638 api_class_def.public_section.extend([ 6639 TextNode("// Cross-component implementation class"), 6640 TextNode("class Impl;"), 6641 EmptyNode(), 6642 ]) 6643 else: 6644 impl_class_def = api_class_def 6645 6646 # Constants 6647 constants_def = None 6648 if class_like.constants: 6649 constants_def = CxxClassDefNode(name="Constant", final=True) 6650 constants_def.top_section.append(TextNode("STATIC_ONLY(Constant);")) 6651 for constant in class_like.constants: 6652 cgc = cg_context.make_copy(constant=constant) 6653 constants_def.public_section.append( 6654 make_constant_constant_def(cgc, constant_name(cgc))) 6655 6656 # Custom callback implementations 6657 custom_callback_impl_decls = ListNode() 6658 6659 def add_custom_callback_impl_decl(**params): 6660 arg_decls = params.pop("arg_decls") 6661 name = params.pop("name", None) 6662 if name is None: 6663 name = custom_function_name(cg_context.make_copy(**params)) 6664 custom_callback_impl_decls.append( 6665 CxxFuncDeclNode( 6666 name=name, 6667 arg_decls=arg_decls, 6668 return_type="void", 6669 static=True)) 6670 6671 if class_like.identifier == "HTMLAllCollection": 6672 add_custom_callback_impl_decl( 6673 name=name_style.func("LegacyCallCustom"), 6674 arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"]) 6675 for attribute in class_like.attributes: 6676 custom_values = attribute.extended_attributes.values_of("Custom") 6677 is_cross_origin = "CrossOrigin" in attribute.extended_attributes 6678 cross_origin_values = attribute.extended_attributes.values_of( 6679 "CrossOrigin") 6680 if "Getter" in custom_values: 6681 add_custom_callback_impl_decl( 6682 attribute=attribute, 6683 attribute_get=True, 6684 arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"]) 6685 if is_cross_origin and (not cross_origin_values 6686 or "Getter" in cross_origin_values): 6687 add_custom_callback_impl_decl( 6688 attribute=attribute, 6689 attribute_get=True, 6690 arg_decls=["const v8::PropertyCallbackInfo<v8::Value>&"]) 6691 if "Setter" in custom_values: 6692 add_custom_callback_impl_decl( 6693 attribute=attribute, 6694 attribute_set=True, 6695 arg_decls=[ 6696 "v8::Local<v8::Value>", 6697 "const v8::FunctionCallbackInfo<v8::Value>&", 6698 ]) 6699 if is_cross_origin and (not cross_origin_values 6700 or "Setter" in cross_origin_values): 6701 add_custom_callback_impl_decl( 6702 attribute=attribute, 6703 attribute_set=True, 6704 arg_decls=[ 6705 "v8::Local<v8::Value>", 6706 "const v8::PropertyCallbackInfo<void>&", 6707 ]) 6708 for operation_group in class_like.operation_groups: 6709 if "Custom" in operation_group.extended_attributes: 6710 add_custom_callback_impl_decl( 6711 operation_group=operation_group, 6712 arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"]) 6713 if interface and interface.indexed_and_named_properties: 6714 props = interface.indexed_and_named_properties 6715 operation = props.own_named_getter 6716 if operation and "Custom" in operation.extended_attributes: 6717 add_custom_callback_impl_decl( 6718 named_property_getter=operation, 6719 arg_decls=[ 6720 "const AtomicString& property_name", 6721 "const v8::PropertyCallbackInfo<v8::Value>&", 6722 ]) 6723 operation = props.own_named_setter 6724 if operation and "Custom" in operation.extended_attributes: 6725 add_custom_callback_impl_decl( 6726 named_property_setter=operation, 6727 arg_decls=[ 6728 "const AtomicString& property_name", 6729 "v8::Local<v8::Value> v8_property_value", 6730 "const v8::PropertyCallbackInfo<v8::Value>&", 6731 ]) 6732 operation = props.own_named_deleter 6733 if operation and "Custom" in operation.extended_attributes: 6734 add_custom_callback_impl_decl( 6735 named_property_deleter=operation, 6736 arg_decls=[ 6737 "const AtomicString& property_name", 6738 "const v8::PropertyCallbackInfo<v8::Value>&", 6739 ]) 6740 6741 # Cross-component trampolines 6742 if is_cross_components: 6743 # tp_ = trampoline name 6744 tp_install_interface_template = TP_INSTALL_INTERFACE_TEMPLATE 6745 tp_install_unconditional_props = TP_INSTALL_UNCONDITIONAL_PROPS 6746 tp_install_context_independent_props = ( 6747 TP_INSTALL_CONTEXT_INDEPENDENT_PROPS) 6748 tp_install_context_dependent_props = TP_INSTALL_CONTEXT_DEPENDENT_PROPS 6749 else: 6750 tp_install_interface_template = None 6751 tp_install_unconditional_props = None 6752 tp_install_context_independent_props = None 6753 tp_install_context_dependent_props = None 6754 6755 # Callback functions 6756 attribute_entries = [] 6757 constant_entries = [] 6758 constructor_entries = [] 6759 exposed_construct_entries = [] 6760 operation_entries = [] 6761 callback_defs = make_property_entries_and_callback_defs( 6762 cg_context, 6763 attribute_entries=attribute_entries, 6764 constant_entries=constant_entries, 6765 constructor_entries=constructor_entries, 6766 exposed_construct_entries=exposed_construct_entries, 6767 operation_entries=operation_entries) 6768 supplemental_install_node = SequenceNode() 6769 6770 # Indexed and named properties 6771 # Shorten a function name to mitigate a style check error. 6772 f = make_indexed_and_named_property_callbacks_and_install_node 6773 (indexed_and_named_property_decls, indexed_and_named_property_defs, 6774 indexed_and_named_property_install_node) = f(cg_context) 6775 supplemental_install_node.append(indexed_and_named_property_install_node) 6776 supplemental_install_node.append(EmptyNode()) 6777 6778 # Named properties object 6779 (named_properties_object_callback_defs, 6780 named_properties_object_install_node) = ( 6781 make_named_properties_object_callbacks_and_install_node(cg_context)) 6782 callback_defs.extend(named_properties_object_callback_defs) 6783 supplemental_install_node.append(named_properties_object_install_node) 6784 supplemental_install_node.append(EmptyNode()) 6785 6786 # Cross origin properties 6787 (cross_origin_property_callback_defs, 6788 cross_origin_property_install_node) = ( 6789 make_cross_origin_property_callbacks_and_install_node( 6790 cg_context, attribute_entries, operation_entries)) 6791 callback_defs.extend(cross_origin_property_callback_defs) 6792 supplemental_install_node.append(cross_origin_property_install_node) 6793 supplemental_install_node.append(EmptyNode()) 6794 6795 # Installer functions 6796 is_unconditional = lambda entry: entry.exposure_conditional.is_always_true 6797 is_context_dependent = lambda entry: entry.is_context_dependent 6798 is_context_independent = ( 6799 lambda e: not is_context_dependent(e) and not is_unconditional(e)) 6800 (install_unconditional_props_decl, install_unconditional_props_def, 6801 install_unconditional_props_trampoline) = make_install_properties( 6802 cg_context, 6803 FN_INSTALL_UNCONDITIONAL_PROPS, 6804 class_name=impl_class_name, 6805 prop_install_mode=PropInstallMode.UNCONDITIONAL, 6806 trampoline_var_name=tp_install_unconditional_props, 6807 attribute_entries=filter(is_unconditional, attribute_entries), 6808 constant_entries=filter(is_unconditional, constant_entries), 6809 exposed_construct_entries=filter(is_unconditional, 6810 exposed_construct_entries), 6811 operation_entries=filter(is_unconditional, operation_entries)) 6812 (install_context_independent_props_decl, 6813 install_context_independent_props_def, 6814 install_context_independent_props_trampoline) = make_install_properties( 6815 cg_context, 6816 FN_INSTALL_CONTEXT_INDEPENDENT_PROPS, 6817 class_name=impl_class_name, 6818 prop_install_mode=PropInstallMode.CONTEXT_INDEPENDENT, 6819 trampoline_var_name=tp_install_context_independent_props, 6820 attribute_entries=filter(is_context_independent, attribute_entries), 6821 constant_entries=filter(is_context_independent, constant_entries), 6822 exposed_construct_entries=filter(is_context_independent, 6823 exposed_construct_entries), 6824 operation_entries=filter(is_context_independent, operation_entries)) 6825 (install_context_dependent_props_decl, install_context_dependent_props_def, 6826 install_context_dependent_props_trampoline) = make_install_properties( 6827 cg_context, 6828 FN_INSTALL_CONTEXT_DEPENDENT_PROPS, 6829 class_name=impl_class_name, 6830 prop_install_mode=PropInstallMode.CONTEXT_DEPENDENT, 6831 trampoline_var_name=tp_install_context_dependent_props, 6832 attribute_entries=filter(is_context_dependent, attribute_entries), 6833 constant_entries=filter(is_context_dependent, constant_entries), 6834 exposed_construct_entries=filter(is_context_dependent, 6835 exposed_construct_entries), 6836 operation_entries=filter(is_context_dependent, operation_entries)) 6837 (install_interface_template_decl, install_interface_template_def, 6838 install_interface_template_trampoline) = make_install_interface_template( 6839 cg_context, 6840 FN_INSTALL_INTERFACE_TEMPLATE, 6841 class_name=impl_class_name, 6842 trampoline_var_name=tp_install_interface_template, 6843 constructor_entries=constructor_entries, 6844 supplemental_install_node=supplemental_install_node, 6845 install_unconditional_func_name=(install_unconditional_props_def 6846 and FN_INSTALL_UNCONDITIONAL_PROPS), 6847 install_context_independent_func_name=( 6848 install_context_independent_props_def 6849 and FN_INSTALL_CONTEXT_INDEPENDENT_PROPS)) 6850 installer_function_decls = ListNode([ 6851 install_interface_template_decl, 6852 install_unconditional_props_decl, 6853 install_context_independent_props_decl, 6854 install_context_dependent_props_decl, 6855 ]) 6856 installer_function_defs = ListNode([ 6857 install_interface_template_def, 6858 EmptyNode(), 6859 install_unconditional_props_def, 6860 EmptyNode(), 6861 install_context_independent_props_def, 6862 EmptyNode(), 6863 install_context_dependent_props_def, 6864 ]) 6865 installer_function_trampolines = ListNode([ 6866 install_interface_template_trampoline, 6867 install_unconditional_props_trampoline, 6868 install_context_independent_props_trampoline, 6869 install_context_dependent_props_trampoline, 6870 ]) 6871 6872 # WrapperTypeInfo 6873 (get_wrapper_type_info_def, wrapper_type_info_var_def, 6874 wrapper_type_info_init) = make_wrapper_type_info( 6875 cg_context, 6876 "GetWrapperTypeInfo", 6877 has_context_dependent_props=bool( 6878 install_context_dependent_props_decl)) 6879 6880 # Cross-component trampolines 6881 if is_cross_components: 6882 (cross_component_init_decl, cross_component_init_def, 6883 trampoline_var_decls, 6884 trampoline_var_defs) = make_cross_component_init( 6885 cg_context, 6886 "Init", 6887 class_name=impl_class_name, 6888 has_unconditional_props=bool(install_unconditional_props_decl), 6889 has_context_independent_props=bool( 6890 install_context_independent_props_decl), 6891 has_context_dependent_props=bool( 6892 install_context_dependent_props_decl)) 6893 6894 # V8 Context Snapshot 6895 (header_v8_context_snapshot_ns, 6896 source_v8_context_snapshot_ns) = make_v8_context_snapshot_api( 6897 cg_context, impl_component, attribute_entries, constant_entries, 6898 constructor_entries, exposed_construct_entries, operation_entries, 6899 named_properties_object_callback_defs, 6900 cross_origin_property_callback_defs, 6901 (install_context_independent_props_def 6902 and FN_INSTALL_CONTEXT_INDEPENDENT_PROPS)) 6903 6904 # Header part (copyright, include directives, and forward declarations) 6905 api_header_node.extend([ 6906 make_copyright_header(), 6907 EmptyNode(), 6908 enclose_with_header_guard( 6909 ListNode([ 6910 make_header_include_directives(api_header_node.accumulator), 6911 EmptyNode(), 6912 api_header_blink_ns, 6913 ]), name_style.header_guard(api_header_path)), 6914 ]) 6915 api_header_blink_ns.body.extend([ 6916 make_forward_declarations(api_header_node.accumulator), 6917 EmptyNode(), 6918 ]) 6919 api_source_node.extend([ 6920 make_copyright_header(), 6921 EmptyNode(), 6922 TextNode("#include \"{}\"".format(api_header_path)), 6923 EmptyNode(), 6924 make_header_include_directives(api_source_node.accumulator), 6925 EmptyNode(), 6926 api_source_blink_ns, 6927 ]) 6928 api_source_blink_ns.body.extend([ 6929 make_forward_declarations(api_source_node.accumulator), 6930 EmptyNode(), 6931 ]) 6932 if is_cross_components: 6933 impl_header_node.extend([ 6934 make_copyright_header(), 6935 EmptyNode(), 6936 enclose_with_header_guard( 6937 ListNode([ 6938 make_header_include_directives( 6939 impl_header_node.accumulator), 6940 EmptyNode(), 6941 impl_header_blink_ns, 6942 ]), name_style.header_guard(impl_header_path)), 6943 ]) 6944 impl_header_blink_ns.body.extend([ 6945 make_forward_declarations(impl_header_node.accumulator), 6946 EmptyNode(), 6947 ]) 6948 impl_source_node.extend([ 6949 make_copyright_header(), 6950 EmptyNode(), 6951 TextNode("#include \"{}\"".format(impl_header_path)), 6952 EmptyNode(), 6953 make_header_include_directives(impl_source_node.accumulator), 6954 EmptyNode(), 6955 impl_source_blink_ns, 6956 ]) 6957 impl_source_blink_ns.body.extend([ 6958 make_forward_declarations(impl_source_node.accumulator), 6959 EmptyNode(), 6960 ]) 6961 api_header_node.accumulator.add_include_headers([ 6962 class_like.code_generator_info.blink_headers[0], 6963 component_export_header(api_component, for_testing), 6964 "third_party/blink/renderer/platform/bindings/v8_interface_bridge.h", 6965 ]) 6966 if interface and interface.inherited: 6967 api_source_node.accumulator.add_include_headers( 6968 [PathManager(interface.inherited).api_path(ext="h")]) 6969 if is_cross_components: 6970 impl_header_node.accumulator.add_include_headers([ 6971 api_header_path, 6972 component_export_header(impl_component, for_testing), 6973 ]) 6974 impl_source_node.accumulator.add_include_headers([ 6975 "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h", 6976 "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h", 6977 "third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h", 6978 "third_party/blink/renderer/platform/bindings/exception_messages.h", 6979 "third_party/blink/renderer/platform/bindings/idl_member_installer.h", 6980 "third_party/blink/renderer/platform/bindings/runtime_call_stats.h", 6981 "third_party/blink/renderer/platform/bindings/v8_binding.h", 6982 ]) 6983 impl_source_node.accumulator.add_include_headers( 6984 _collect_include_headers(class_like)) 6985 6986 # Assemble the parts. 6987 api_header_blink_ns.body.extend([ 6988 api_class_def, 6989 EmptyNode(), 6990 ]) 6991 if is_cross_components: 6992 impl_header_blink_ns.body.extend([ 6993 impl_class_def, 6994 EmptyNode(), 6995 ]) 6996 6997 if constants_def: 6998 api_class_def.public_section.extend([ 6999 TextNode("// Constants"), 7000 constants_def, 7001 EmptyNode(), 7002 ]) 7003 7004 api_class_def.public_section.append(get_wrapper_type_info_def) 7005 api_class_def.public_section.append(EmptyNode()) 7006 api_class_def.private_section.append(wrapper_type_info_var_def) 7007 api_class_def.private_section.append(EmptyNode()) 7008 api_source_blink_ns.body.extend([ 7009 wrapper_type_info_init, 7010 EmptyNode(), 7011 ]) 7012 7013 if is_cross_components: 7014 api_class_def.public_section.append(installer_function_trampolines) 7015 api_class_def.public_section.append(EmptyNode()) 7016 api_class_def.private_section.extend([ 7017 TextNode("// Cross-component trampolines"), 7018 trampoline_var_decls, 7019 EmptyNode(), 7020 ]) 7021 api_source_blink_ns.body.extend([ 7022 TextNode("// Cross-component trampolines"), 7023 trampoline_var_defs, 7024 EmptyNode(), 7025 ]) 7026 impl_class_def.public_section.append(cross_component_init_decl) 7027 impl_class_def.private_section.append(installer_function_decls) 7028 impl_source_blink_ns.body.extend([ 7029 cross_component_init_def, 7030 EmptyNode(), 7031 ]) 7032 else: 7033 api_class_def.public_section.append(installer_function_decls) 7034 api_class_def.public_section.append(EmptyNode()) 7035 7036 if custom_callback_impl_decls: 7037 api_class_def.public_section.extend([ 7038 TextNode("// Custom callback implementations"), 7039 custom_callback_impl_decls, 7040 EmptyNode(), 7041 ]) 7042 7043 if indexed_and_named_property_decls: 7044 api_class_def.public_section.extend([ 7045 TextNode("// Indexed properties and named properties"), 7046 indexed_and_named_property_decls, 7047 EmptyNode(), 7048 ]) 7049 api_source_blink_ns.body.extend([ 7050 indexed_and_named_property_defs, 7051 EmptyNode(), 7052 ]) 7053 7054 impl_source_blink_ns.body.extend([ 7055 CxxNamespaceNode(name="", body=callback_defs), 7056 EmptyNode(), 7057 installer_function_defs, 7058 EmptyNode(), 7059 ]) 7060 7061 if header_v8_context_snapshot_ns: 7062 impl_header_blink_ns.body.extend([ 7063 CxxNamespaceNode(name=name_style.namespace("bindings"), 7064 body=header_v8_context_snapshot_ns), 7065 EmptyNode(), 7066 ]) 7067 impl_source_blink_ns.body.extend([ 7068 CxxNamespaceNode(name=name_style.namespace("bindings"), 7069 body=source_v8_context_snapshot_ns), 7070 EmptyNode(), 7071 ]) 7072 7073 # Write down to the files. 7074 write_code_node_to_file(api_header_node, 7075 path_manager.gen_path_to(api_header_path)) 7076 write_code_node_to_file(api_source_node, 7077 path_manager.gen_path_to(api_source_path)) 7078 if path_manager.is_cross_components: 7079 write_code_node_to_file(impl_header_node, 7080 path_manager.gen_path_to(impl_header_path)) 7081 write_code_node_to_file(impl_source_node, 7082 path_manager.gen_path_to(impl_source_path)) 7083 7084 7085def generate_interface(interface_identifier): 7086 assert isinstance(interface_identifier, web_idl.Identifier) 7087 7088 web_idl_database = package_initializer().web_idl_database() 7089 interface = web_idl_database.find(interface_identifier) 7090 7091 generate_class_like(interface) 7092 7093 7094def generate_install_properties_per_feature(function_name, 7095 filepath_basename, 7096 for_testing=False): 7097 assert isinstance(function_name, str) 7098 assert isinstance(filepath_basename, str) 7099 assert isinstance(for_testing, bool) 7100 7101 web_idl_database = package_initializer().web_idl_database() 7102 7103 # Filepaths 7104 header_path = PathManager.component_path("modules", 7105 "{}.h".format(filepath_basename)) 7106 source_path = PathManager.component_path("modules", 7107 "{}.cc".format(filepath_basename)) 7108 7109 # Root nodes 7110 header_node = ListNode(tail="\n") 7111 header_node.set_accumulator(CodeGenAccumulator()) 7112 header_node.set_renderer(MakoRenderer()) 7113 source_node = ListNode(tail="\n") 7114 source_node.set_accumulator(CodeGenAccumulator()) 7115 source_node.set_renderer(MakoRenderer()) 7116 7117 # Namespaces 7118 header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) 7119 source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) 7120 header_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings")) 7121 source_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings")) 7122 header_blink_ns.body.extend([ 7123 make_forward_declarations(header_node.accumulator), 7124 EmptyNode(), 7125 header_bindings_ns, 7126 ]) 7127 source_blink_ns.body.append(source_bindings_ns) 7128 7129 # Function nodes 7130 arg_decls = [ 7131 "ScriptState* script_state", 7132 "OriginTrialFeature feature", 7133 ] 7134 func_decl = CxxFuncDeclNode( 7135 name=function_name, arg_decls=arg_decls, return_type="void") 7136 func_def = CxxFuncDefNode( 7137 name=function_name, arg_decls=arg_decls, return_type="void") 7138 func_def.body.add_template_vars({ 7139 "script_state": "script_state", 7140 "feature": "feature", 7141 }) 7142 helper_func_def = CxxFuncDefNode( 7143 name="InstallPropertiesPerFeatureInternal", 7144 arg_decls=[ 7145 "ScriptState* script_state", 7146 "OriginTrialFeature feature", 7147 "base::span<const WrapperTypeInfo* const> wrapper_type_info_list", 7148 ], 7149 return_type="void") 7150 7151 # Assemble the parts. 7152 header_node.accumulator.add_class_decls(["ScriptState"]) 7153 header_node.accumulator.add_include_headers([ 7154 "third_party/blink/renderer/platform/runtime_enabled_features.h", 7155 ]) 7156 header_node.extend([ 7157 make_copyright_header(), 7158 EmptyNode(), 7159 enclose_with_header_guard( 7160 ListNode([ 7161 make_header_include_directives(header_node.accumulator), 7162 EmptyNode(), 7163 header_blink_ns, 7164 ]), name_style.header_guard(header_path)), 7165 ]) 7166 source_node.accumulator.add_include_headers([ 7167 "base/containers/span.h", 7168 "third_party/blink/renderer/platform/bindings/script_state.h", 7169 "third_party/blink/renderer/platform/bindings/v8_per_context_data.h", 7170 ]) 7171 source_node.extend([ 7172 make_copyright_header(), 7173 EmptyNode(), 7174 TextNode("#include \"{}\"".format(header_path)), 7175 EmptyNode(), 7176 make_header_include_directives(source_node.accumulator), 7177 EmptyNode(), 7178 source_blink_ns, 7179 ]) 7180 header_bindings_ns.body.extend([ 7181 TextNode("""\ 7182// Install ES properties associated with the given origin trial feature.\ 7183"""), 7184 func_decl, 7185 ]) 7186 source_bindings_ns.body.extend([ 7187 CxxNamespaceNode(name="", body=helper_func_def), 7188 EmptyNode(), 7189 func_def, 7190 ]) 7191 7192 # The public function 7193 feature_to_class_likes = {} 7194 set_of_class_likes = set() 7195 for class_like in itertools.chain(web_idl_database.interfaces, 7196 web_idl_database.namespaces): 7197 if class_like.code_generator_info.for_testing != for_testing: 7198 continue 7199 7200 for member in itertools.chain(class_like.attributes, 7201 class_like.constants, 7202 class_like.operation_groups, 7203 class_like.exposed_constructs): 7204 features = list( 7205 member.exposure.context_dependent_runtime_enabled_features) 7206 for entry in member.exposure.global_names_and_features: 7207 if entry.feature and entry.feature.is_context_dependent: 7208 features.append(entry.feature) 7209 for feature in features: 7210 feature_to_class_likes.setdefault(feature, 7211 set()).add(class_like) 7212 if features: 7213 set_of_class_likes.add(class_like) 7214 7215 switch_node = CxxSwitchNode(cond="${feature}") 7216 switch_node.append( 7217 case=None, 7218 body=[ 7219 TextNode("// Ignore unknown, deprecated, and unused features."), 7220 TextNode("return;"), 7221 ], 7222 should_add_break=False) 7223 for feature, class_likes in sorted(feature_to_class_likes.items()): 7224 entries = [ 7225 TextNode("{}::GetWrapperTypeInfo(), ".format( 7226 v8_bridge_class_name(class_like))) 7227 for class_like in sorted(class_likes, key=lambda x: x.identifier) 7228 ] 7229 table_def = ListNode([ 7230 TextNode("static const WrapperTypeInfo* const wti_list[] = {"), 7231 ListNode(entries), 7232 TextNode("};"), 7233 ]) 7234 switch_node.append( 7235 case="OriginTrialFeature::k{}".format(feature), 7236 body=[ 7237 table_def, 7238 TextNode("selected_wti_list = wti_list;"), 7239 ]) 7240 7241 func_def.body.extend([ 7242 TextNode( 7243 "base::span<const WrapperTypeInfo* const> selected_wti_list;"), 7244 EmptyNode(), 7245 switch_node, 7246 EmptyNode(), 7247 TextNode("InstallPropertiesPerFeatureInternal" 7248 "(${script_state}, ${feature}, selected_wti_list);"), 7249 ]) 7250 7251 for class_like in set_of_class_likes: 7252 path_manager = PathManager(class_like) 7253 source_node.accumulator.add_include_headers( 7254 [path_manager.api_path(ext="h")]) 7255 7256 # The helper function 7257 helper_func_def.body.append( 7258 TextNode("""\ 7259V8PerContextData* per_context_data = script_state->PerContextData(); 7260v8::Isolate* isolate = script_state->GetIsolate(); 7261v8::Local<v8::Context> context = script_state->GetContext(); 7262const DOMWrapperWorld& world = script_state->World(); 7263V8InterfaceBridgeBase::FeatureSelector feature_selector(feature); 7264 7265for (const auto* wrapper_type_info : wrapper_type_info_list) { 7266 v8::Local<v8::Object> instance_object; 7267 v8::Local<v8::Object> prototype_object; 7268 v8::Local<v8::Function> interface_object; 7269 v8::Local<v8::Template> interface_template = 7270 wrapper_type_info->GetV8ClassTemplate(isolate, world); 7271 7272 switch (wrapper_type_info->idl_definition_kind) { 7273 case WrapperTypeInfo::kIdlInterface: 7274 if (!per_context_data->GetExistingConstructorAndPrototypeForType( 7275 wrapper_type_info, &prototype_object, &interface_object)) { 7276 continue; 7277 } 7278 break; 7279 case WrapperTypeInfo::kIdlNamespace: 7280 NOTIMPLEMENTED(); 7281 break; 7282 default: 7283 NOTREACHED(); 7284 } 7285 7286 wrapper_type_info->install_context_dependent_props_func( 7287 context, world, instance_object, prototype_object, interface_object, 7288 interface_template, feature_selector); 7289}\ 7290""")) 7291 7292 # Write down to the files. 7293 write_code_node_to_file(header_node, path_manager.gen_path_to(header_path)) 7294 write_code_node_to_file(source_node, path_manager.gen_path_to(source_path)) 7295 7296 7297def generate_init_idl_interfaces(function_name, 7298 filepath_basename, 7299 for_testing=False): 7300 assert isinstance(function_name, str) 7301 assert isinstance(filepath_basename, str) 7302 assert isinstance(for_testing, bool) 7303 7304 web_idl_database = package_initializer().web_idl_database() 7305 7306 # Filepaths 7307 header_path = PathManager.component_path("modules", 7308 "{}.h".format(filepath_basename)) 7309 source_path = PathManager.component_path("modules", 7310 "{}.cc".format(filepath_basename)) 7311 7312 # Root nodes 7313 header_node = ListNode(tail="\n") 7314 header_node.set_accumulator(CodeGenAccumulator()) 7315 header_node.set_renderer(MakoRenderer()) 7316 source_node = ListNode(tail="\n") 7317 source_node.set_accumulator(CodeGenAccumulator()) 7318 source_node.set_renderer(MakoRenderer()) 7319 7320 # Namespaces 7321 header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) 7322 source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) 7323 header_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings")) 7324 source_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings")) 7325 header_blink_ns.body.append(header_bindings_ns) 7326 source_blink_ns.body.append(source_bindings_ns) 7327 7328 # Function nodes 7329 func_decl = CxxFuncDeclNode( 7330 name=function_name, arg_decls=[], return_type="void") 7331 func_def = CxxFuncDefNode( 7332 name=function_name, arg_decls=[], return_type="void") 7333 header_bindings_ns.body.extend([ 7334 TextNode("""\ 7335// Initializes cross-component trampolines of IDL interface / namespace.\ 7336"""), 7337 func_decl, 7338 ]) 7339 source_bindings_ns.body.append(func_def) 7340 7341 # Assemble the parts. 7342 header_node.extend([ 7343 make_copyright_header(), 7344 EmptyNode(), 7345 enclose_with_header_guard( 7346 ListNode([ 7347 make_header_include_directives(header_node.accumulator), 7348 EmptyNode(), 7349 header_blink_ns, 7350 ]), name_style.header_guard(header_path)), 7351 ]) 7352 source_node.extend([ 7353 make_copyright_header(), 7354 EmptyNode(), 7355 TextNode("#include \"{}\"".format(header_path)), 7356 EmptyNode(), 7357 make_header_include_directives(source_node.accumulator), 7358 EmptyNode(), 7359 source_blink_ns, 7360 ]) 7361 7362 init_calls = [] 7363 for class_like in itertools.chain(web_idl_database.interfaces, 7364 web_idl_database.namespaces): 7365 if class_like.code_generator_info.for_testing != for_testing: 7366 continue 7367 7368 path_manager = PathManager(class_like) 7369 if path_manager.is_cross_components: 7370 source_node.accumulator.add_include_headers( 7371 [path_manager.impl_path(ext="h")]) 7372 7373 class_name = v8_bridge_class_name(class_like) 7374 init_calls.append(_format("{}::Impl::Init();", class_name)) 7375 for init_call in sorted(init_calls): 7376 func_def.body.append(TextNode(init_call)) 7377 7378 # Write down to the files. 7379 write_code_node_to_file(header_node, path_manager.gen_path_to(header_path)) 7380 write_code_node_to_file(source_node, path_manager.gen_path_to(source_path)) 7381 7382 7383def generate_interfaces(task_queue): 7384 assert isinstance(task_queue, TaskQueue) 7385 7386 web_idl_database = package_initializer().web_idl_database() 7387 7388 for interface in web_idl_database.interfaces: 7389 task_queue.post_task(generate_interface, interface.identifier) 7390 7391 task_queue.post_task(generate_install_properties_per_feature, 7392 "InstallPropertiesPerFeature", 7393 "properties_per_feature_installer") 7394 task_queue.post_task(generate_install_properties_per_feature, 7395 "InstallPropertiesPerFeatureForTesting", 7396 "properties_per_feature_installer_for_testing", 7397 for_testing=True) 7398 task_queue.post_task(generate_init_idl_interfaces, "InitIDLInterfaces", 7399 "init_idl_interfaces") 7400 task_queue.post_task(generate_init_idl_interfaces, 7401 "InitIDLInterfacesForTesting", 7402 "init_idl_interfaces_for_testing", 7403 for_testing=True) 7404