2 # Copyright (C) 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
4 # Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
5 # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
6 # Copyright (C) 2006-2010, 2013-2016 Apple Inc. All rights reserved.
7 # Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
8 # Copyright (C) Research In Motion Limited 2010. All rights reserved.
9 # Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
10 # Copyright (C) 2011 Patrick Gansterer <paroga@webkit.org>
11 # Copyright (C) 2012 Ericsson AB. All rights reserved.
12 # Copyright (C) 2007, 2008, 2009, 2012 Google Inc.
13 # Copyright (C) 2013 Samsung Electronics. All rights reserved.
14 # Copyright (C) 2015, 2016 Canon Inc. All rights reserved.
16 # This library is free software; you can redistribute it and/or
17 # modify it under the terms of the GNU Library General Public
18 # License as published by the Free Software Foundation; either
19 # version 2 of the License, or (at your option) any later version.
21 # This library is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 # Library General Public License for more details.
26 # You should have received a copy of the GNU Library General Public License
27 # along with this library; see the file COPYING.LIB. If not, write to
28 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29 # Boston, MA 02110-1301, USA.
32 package CodeGeneratorJS;
35 use constant FileNamePrefix => "JS";
40 my @headerContentHeader = ();
41 my @headerContent = ();
42 my %headerIncludes = ();
43 my %headerTrailingIncludes = ();
45 my @implContentHeader = ();
47 my %implIncludes = ();
49 my $numCachedAttributes = 0;
50 my $currentCachedAttribute = 0;
52 my $beginAppleCopyrightForHeaderFiles = <<END;
53 // ------- Begin Apple Copyright -------
55 * Copyright (C) 2008, Apple Inc. All rights reserved.
57 * Permission is granted by Apple to use this file to the extent
58 * necessary to relink with LGPL WebKit files.
60 * No license or rights are granted by Apple expressly or by
61 * implication, estoppel, or otherwise, to Apple patents and
62 * trademarks. For the sake of clarity, no license or rights are
63 * granted by Apple expressly or by implication, estoppel, or otherwise,
64 * under any Apple patents, copyrights and trademarks to underlying
65 * implementations of any application programming interfaces (APIs)
66 * or to any functionality that is invoked by calling any API.
70 my $beginAppleCopyrightForSourceFiles = <<END;
71 // ------- Begin Apple Copyright -------
73 * Copyright (C) 2008, Apple Inc. All rights reserved.
75 * No license or rights are granted by Apple expressly or by implication,
76 * estoppel, or otherwise, to Apple copyrights, patents, trademarks, trade
77 * secrets or other rights.
81 my $endAppleCopyright = <<END;
82 // ------- End Apple Copyright -------
87 my $headerTemplate = << "EOF";
89 This file is part of the WebKit open source project.
90 This file has been generated by generate-bindings.pl. DO NOT MODIFY!
92 This library is free software; you can redistribute it and/or
93 modify it under the terms of the GNU Library General Public
94 License as published by the Free Software Foundation; either
95 version 2 of the License, or (at your option) any later version.
97 This library is distributed in the hope that it will be useful,
98 but WITHOUT ANY WARRANTY; without even the implied warranty of
99 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
100 Library General Public License for more details.
102 You should have received a copy of the GNU Library General Public License
103 along with this library; see the file COPYING.LIB. If not, write to
104 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
105 Boston, MA 02110-1301, USA.
109 # Default constructor
115 $codeGenerator = shift;
117 bless($reference, $object);
121 sub GenerateInterface
123 my ($object, $interface, $defines, $enumerations, $dictionaries) = @_;
125 $codeGenerator->LinkOverloadedFunctions($interface);
126 if ($interface->isCallback) {
127 $object->GenerateCallbackHeader($interface);
128 $object->GenerateCallbackImplementation($interface, $enumerations, $dictionaries);
130 $object->GenerateHeader($interface);
131 $object->GenerateImplementation($interface, $enumerations, $dictionaries);
135 sub EventHandlerAttributeEventName
137 my $attribute = shift;
138 my $eventType = $attribute->signature->extendedAttributes->{"ImplementedAs"} || $attribute->signature->name;
140 # Remove the "on" prefix.
141 $eventType = substr($eventType, 2);
143 return "eventNames().${eventType}Event";
146 sub GetParentClassName
148 my $interface = shift;
150 return $interface->extendedAttributes->{"JSLegacyParent"} if $interface->extendedAttributes->{"JSLegacyParent"};
151 return "JSDOMObject" unless NeedsImplementationClass($interface);
152 return "JSDOMWrapper<" . GetImplClassName($interface->name) . ">" unless $interface->parent;
153 return "JS" . $interface->parent;
156 sub GetCallbackClassName
158 my $className = shift;
160 return "JS$className";
163 sub GetJSCallbackDataType
165 my $callbackInterface = shift;
167 return $callbackInterface->extendedAttributes->{"IsWeakCallback"} ? "JSCallbackDataWeak" : "JSCallbackDataStrong";
170 sub AddIncludesForTypeInImpl
173 my $isCallback = @_ ? shift : 0;
175 AddIncludesForType($type, $isCallback, \%implIncludes);
178 sub AddIncludesForTypeInHeader
181 my $isCallback = @_ ? shift : 0;
183 AddIncludesForType($type, $isCallback, \%headerIncludes);
186 sub GetExportMacroForJSClass
188 my $interface = shift;
190 return $interface->extendedAttributes->{"ExportMacro"} . " " if $interface->extendedAttributes->{"ExportMacro"};
194 sub AddIncludesForType
197 my $isCallback = shift;
198 my $includesRef = shift;
200 return if $codeGenerator->SkipIncludeHeader($type);
202 # When we're finished with the one-file-per-class reorganization, we won't need these special cases.
203 if ($isCallback && $codeGenerator->IsWrapperType($type)) {
204 $includesRef->{"JS${type}.h"} = 1;
205 } elsif ($codeGenerator->GetArrayOrSequenceType($type)) {
206 my $arrayType = $codeGenerator->GetArrayType($type);
207 my $arrayOrSequenceType = $arrayType || $codeGenerator->GetSequenceType($type);
208 if ($arrayType eq "DOMString") {
209 $includesRef->{"JSDOMStringList.h"} = 1;
210 $includesRef->{"DOMStringList.h"} = 1;
211 } elsif ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) {
212 $includesRef->{"JS${arrayOrSequenceType}.h"} = 1;
213 $includesRef->{"${arrayOrSequenceType}.h"} = 1;
215 $includesRef->{"<runtime/JSArray.h>"} = 1;
217 # default, include the same named file
218 $includesRef->{"${type}.h"} = 1;
222 sub AddToImplIncludes
225 my $conditional = shift;
227 if (not $conditional) {
228 $implIncludes{$header} = 1;
229 } elsif (not exists($implIncludes{$header})) {
230 $implIncludes{$header} = $conditional;
232 my $oldValue = $implIncludes{$header};
233 $implIncludes{$header} = "$oldValue|$conditional" if $oldValue ne 1;
239 my $attribute = shift;
240 return $attribute->isReadOnly && !$attribute->signature->extendedAttributes->{"Replaceable"} && !$attribute->signature->extendedAttributes->{"PutForwards"};
243 sub AddClassForwardIfNeeded
245 my $interfaceName = shift;
247 # SVGAnimatedLength/Number/etc. are typedefs and should not be forward-declared as classes.
248 return if $codeGenerator->IsSVGAnimatedType($interfaceName);
250 return if $codeGenerator->IsTypedArrayType($interfaceName);
252 push(@headerContent, "class $interfaceName;\n\n");
255 sub GetGenerateIsReachable
257 my $interface = shift;
258 return $interface->extendedAttributes->{"GenerateIsReachable"};
261 sub GetCustomIsReachable
263 my $interface = shift;
264 return $interface->extendedAttributes->{"CustomIsReachable"};
267 sub IsDOMGlobalObject
269 my $interface = shift;
270 return $interface->name eq "DOMWindow" || $codeGenerator->InheritsInterface($interface, "WorkerGlobalScope") || $interface->name eq "TestGlobalObject";
273 sub ShouldUseGlobalObjectPrototype
275 my $interface = shift;
277 # For workers, the global object is a DedicatedWorkerGlobalScope.
278 return 0 if $interface->name eq "WorkerGlobalScope";
280 return IsDOMGlobalObject($interface);
283 sub GenerateGetOwnPropertySlotBody
285 my ($interface, $className, $inlined) = @_;
287 my $namespaceMaybe = ($inlined ? "JSC::" : "");
288 my $namedGetterFunction = GetNamedGetterFunction($interface);
289 my $indexedGetterFunction = GetIndexedGetterFunction($interface);
291 my @getOwnPropertySlotImpl = ();
293 my $ownPropertyCheck = sub {
294 push(@getOwnPropertySlotImpl, " if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot))\n");
295 push(@getOwnPropertySlotImpl, " return true;\n");
298 # FIXME: As per the Web IDL specification, the prototype check is supposed to skip "named properties objects":
299 # https://heycam.github.io/webidl/#dfn-named-property-visibility
300 # https://heycam.github.io/webidl/#dfn-named-properties-object
301 my $prototypeCheck = sub {
302 push(@getOwnPropertySlotImpl, " ${namespaceMaybe}JSValue proto = thisObject->getPrototypeDirect();\n");
303 push(@getOwnPropertySlotImpl, " if (proto.isObject() && jsCast<${namespaceMaybe}JSObject*>(proto)->hasProperty(state, propertyName))\n");
304 push(@getOwnPropertySlotImpl, " return false;\n\n");
307 if ($indexedGetterFunction) {
308 push(@getOwnPropertySlotImpl, " Optional<uint32_t> optionalIndex = parseIndex(propertyName);\n");
310 # If the item function returns a string then we let the TreatReturnedNullStringAs handle the cases
311 # where the index is out of range.
312 if ($indexedGetterFunction->signature->type eq "DOMString") {
313 push(@getOwnPropertySlotImpl, " if (optionalIndex) {\n");
315 push(@getOwnPropertySlotImpl, " if (optionalIndex && optionalIndex.value() < thisObject->wrapped().length()) {\n");
317 push(@getOwnPropertySlotImpl, " unsigned index = optionalIndex.value();\n");
318 # Assume that if there's a setter, the index will be writable
319 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
320 push(@getOwnPropertySlotImpl, " unsigned attributes = ${namespaceMaybe}DontDelete;\n");
322 push(@getOwnPropertySlotImpl, " unsigned attributes = ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly;\n");
324 push(@getOwnPropertySlotImpl, " slot.setValue(thisObject, attributes, " . GetIndexedGetterExpression($indexedGetterFunction) . ");\n");
325 push(@getOwnPropertySlotImpl, " return true;\n");
326 push(@getOwnPropertySlotImpl, " }\n");
329 my $hasNamedGetter = $namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"};
330 if ($hasNamedGetter) {
331 if (!$interface->extendedAttributes->{"OverrideBuiltins"}) {
332 &$ownPropertyCheck();
336 # The "thisObject->classInfo() == info()" check is to make sure we use the subclass' named getter
337 # instead of the base class one when possible.
338 if ($indexedGetterFunction) {
339 # Indexing an object with an integer that is not a supported property index should not call the named property getter.
340 # https://heycam.github.io/webidl/#idl-indexed-properties
341 push(@getOwnPropertySlotImpl, " if (!optionalIndex && thisObject->classInfo() == info()) {\n");
343 push(@getOwnPropertySlotImpl, " if (thisObject->classInfo() == info()) {\n");
345 push(@getOwnPropertySlotImpl, " JSValue value;\n");
346 push(@getOwnPropertySlotImpl, " if (thisObject->nameGetter(state, propertyName, value)) {\n");
347 push(@getOwnPropertySlotImpl, " slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, value);\n");
348 push(@getOwnPropertySlotImpl, " return true;\n");
349 push(@getOwnPropertySlotImpl, " }\n");
350 push(@getOwnPropertySlotImpl, " }\n");
352 $headerIncludes{"wtf/text/AtomicString.h"} = 1;
354 $implIncludes{"wtf/text/AtomicString.h"} = 1;
358 if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
359 push(@getOwnPropertySlotImpl, " if (thisObject->getOwnPropertySlotDelegate(state, propertyName, slot))\n");
360 push(@getOwnPropertySlotImpl, " return true;\n");
363 if (!$hasNamedGetter || $interface->extendedAttributes->{"OverrideBuiltins"}) {
364 &$ownPropertyCheck();
367 push(@getOwnPropertySlotImpl, " return false;\n");
369 return @getOwnPropertySlotImpl;
372 sub GenerateHeaderContentHeader
374 my $interface = shift;
375 my $className = "JS" . $interface->name;
377 my @headerContentHeader;
378 if ($interface->extendedAttributes->{"AppleCopyright"}) {
379 @headerContentHeader = split("\r", $beginAppleCopyrightForHeaderFiles);
381 @headerContentHeader = split("\r", $headerTemplate);
384 push(@headerContentHeader, "\n#pragma once\n\n");
386 my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
387 push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
388 return @headerContentHeader;
391 sub GenerateImplementationContentHeader
393 my $interface = shift;
394 my $className = "JS" . $interface->name;
396 my @implContentHeader;
397 if ($interface->extendedAttributes->{"AppleCopyright"}) {
398 @implContentHeader = split("\r", $beginAppleCopyrightForSourceFiles);
400 @implContentHeader = split("\r", $headerTemplate);
403 push(@implContentHeader, "\n#include \"config.h\"\n");
404 my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
405 push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;
406 push(@implContentHeader, "#include \"$className.h\"\n\n");
407 return @implContentHeader;
410 sub NeedsImplementationClass
412 my ($interface) = @_;
414 return 0 if $interface->extendedAttributes->{"JSBuiltin"};
418 sub ShouldGenerateToWrapped
420 my ($hasParent, $interface) = @_;
422 return 0 if not NeedsImplementationClass($interface);
423 return 1 if !$hasParent or $interface->extendedAttributes->{"JSGenerateToNativeObject"};
424 return 1 if $interface->parent && $interface->parent eq "EventTarget";
428 sub ShouldGenerateWrapperOwnerCode
430 my ($hasParent, $interface) = @_;
432 return 0 if not NeedsImplementationClass($interface);
434 GetGenerateIsReachable($interface) ||
435 GetCustomIsReachable($interface) ||
436 $interface->extendedAttributes->{"JSCustomFinalize"} ||
437 $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
443 sub ShouldGenerateToJSDeclaration
445 my ($hasParent, $interface) = @_;
447 return 0 if ($interface->extendedAttributes->{"SuppressToJSObject"});
448 return 0 if not NeedsImplementationClass($interface);
449 return 0 if $interface->name eq "AbstractView";
450 return 0 if $interface->extendedAttributes->{"CustomProxyToJSObject"};
451 return 1 if (!$hasParent or $interface->extendedAttributes->{"JSGenerateToJSObject"} or $interface->extendedAttributes->{"CustomToJSObject"});
452 return 1 if $interface->parent && $interface->parent eq "EventTarget";
453 return 1 if $interface->extendedAttributes->{"Constructor"} or $interface->extendedAttributes->{"NamedConstructor"};
457 sub ShouldGenerateToJSImplementation
459 my ($hasParent, $interface) = @_;
461 return 0 if not ShouldGenerateToJSDeclaration($hasParent, $interface);
462 return 1 if not $interface->extendedAttributes->{"CustomToJSObject"};
466 sub GetAttributeGetterName
468 my ($interface, $className, $attribute) = @_;
470 return $codeGenerator->WK_lcfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name) if $attribute->isStatic;
471 return GetJSBuiltinFunctionName($className, $attribute) if IsJSBuiltin($interface, $attribute);
472 return "js" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
475 sub GetAttributeSetterName
477 my ($interface, $className, $attribute) = @_;
479 return "set" . $codeGenerator->WK_ucfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name) if $attribute->isStatic;
480 return "set" . $codeGenerator->WK_ucfirst(GetJSBuiltinFunctionName($className, $attribute)) if IsJSBuiltin($interface, $attribute);
481 return "setJS" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
486 my ($interface, $className, $function) = @_;
488 return GetJSBuiltinFunctionName($className, $function) if IsJSBuiltin($interface, $function);
490 my $functionName = $function->signature->name;
491 $functionName = "SymbolIterator" if $functionName eq "[Symbol.Iterator]";
493 my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
494 return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($functionName);
497 sub GetSpecialAccessorFunctionForType
499 my $interface = shift;
501 my $firstParameterType = shift;
502 my $numberOfParameters = shift;
504 foreach my $function (@{$interface->functions}, @{$interface->anonymousFunctions}) {
505 my $specials = $function->signature->specials;
506 my $specialExists = grep { $_ eq $special } @$specials;
507 my $parameters = $function->parameters;
508 if ($specialExists and scalar(@$parameters) == $numberOfParameters and $parameters->[0]->type eq $firstParameterType) {
516 sub HasComplexGetOwnProperty
518 my $interface = shift;
520 my $namedGetterFunction = GetNamedGetterFunction($interface);
521 my $indexedGetterFunction = GetIndexedGetterFunction($interface);
523 my $hasNamedGetter = $namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"};
525 my $hasComplexGetter = $indexedGetterFunction
526 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
527 || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
530 return 1 if $interface->extendedAttributes->{"CheckSecurity"};
531 return 1 if IsDOMGlobalObject($interface);
532 return 1 if $hasComplexGetter;
537 sub InterfaceRequiresAttributesOnInstanceForCompatibility
539 my $interface = shift;
540 my $interfaceName = $interface->name;
542 # Needed for compatibility with existing content
543 return 1 if $interfaceName =~ "Touch";
548 sub InterfaceRequiresAttributesOnInstance
550 my $interface = shift;
551 my $interfaceName = $interface->name;
553 # FIXME: All these return 1 if ... should ideally be removed.
554 # Some of them are unavoidable due to DOM weirdness, in which case we should
555 # add an IDL attribute for them
557 # FIXME: We should be able to drop this once <rdar://problem/24466097> is fixed.
558 return 1 if $interface->isException;
560 # FIXME: Add support for [PrimaryGlobal] / [Global].
561 return 1 if IsDOMGlobalObject($interface) && $interface->name ne "WorkerGlobalScope";
563 return 1 if InterfaceRequiresAttributesOnInstanceForCompatibility($interface);
568 sub AttributeShouldBeOnInstance
570 my $interface = shift;
571 my $attribute = shift;
573 # FIXME: The bindings generator does not support putting runtime-enabled attributes on the instance yet (except for global objects).
574 return 0 if $attribute->signature->extendedAttributes->{"EnabledAtRuntime"} && !IsDOMGlobalObject($interface);
576 return 1 if InterfaceRequiresAttributesOnInstance($interface);
577 return 1 if $attribute->signature->type =~ /Constructor$/;
579 # [Unforgeable] attributes should be on the instance.
580 # https://heycam.github.io/webidl/#Unforgeable
581 return 1 if IsUnforgeable($interface, $attribute);
583 if ($interface->extendedAttributes->{"CheckSecurity"}) {
584 if ($attribute->signature->extendedAttributes->{"DoNotCheckSecurity"} or
585 $attribute->signature->extendedAttributes->{"DoNotCheckSecurityOnGetter"}) {
593 # https://heycam.github.io/webidl/#es-operations
594 sub OperationShouldBeOnInstance
596 my $interface = shift;
597 my $function = shift;
599 # FIXME: Add support for [PrimaryGlobal] / [Global].
600 return 1 if IsDOMGlobalObject($interface) && $interface->name ne "WorkerGlobalScope";
602 # FIXME: The bindings generator does not support putting runtime-enabled operations on the instance yet (except for global objects).
603 return 0 if $function->signature->extendedAttributes->{"EnabledAtRuntime"};
605 # [Unforgeable] operations should be on the instance. https://heycam.github.io/webidl/#Unforgeable
606 return 1 if IsUnforgeable($interface, $function);
611 sub GetJSCAttributesForAttribute
613 my $interface = shift;
614 my $attribute = shift;
617 push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute);
619 # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable.
620 my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
621 push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor);
622 push(@specials, "ReadOnly") if IsReadonly($attribute);
623 push(@specials, "CustomAccessor") unless $is_global_constructor or IsJSBuiltin($interface, $attribute);
624 push(@specials, "Accessor | Builtin") if IsJSBuiltin($interface, $attribute);
625 return (@specials > 0) ? join(" | ", @specials) : "0";
628 sub GetIndexedGetterFunction
630 my $interface = shift;
631 return GetSpecialAccessorFunctionForType($interface, "getter", "unsigned long", 1);
634 sub GetNamedGetterFunction
636 my $interface = shift;
637 return GetSpecialAccessorFunctionForType($interface, "getter", "DOMString", 1);
640 sub InstanceFunctionCount
642 my $interface = shift;
645 foreach my $function (@{$interface->functions}) {
646 $count++ if OperationShouldBeOnInstance($interface, $function);
652 sub PrototypeFunctionCount
654 my $interface = shift;
657 foreach my $function (@{$interface->functions}) {
658 $count++ if !$function->isStatic && !OperationShouldBeOnInstance($interface, $function);
661 $count += scalar @{$interface->iterable->functions} if $interface->iterable;
666 sub InstancePropertyCount
668 my $interface = shift;
670 foreach my $attribute (@{$interface->attributes}) {
671 $count++ if AttributeShouldBeOnInstance($interface, $attribute);
673 $count += InstanceFunctionCount($interface);
677 sub PrototypePropertyCount
679 my $interface = shift;
681 foreach my $attribute (@{$interface->attributes}) {
682 $count++ if !AttributeShouldBeOnInstance($interface, $attribute);
684 $count += PrototypeFunctionCount($interface);
685 $count++ if NeedsConstructorProperty($interface);
689 sub InstanceOverridesGetOwnPropertySlot
691 my $interface = shift;
693 my $namedGetterFunction = GetNamedGetterFunction($interface);
694 my $indexedGetterFunction = GetIndexedGetterFunction($interface);
696 my $hasNamedGetter = $namedGetterFunction
697 || $interface->extendedAttributes->{"CustomNamedGetter"};
699 my $hasComplexGetter = $indexedGetterFunction
700 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
701 || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
704 return $hasComplexGetter;
707 sub PrototypeHasStaticPropertyTable
709 my $interface = shift;
710 my $numPrototypeProperties = PrototypePropertyCount($interface);
711 my $numConstants = @{$interface->constants};
712 return $numConstants > 0 || $numPrototypeProperties > 0;
715 sub InstanceOverridesPutImplementation
717 my $interface = shift;
718 return $interface->extendedAttributes->{"CustomNamedSetter"}
719 || $interface->extendedAttributes->{"CustomIndexedSetter"};
722 sub InstanceOverridesPutDeclaration
724 my $interface = shift;
725 return $interface->extendedAttributes->{"CustomPutFunction"}
726 || $interface->extendedAttributes->{"CustomNamedSetter"}
727 || $interface->extendedAttributes->{"CustomIndexedSetter"};
730 sub InstanceNeedsVisitChildren
732 my $interface = shift;
733 return $interface->extendedAttributes->{"JSCustomMarkFunction"}
734 || $codeGenerator->InheritsInterface($interface, "EventTarget")
735 || $interface->name eq "EventTarget"
736 || $interface->extendedAttributes->{"ReportExtraMemoryCost"}
737 || IsJSBuiltinConstructor($interface)
740 sub InstanceNeedsEstimatedSize
742 my $interface = shift;
743 return $interface->extendedAttributes->{"ReportExtraMemoryCost"};
750 return "DOMWindow" if $name eq "AbstractView";
752 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($name);
753 return $svgNativeType if $svgNativeType;
758 sub IsClassNameWordBoundary
762 # Interpret negative numbers as distance from end of string, just as the substr function does.
763 $i += length($name) if $i < 0;
767 return 1 if $i == length($name);
768 return 0 if $i > length($name);
770 my $checkString = substr($name, $i - 1);
771 return $checkString =~ /^[^A-Z][A-Z]/ || $checkString =~ /^[A-Z][A-Z][^A-Z]/;
774 sub IsPrefixRemovable
776 my ($class, $name, $i) = @_;
778 return IsClassNameWordBoundary($name, $i)
779 && (IsClassNameWordBoundary($class, $i) && substr($class, 0, $i) eq substr($name, 0, $i)
780 || IsClassNameWordBoundary($class, -$i) && substr($class, -$i) eq substr($name, 0, $i));
783 sub GetNestedClassName
785 my ($interface, $name) = @_;
787 my $class = GetImplClassName($interface->name);
788 my $member = $codeGenerator->WK_ucfirst($name);
790 # Since the enumeration name will be nested in the class name's namespace, remove any words
791 # that happen to match the start or end of the class name. If an enumeration is named TrackType or
792 # TextTrackType, and the class is named TextTrack, then we will get a name like TextTrack::Type.
793 my $memberLength = length($member);
794 my $longestPrefixLength = 0;
795 if ($member =~ /^[A-Z]./) {
796 for (my $i = 2; $i < $memberLength - 1; $i++) {
797 $longestPrefixLength = $i if IsPrefixRemovable($class, $member, $i);
800 $member = substr($member, $longestPrefixLength);
802 return "${class}::$member";
805 sub GetEnumerationClassName
807 my ($interface, $name) = @_;
809 return GetNestedClassName($interface, $name);
812 sub GetEnumerationValueName
816 return "EmptyString" if $name eq "";
817 $name = join("", map { $codeGenerator->WK_ucfirst($_) } split("-", $name));
818 $name = "_$name" if $name =~ /^\d/;
822 sub GenerateEnumerationImplementationContent
824 my ($interface, $enumerations) = @_;
826 return "" unless @$enumerations;
828 # FIXME: Could optimize this to only generate the parts of each enumeration that are actually
829 # used, which would require iterating over everything in the interface.
833 $result .= "template<typename T> Optional<T> parse(ExecState&, JSValue);\n";
834 $result .= "template<typename T> const char* expectedEnumerationValues();\n\n";
836 foreach my $enumeration (@$enumerations) {
837 my $name = $enumeration->name;
839 my $className = GetEnumerationClassName($interface, $name);
841 # FIXME: A little ugly to have this be a side effect instead of a return value.
842 AddToImplIncludes("<runtime/JSString.h>");
844 my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
845 $result .= "#if ${conditionalString}\n\n" if $conditionalString;
847 # Declare this instead of using "static" because it may be unused and we don't want warnings about that.
848 $result .= "JSString* jsStringWithCache(ExecState*, $className);\n\n";
850 # Take an ExecState* instead of an ExecState& to match the jsStringWithCache from JSString.h.
851 # FIXME: Change to take VM& instead of ExecState*.
852 $result .= "JSString* jsStringWithCache(ExecState* state, $className enumerationValue)\n";
854 # FIXME: Might be nice to make this global be "const", but NeverDestroyed does not currently support that.
855 # FIXME: Might be nice to make the entire array be NeverDestroyed instead of each value, but not sure what the syntax for that is.
856 $result .= " static NeverDestroyed<const String> values[] = {\n";
857 foreach my $value (@{$enumeration->values}) {
859 $result .= " emptyString(),\n";
861 $result .= " ASCIILiteral(\"$value\"),\n";
866 foreach my $value (@{$enumeration->values}) {
867 my $enumerationValueName = GetEnumerationValueName($value);
868 $result .= " static_assert(static_cast<size_t>(${className}::$enumerationValueName) == $index, \"${className}::$enumerationValueName is not $index as expected\");\n";
871 $result .= " ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values));\n";
872 $result .= " return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);\n";
875 $result .= "template<> struct JSValueTraits<$className> {\n";
876 $result .= " static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, $className value) { return jsStringWithCache(state, value); }\n";
879 # FIXME: Change to take VM& instead of ExecState&.
880 # FIXME: Consider using toStringOrNull to make exception checking faster.
881 # FIXME: Consider finding a more efficient way to match against all the strings quickly.
882 $result .= "template<> Optional<$className> parse<$className>(ExecState& state, JSValue value)\n";
884 $result .= " auto stringValue = value.toWTFString(&state);\n";
885 foreach my $value (@{$enumeration->values}) {
886 my $enumerationValueName = GetEnumerationValueName($value);
888 $result .= " if (stringValue.isEmpty())\n";
890 $result .= " if (stringValue == \"$value\")\n";
892 $result .= " return ${className}::${enumerationValueName};\n";
894 $result .= " return Nullopt;\n";
897 # FIXME: A little ugly to have this be a side effect instead of a return value.
898 AddToImplIncludes("JSDOMConvert.h");
900 $result .= "template<> $className convert<$className>(ExecState& state, JSValue value)\n";
902 $result .= " auto result = parse<$className>(state, value);\n";
903 $result .= " if (UNLIKELY(!result)) {\n";
904 $result .= " throwTypeError(&state);\n";
905 $result .= " return { };\n";
907 $result .= " return result.value();\n";
910 $result .= "template<> inline const char* expectedEnumerationValues<$className>()\n";
912 $result .= " return \"\\\"" . join ("\\\", \\\"", @{$enumeration->values}) . "\\\"\";\n";
915 $result .= "#endif\n\n" if $conditionalString;
920 sub GetDictionaryClassName
922 my ($interface, $name) = @_;
924 return GetNestedClassName($interface, $name);
927 sub GenerateDefaultValue
929 my ($interface, $member) = @_;
931 my $value = $member->default;
933 if ($codeGenerator->IsEnumType($member->type)) {
934 # FIXME: Would be nice to report an error if the value does not have quote marks around it.
935 # FIXME: Would be nice to report an error if the value is not one of the enumeration values.
936 my $className = GetEnumerationClassName($interface, $member->type);
937 my $enumerationValueName = GetEnumerationValueName(substr($value, 1, -1));
938 $value = $className . "::" . $enumerationValueName;
944 sub ShouldAllowNonFiniteForFloatingPointType
948 die "Can only be called with floating point types" unless $codeGenerator->IsFloatingPointType($type);
949 return $type eq "unrestricted double" || $type eq "unrestricted float";
952 sub GenerateConversionRuleWithLeadingComma
954 my ($interface, $member) = @_;
956 if ($codeGenerator->IsFloatingPointType($member->type)) {
957 return ", " . (ShouldAllowNonFiniteForFloatingPointType($member->type) ? "ShouldAllowNonFinite::Yes" : "ShouldAllowNonFinite::No");
959 return ", " . GetIntegerConversionConfiguration($member) if $codeGenerator->IsIntegerType($member->type);
963 sub GenerateDefaultValueWithLeadingComma
965 my ($interface, $member) = @_;
967 return "" unless $member->isOptional && defined $member->default;
968 return ", " . GenerateDefaultValue($interface, $member);
971 sub GenerateDictionaryImplementationContent
973 my ($interface, $dictionaries) = @_;
976 foreach my $dictionary (@$dictionaries) {
977 my $name = $dictionary->name;
979 my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
980 $result .= "#if ${conditionalString}\n\n" if $conditionalString;
982 my $className = GetDictionaryClassName($interface, $name);
984 # FIXME: A little ugly to have this be a side effect instead of a return value.
985 AddToImplIncludes("JSDOMConvert.h");
987 my $defaultValues = "";
989 foreach my $member (@{$dictionary->members}) {
990 if (!$member->isOptional) {
994 $defaultValues .= $comma . (defined $member->default ? GenerateDefaultValue($interface, $member) : "{ }");
998 $result .= "template<> $className convert<$className>(ExecState& state, JSValue value)\n";
1000 $result .= " if (value.isUndefinedOrNull())\n" if $defaultValues;
1001 $result .= " return { " . $defaultValues . " };\n" if $defaultValues;
1002 $result .= " auto* object = value.getObject();\n";
1003 $result .= " if (UNLIKELY(!object || object->type() == RegExpObjectType)) {\n";
1004 $result .= " throwTypeError(&state);\n";
1005 $result .= " return { };\n";
1008 my $needExceptionCheck = 0;
1009 foreach my $member (@{$dictionary->members}) {
1010 if ($needExceptionCheck) {
1011 $result .= " if (UNLIKELY(state.hadException()))\n";
1012 $result .= " return { };\n";
1014 # FIXME: Eventually we will want this to share a lot more code with JSValueToNative.
1015 my $function = $member->isOptional ? "convertOptional" : "convert";
1016 $result .= " auto " . $member->name . " = " . $function . "<" . GetNativeTypeFromSignature($interface, $member) . ">"
1017 . "(state, object->get(&state, Identifier::fromString(&state, \"" . $member->name . "\"))"
1018 . GenerateConversionRuleWithLeadingComma($interface, $member)
1019 . GenerateDefaultValueWithLeadingComma($interface, $member) . ");\n";
1020 $needExceptionCheck = 1;
1025 foreach my $member (@{$dictionary->members}) {
1026 $arguments .= $comma . "WTFMove(" . $member->name . ")";
1030 $result .= " return { " . $arguments . " };\n";
1033 $result .= "#endif\n\n" if $conditionalString;
1040 my ($object, $interface) = @_;
1042 my $interfaceName = $interface->name;
1043 my $className = "JS$interfaceName";
1044 my %structureFlags = ();
1046 my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
1047 my $hasRealParent = $interface->parent;
1048 my $hasParent = $hasLegacyParent || $hasRealParent;
1049 my $parentClassName = GetParentClassName($interface);
1050 my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
1052 # - Add default header template and header protection
1053 push(@headerContentHeader, GenerateHeaderContentHeader($interface));
1056 $headerIncludes{"$parentClassName.h"} = 1;
1058 $headerIncludes{"JSDOMWrapper.h"} = 1;
1059 if ($interface->isException) {
1060 $headerIncludes{"<runtime/ErrorPrototype.h>"} = 1;
1064 if ($interface->extendedAttributes->{"CustomCall"}) {
1065 $headerIncludes{"<runtime/CallData.h>"} = 1;
1068 if ($hasParent && $interface->extendedAttributes->{"JSGenerateToNativeObject"}) {
1069 $headerIncludes{"$interfaceName.h"} = 1;
1072 $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
1074 my $implType = GetImplClassName($interfaceName);
1075 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($interfaceName);
1076 my $svgPropertyOrListPropertyType;
1077 $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
1078 $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
1080 my $numConstants = @{$interface->constants};
1081 my $numAttributes = @{$interface->attributes};
1082 my $numFunctions = @{$interface->functions};
1084 push(@headerContent, "\nnamespace WebCore {\n\n");
1086 if ($codeGenerator->IsSVGAnimatedType($interfaceName)) {
1087 $headerIncludes{"$interfaceName.h"} = 1;
1089 # Implementation class forward declaration
1090 if (IsDOMGlobalObject($interface)) {
1091 AddClassForwardIfNeeded($interfaceName) unless $svgPropertyOrListPropertyType;
1095 AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow";
1096 AddClassForwardIfNeeded("JSDictionary") if $codeGenerator->IsConstructorTemplate($interface, "Event");
1098 my $exportMacro = GetExportMacroForJSClass($interface);
1101 push(@headerContent, "class $exportMacro$className : public $parentClassName {\n");
1103 # Static create methods
1104 push(@headerContent, "public:\n");
1105 push(@headerContent, " typedef $parentClassName Base;\n");
1106 push(@headerContent, " typedef $implType DOMWrapped;\n") if $interface->parent;
1108 if ($interfaceName eq "DOMWindow") {
1109 push(@headerContent, " static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* windowShell)\n");
1110 push(@headerContent, " {\n");
1111 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl), windowShell);\n");
1112 push(@headerContent, " ptr->finishCreation(vm, windowShell);\n");
1113 push(@headerContent, " vm.heap.addFinalizer(ptr, destroy);\n");
1114 push(@headerContent, " return ptr;\n");
1115 push(@headerContent, " }\n\n");
1116 } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1117 push(@headerContent, " static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSC::JSProxy* proxy)\n");
1118 push(@headerContent, " {\n");
1119 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl));\n");
1120 push(@headerContent, " ptr->finishCreation(vm, proxy);\n");
1121 push(@headerContent, " vm.heap.addFinalizer(ptr, destroy);\n");
1122 push(@headerContent, " return ptr;\n");
1123 push(@headerContent, " }\n\n");
1124 } elsif ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
1125 AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
1126 push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
1127 push(@headerContent, " {\n");
1128 push(@headerContent, " globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(globalObject->vm(), \"Allocated masquerading object\");\n");
1129 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
1130 push(@headerContent, " ptr->finishCreation(globalObject->vm());\n");
1131 push(@headerContent, " return ptr;\n");
1132 push(@headerContent, " }\n\n");
1133 } elsif (!NeedsImplementationClass($interface)) {
1134 push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject)\n");
1135 push(@headerContent, " {\n");
1136 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject);\n");
1137 push(@headerContent, " ptr->finishCreation(globalObject->vm());\n");
1138 push(@headerContent, " return ptr;\n");
1139 push(@headerContent, " }\n\n");
1141 AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
1142 push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
1143 push(@headerContent, " {\n");
1144 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
1145 push(@headerContent, " ptr->finishCreation(globalObject->vm());\n");
1146 push(@headerContent, " return ptr;\n");
1147 push(@headerContent, " }\n\n");
1150 if (IsDOMGlobalObject($interface)) {
1151 push(@headerContent, " static const bool needsDestruction = false;\n\n");
1154 if (InstancePropertyCount($interface) > 0) {
1155 $structureFlags{"JSC::HasStaticPropertyTable"} = 1;
1159 unless (ShouldUseGlobalObjectPrototype($interface)) {
1160 push(@headerContent, " static JSC::JSObject* createPrototype(JSC::VM&, JSC::JSGlobalObject*);\n");
1161 push(@headerContent, " static JSC::JSObject* prototype(JSC::VM&, JSC::JSGlobalObject*);\n");
1164 # JSValue to implementation type
1165 if (ShouldGenerateToWrapped($hasParent, $interface)) {
1166 my $nativeType = GetNativeType($interface, $implType);
1167 if ($interface->extendedAttributes->{"JSCustomToNativeObject"}) {
1168 push(@headerContent, " static $nativeType toWrapped(JSC::ExecState&, JSC::JSValue);\n");
1170 push(@headerContent, " static $nativeType toWrapped(JSC::JSValue);\n");
1174 $headerTrailingIncludes{"${className}Custom.h"} = 1 if $interface->extendedAttributes->{"JSCustomHeader"};
1176 my $namedGetterFunction = GetNamedGetterFunction($interface);
1177 my $indexedGetterFunction = GetIndexedGetterFunction($interface);
1179 my $hasNamedGetter = $namedGetterFunction
1180 || $interface->extendedAttributes->{"CustomNamedGetter"};
1182 my $hasComplexGetter =
1183 $indexedGetterFunction
1184 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
1185 || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
1188 my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
1190 if ($hasNamedGetter) {
1191 if ($interface->extendedAttributes->{"OverrideBuiltins"}) {
1192 $structureFlags{"JSC::GetOwnPropertySlotIsImpure"} = 1;
1194 $structureFlags{"JSC::GetOwnPropertySlotIsImpureForPropertyAbsence"} = 1;
1197 if ($interface->extendedAttributes->{"NewImpurePropertyFiresWatchpoints"}) {
1198 $structureFlags{"JSC::NewImpurePropertyFiresWatchpoints"} = 1;
1200 if ($interface->extendedAttributes->{"CustomCall"}) {
1201 $structureFlags{"JSC::TypeOfShouldCallGetCallData"} = 1;
1206 push(@headerContent, " static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
1207 push(@headerContent, " bool getOwnPropertySlotDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n") if $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"};
1208 $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
1210 if ($hasComplexGetter) {
1211 push(@headerContent, " static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n");
1212 $structureFlags{"JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero"} = 1;
1216 my $overridesPut = InstanceOverridesPutDeclaration($interface);
1219 if ($overridesPut) {
1220 push(@headerContent, " static bool put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1221 push(@headerContent, " static bool putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n");
1222 push(@headerContent, " bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&, bool& putResult);\n") if $interface->extendedAttributes->{"CustomNamedSetter"};
1226 push(@headerContent, " static void destroy(JSC::JSCell*);\n");
1230 if ($interfaceName eq "Node") {
1231 push(@headerContent, "\n");
1232 push(@headerContent, "protected:\n");
1233 push(@headerContent, " static const JSC::ClassInfo s_info;\n");
1234 push(@headerContent, "public:\n");
1235 push(@headerContent, " static const JSC::ClassInfo* info() { return &s_info; }\n\n");
1237 push(@headerContent, "\n");
1238 push(@headerContent, " DECLARE_INFO;\n\n");
1241 if ($interfaceName eq "DOMWindow") {
1242 $structureFlags{"JSC::ImplementsHasInstance | JSC::ImplementsDefaultHasInstance"} = 1;
1244 push(@headerContent, " static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
1245 push(@headerContent, " {\n");
1246 if (IsDOMGlobalObject($interface)) {
1247 push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info());\n");
1248 } elsif ($codeGenerator->InheritsInterface($interface, "Document")) {
1249 push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSDocumentWrapperType), StructureFlags), info());\n");
1250 } elsif ($codeGenerator->InheritsInterface($interface, "Element")) {
1251 push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSElementType), StructureFlags), info());\n");
1252 } elsif ($codeGenerator->InheritsInterface($interface, "Node")) {
1253 push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSNodeType), StructureFlags), info());\n");
1255 push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n");
1257 push(@headerContent, " }\n\n");
1259 # Custom pushEventHandlerScope function
1260 push(@headerContent, " JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{"JSCustomPushEventHandlerScope"};
1262 # Custom call functions
1263 push(@headerContent, " static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $interface->extendedAttributes->{"CustomCall"};
1265 # Custom deleteProperty function
1266 push(@headerContent, " static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
1267 push(@headerContent, " static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
1269 # Custom getPropertyNames function exists on DOMWindow
1270 if ($interfaceName eq "DOMWindow") {
1271 push(@headerContent, " static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1272 push(@headerContent, " static void getGenericPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1273 push(@headerContent, " static void getStructurePropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1274 push(@headerContent, " static uint32_t getEnumerableLength(JSC::ExecState*, JSC::JSObject*);\n");
1275 $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
1278 # Custom getOwnPropertyNames function
1279 if ($interface->extendedAttributes->{"CustomEnumerateProperty"} || $indexedGetterFunction || $namedGetterFunction) {
1280 push(@headerContent, " static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1281 $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
1284 # Custom defineOwnProperty function
1285 push(@headerContent, " static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnProperty"};
1287 # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
1288 if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
1289 $structureFlags{"JSC::MasqueradesAsUndefined"} = 1;
1292 # Constructor object getter
1293 unless ($interface->extendedAttributes->{"NoInterfaceObject"}) {
1294 push(@headerContent, " static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);\n");
1295 push(@headerContent, " static JSC::JSValue getNamedConstructor(JSC::VM&, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{"NamedConstructor"};
1298 my $numCustomFunctions = 0;
1299 my $numCustomAttributes = 0;
1301 my $hasForwardDeclaringFunctions = 0;
1302 my $hasForwardDeclaringAttributes = 0;
1304 # Attribute and function enums
1305 if ($numAttributes > 0) {
1306 foreach (@{$interface->attributes}) {
1308 $numCustomAttributes++ if HasCustomGetter($attribute->signature->extendedAttributes);
1309 $numCustomAttributes++ if HasCustomSetter($attribute->signature->extendedAttributes);
1310 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
1311 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1312 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1313 push(@headerContent, " mutable JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->signature->name . ";\n");
1314 $numCachedAttributes++;
1315 $needsVisitChildren = 1;
1316 push(@headerContent, "#endif\n") if $conditionalString;
1319 if ($attribute->signature->extendedAttributes->{"ForwardDeclareInHeader"}) {
1320 $hasForwardDeclaringAttributes = 1;
1326 if ($needsVisitChildren) {
1327 push(@headerContent, " static void visitChildren(JSCell*, JSC::SlotVisitor&);\n");
1328 push(@headerContent, " void visitAdditionalChildren(JSC::SlotVisitor&);\n") if $interface->extendedAttributes->{"JSCustomMarkFunction"};
1329 push(@headerContent, "\n");
1332 if (InstanceNeedsEstimatedSize($interface)) {
1333 push(@headerContent, " static size_t estimatedSize(JSCell*);\n");
1336 if ($numCustomAttributes > 0) {
1337 push(@headerContent, "\n // Custom attributes\n");
1339 foreach my $attribute (@{$interface->attributes}) {
1340 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1341 if (HasCustomGetter($attribute->signature->extendedAttributes)) {
1342 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1343 my $methodName = $codeGenerator->WK_lcfirst($attribute->signature->name);
1344 push(@headerContent, " JSC::JSValue " . $methodName . "(JSC::ExecState&) const;\n");
1345 push(@headerContent, "#endif\n") if $conditionalString;
1347 if (HasCustomSetter($attribute->signature->extendedAttributes) && !IsReadonly($attribute)) {
1348 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1349 push(@headerContent, " void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState&, JSC::JSValue);\n");
1350 push(@headerContent, "#endif\n") if $conditionalString;
1355 foreach my $function (@{$interface->functions}) {
1356 $numCustomFunctions++ if HasCustomMethod($function->signature->extendedAttributes);
1358 if ($function->signature->extendedAttributes->{"ForwardDeclareInHeader"}) {
1359 $hasForwardDeclaringFunctions = 1;
1363 if ($numCustomFunctions > 0) {
1364 my $inAppleCopyright = 0;
1365 push(@headerContent, "\n // Custom functions\n");
1366 foreach my $function (@{$interface->functions}) {
1367 my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
1368 if ($needsAppleCopyright) {
1369 if (!$inAppleCopyright) {
1370 push(@headerContent, $beginAppleCopyrightForHeaderFiles);
1371 $inAppleCopyright = 1;
1373 } elsif ($inAppleCopyright) {
1374 push(@headerContent, $endAppleCopyright);
1375 $inAppleCopyright = 0;
1377 next unless HasCustomMethod($function->signature->extendedAttributes);
1378 next if $function->{overloads} && $function->{overloadIndex} != 1;
1379 my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1380 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1381 my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
1382 push(@headerContent, " " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState&);\n");
1383 push(@headerContent, "#endif\n") if $conditionalString;
1385 push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
1388 if (NeedsImplementationClass($interface)) {
1390 push(@headerContent, " $interfaceName& wrapped() const\n");
1391 push(@headerContent, " {\n");
1392 push(@headerContent, " return static_cast<$interfaceName&>(Base::wrapped());\n");
1393 push(@headerContent, " }\n");
1398 if (%structureFlags) {
1399 push(@headerContent, "public:\n");
1400 push(@headerContent, " static const unsigned StructureFlags = ");
1401 foreach my $structureFlag (sort (keys %structureFlags)) {
1402 push(@headerContent, $structureFlag . " | ");
1404 push(@headerContent, "Base::StructureFlags;\n");
1407 push(@headerContent, "protected:\n");
1410 if ($interfaceName eq "DOMWindow") {
1411 push(@headerContent, " $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&, JSDOMWindowShell*);\n");
1412 } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1413 push(@headerContent, " $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&);\n");
1414 } elsif (!NeedsImplementationClass($interface)) {
1415 push(@headerContent, " $className(JSC::Structure*, JSDOMGlobalObject&);\n\n");
1417 push(@headerContent, " $className(JSC::Structure*, JSDOMGlobalObject&, Ref<$implType>&&);\n\n");
1418 push(@headerContent, " void finishCreation(JSC::VM& vm)\n");
1419 push(@headerContent, " {\n");
1420 push(@headerContent, " Base::finishCreation(vm);\n");
1421 push(@headerContent, " ASSERT(inherits(info()));\n");
1422 push(@headerContent, " }\n\n");
1425 if (IsDOMGlobalObject($interface)) {
1426 if ($interfaceName eq "DOMWindow") {
1427 push(@headerContent, " void finishCreation(JSC::VM&, JSDOMWindowShell*);\n");
1429 push(@headerContent, " void finishCreation(JSC::VM&, JSC::JSProxy*);\n");
1434 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
1435 push(@headerContent, " void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
1438 if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
1439 push(@headerContent, "private:\n");
1440 push(@headerContent, " bool nameGetter(JSC::ExecState*, JSC::PropertyName, JSC::JSValue&);\n");
1443 push(@headerContent, "};\n\n");
1445 if (ShouldGenerateWrapperOwnerCode($hasParent, $interface)) {
1446 if ($interfaceName ne "Node" && $codeGenerator->InheritsInterface($interface, "Node")) {
1447 $headerIncludes{"JSNode.h"} = 1;
1448 push(@headerContent, "class JS${interfaceName}Owner : public JSNodeOwner {\n");
1450 push(@headerContent, "class JS${interfaceName}Owner : public JSC::WeakHandleOwner {\n");
1452 $headerIncludes{"<wtf/NeverDestroyed.h>"} = 1;
1453 push(@headerContent, "public:\n");
1454 push(@headerContent, " virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
1455 push(@headerContent, " virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
1456 push(@headerContent, "};\n");
1457 push(@headerContent, "\n");
1458 push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, $implType*)\n");
1459 push(@headerContent, "{\n");
1460 push(@headerContent, " static NeverDestroyed<JS${interfaceName}Owner> owner;\n");
1461 push(@headerContent, " return &owner.get();\n");
1462 push(@headerContent, "}\n");
1463 push(@headerContent, "\n");
1464 push(@headerContent, "inline void* wrapperKey($implType* wrappableObject)\n");
1465 push(@headerContent, "{\n");
1466 push(@headerContent, " return wrappableObject;\n");
1467 push(@headerContent, "}\n");
1468 push(@headerContent, "\n");
1470 if (ShouldGenerateToJSDeclaration($hasParent, $interface)) {
1471 # Node and NodeList have custom inline implementations which thus cannot be exported.
1472 # FIXME: The special case for Node and NodeList should probably be implemented via an IDL attribute.
1473 if ($implType eq "Node" or $implType eq "NodeList") {
1474 push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType&);\n");
1476 push(@headerContent, $exportMacro."JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType&);\n");
1478 push(@headerContent, "inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, $implType* impl) { return impl ? toJS(state, globalObject, *impl) : JSC::jsNull(); }\n");
1480 push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, Ref<$implType>&&);\n");
1481 push(@headerContent, "inline JSC::JSValue toJSNewlyCreated(JSC::ExecState* state, JSDOMGlobalObject* globalObject, RefPtr<$implType>&& impl) { return impl ? toJSNewlyCreated(state, globalObject, impl.releaseNonNull()) : JSC::jsNull(); }\n");
1484 push(@headerContent, "\n");
1486 GeneratePrototypeDeclaration(\@headerContent, $className, $interface) if HeaderNeedsPrototypeDeclaration($interface);
1488 if ($hasForwardDeclaringFunctions) {
1489 my $inAppleCopyright = 0;
1490 push(@headerContent,"// Functions\n\n");
1491 foreach my $function (@{$interface->functions}) {
1492 next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1493 next unless $function->signature->extendedAttributes->{"ForwardDeclareInHeader"};
1495 my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
1496 if ($needsAppleCopyright) {
1497 if (!$inAppleCopyright) {
1498 push(@headerContent, $beginAppleCopyrightForHeaderFiles);
1499 $inAppleCopyright = 1;
1501 } elsif ($inAppleCopyright) {
1502 push(@headerContent, $endAppleCopyright);
1503 $inAppleCopyright = 0;
1506 my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1507 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1508 my $functionName = GetFunctionName($interface, $className, $function);
1509 push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
1510 push(@headerContent, "#endif\n") if $conditionalString;
1513 push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
1514 push(@headerContent,"\n");
1517 if ($hasForwardDeclaringAttributes) {
1518 push(@headerContent,"// Attributes\n\n");
1519 foreach my $attribute (@{$interface->attributes}) {
1520 next unless $attribute->signature->extendedAttributes->{"ForwardDeclareInHeader"};
1522 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1523 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1524 my $getter = GetAttributeGetterName($interface, $className, $attribute);
1525 push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
1526 if (!IsReadonly($attribute)) {
1527 my $setter = GetAttributeSetterName($interface, $className, $attribute);
1528 push(@headerContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
1530 push(@headerContent, "#endif\n") if $conditionalString;
1534 if (HasCustomConstructor($interface)) {
1535 push(@headerContent, "// Custom constructor\n");
1536 push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState&);\n\n");
1539 if ($codeGenerator->IsConstructorTemplate($interface, "Event")) {
1540 push(@headerContent, "bool fill${interfaceName}Init(${interfaceName}Init&, JSDictionary&);\n\n");
1543 my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
1544 push(@headerContent, "\n} // namespace WebCore\n");
1545 push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
1547 if ($interface->extendedAttributes->{"AppleCopyright"}) {
1548 push(@headerContent, "\n");
1549 push(@headerContent, split("\r", $endAppleCopyright));
1553 sub GeneratePropertiesHashTable
1555 my ($object, $interface, $isInstance, $hashKeys, $hashSpecials, $hashValue1, $hashValue2, $conditionals, $runtimeEnabledFunctions, $runtimeEnabledAttributes) = @_;
1557 # FIXME: These should be functions on $interface.
1558 my $interfaceName = $interface->name;
1559 my $className = "JS$interfaceName";
1561 # - Add all properties in a hashtable definition
1562 my $propertyCount = $isInstance ? InstancePropertyCount($interface) : PrototypePropertyCount($interface);
1564 if (!$isInstance && NeedsConstructorProperty($interface)) {
1565 die if !$propertyCount;
1566 push(@$hashKeys, "constructor");
1567 my $getter = "js" . $interfaceName . "Constructor";
1568 push(@$hashValue1, $getter);
1570 my $setter = "setJS" . $interfaceName . "Constructor";
1571 push(@$hashValue2, $setter);
1572 push(@$hashSpecials, "DontEnum");
1575 return 0 if !$propertyCount;
1577 foreach my $attribute (@{$interface->attributes}) {
1578 next if ($attribute->isStatic);
1579 next if AttributeShouldBeOnInstance($interface, $attribute) != $isInstance;
1581 # Global objects add RuntimeEnabled attributes after creation so do not add them to the static table.
1582 if (IsDOMGlobalObject($interface) && $attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1583 $propertyCount -= 1;
1587 my $name = $attribute->signature->name;
1588 push(@$hashKeys, $name);
1590 my $special = GetJSCAttributesForAttribute($interface, $attribute);
1591 push(@$hashSpecials, $special);
1593 my $getter = GetAttributeGetterName($interface, $className, $attribute);
1594 push(@$hashValue1, $getter);
1596 if (IsReadonly($attribute)) {
1597 push(@$hashValue2, "0");
1599 my $setter = GetAttributeSetterName($interface, $className, $attribute);
1600 push(@$hashValue2, $setter);
1603 my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
1605 $conditionals->{$name} = $conditional;
1608 if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1610 die "We currently do not support [EnabledAtRuntime] attributes on the instance (except for global objects).";
1612 push(@$runtimeEnabledAttributes, $attribute);
1617 my @functions = @{$interface->functions};
1618 push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
1619 foreach my $function (@functions) {
1620 next if ($function->signature->extendedAttributes->{"PrivateIdentifier"} and not $function->signature->extendedAttributes->{"PublicIdentifier"});
1621 next if ($function->isStatic);
1622 next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1623 next if OperationShouldBeOnInstance($interface, $function) != $isInstance;
1624 next if $function->signature->name eq "[Symbol.Iterator]";
1626 # Global objects add RuntimeEnabled operations after creation so do not add them to the static table.
1627 if (IsDOMGlobalObject($interface) && $function->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1628 $propertyCount -= 1;
1632 my $name = $function->signature->name;
1633 push(@$hashKeys, $name);
1635 my $functionName = GetFunctionName($interface, $className, $function);
1636 push(@$hashValue1, $functionName);
1638 my $functionLength = GetFunctionLength($function);
1639 push(@$hashValue2, $functionLength);
1641 push(@$hashSpecials, ComputeFunctionSpecial($interface, $function));
1643 my $conditional = $function->signature->extendedAttributes->{"Conditional"};
1645 $conditionals->{$name} = $conditional;
1648 if ($function->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1650 die "We currently do not support [EnabledAtRuntime] operations on the instance (except for global objects).";
1652 push(@$runtimeEnabledFunctions, $function);
1657 return $propertyCount;
1660 sub GenerateParametersCheckExpression
1662 my $numParameters = shift;
1663 my $function = shift;
1665 my @andExpression = ();
1666 push(@andExpression, "argsCount == $numParameters");
1667 my $parameterIndex = 0;
1668 my %usedArguments = ();
1669 foreach my $parameter (@{$function->parameters}) {
1670 last if $parameterIndex >= $numParameters;
1671 my $value = "arg$parameterIndex";
1672 my $type = $parameter->type;
1674 # For DOMString with StrictTypeChecking only Null, Undefined and Object
1675 # are accepted for compatibility. Otherwise, no restrictions are made to
1676 # match the non-overloaded behavior.
1677 # FIXME: Implement WebIDL overload resolution algorithm.
1678 if ($type eq "DOMString" || $codeGenerator->IsEnumType($type)) {
1679 if ($parameter->extendedAttributes->{"StrictTypeChecking"}) {
1680 push(@andExpression, "(${value}.isUndefinedOrNull() || ${value}.isString() || ${value}.isObject())");
1681 $usedArguments{$parameterIndex} = 1;
1683 } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) {
1684 # For Callbacks only checks if the value is null or object.
1685 if ($codeGenerator->IsFunctionOnlyCallbackInterface($parameter->type)) {
1686 push(@andExpression, "(${value}.isNull() || ${value}.isFunction())");
1688 push(@andExpression, "(${value}.isNull() || ${value}.isObject())");
1690 $usedArguments{$parameterIndex} = 1;
1691 } elsif ($codeGenerator->IsDictionaryType($parameter->type)) {
1692 push(@andExpression, "(${value}.isUndefinedOrNull() || ${value}.isObject())");
1693 $usedArguments{$parameterIndex} = 1;
1694 } elsif (($codeGenerator->GetArrayOrSequenceType($type) || $codeGenerator->IsTypedArrayType($type) || $codeGenerator->IsWrapperType($type)) && $type ne "EventListener") {
1697 if ($parameter->isNullable) {
1698 $condition .= "${value}.isUndefinedOrNull() || ";
1699 } elsif ($parameter->isOptional) {
1700 $condition .= "${value}.isUndefined() || ";
1703 if ($codeGenerator->GetArrayOrSequenceType($type)) {
1704 # FIXME: Add proper support for T[], T[]?, sequence<T>.
1705 $condition .= "(${value}.isObject() && isJSArray(${value}))";
1707 $condition .= "(${value}.isObject() && asObject(${value})->inherits(JS${type}::info()))";
1709 push(@andExpression, "(" . $condition . ")");
1710 $usedArguments{$parameterIndex} = 1;
1714 my $res = join(" && ", @andExpression);
1715 $res = "($res)" if @andExpression > 1;
1716 return ($res, sort {$a <=> $b} (keys %usedArguments));
1719 # As per Web IDL specification, the length of a function Object is its number of mandatory parameters.
1720 sub GetFunctionLength
1722 my $function = shift;
1725 foreach my $parameter (@{$function->parameters}) {
1726 # Abort as soon as we find the first optional parameter as no mandatory
1727 # parameter can follow an optional one.
1728 last if $parameter->isOptional || $parameter->isVariadic;
1734 sub GenerateFunctionParametersCheck
1736 my $function = shift;
1738 my @orExpression = ();
1739 my $numParameters = 0;
1740 my @neededArguments = ();
1741 my $hasVariadic = 0;
1742 my $numMandatoryParams = @{$function->parameters};
1744 foreach my $parameter (@{$function->parameters}) {
1745 if ($parameter->isOptional) {
1746 my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1747 push(@orExpression, $expression);
1748 push(@neededArguments, @usedArguments);
1749 $numMandatoryParams--;
1751 if ($parameter->isVariadic) {
1757 if (!$hasVariadic) {
1758 my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1759 push(@orExpression, $expression);
1760 push(@neededArguments, @usedArguments);
1762 return ($numMandatoryParams, join(" || ", @orExpression), @neededArguments);
1765 sub LengthOfLongestFunctionParameterList
1767 my ($overloads) = @_;
1769 foreach my $overload (@{$overloads}) {
1770 my @parameters = @{$overload->parameters};
1771 $result = @parameters if $result < @parameters;
1776 sub GenerateOverloadedFunction
1778 my ($function, $interface) = @_;
1780 # Generate code for choosing the correct overload to call. Overloads are
1781 # chosen based on the total number of arguments passed and the type of
1782 # values passed in non-primitive argument slots. When more than a single
1783 # overload is applicable, precedence is given according to the order of
1784 # declaration in the IDL.
1786 my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
1787 my $interfaceName = $interface->name;
1788 my $functionName = "js${interfaceName}${kind}Function" . $codeGenerator->WK_ucfirst($function->signature->name);
1790 # FIXME: Implement support for overloaded functions with variadic arguments.
1791 my $lengthOfLongestOverloadedFunctionParameterList = LengthOfLongestFunctionParameterList($function->{overloads});
1793 push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* state)\n");
1794 push(@implContent, <<END);
1796 size_t argsCount = std::min<size_t>($lengthOfLongestOverloadedFunctionParameterList, state->argumentCount());
1799 my %fetchedArguments = ();
1800 my $leastNumMandatoryParams = 255;
1802 foreach my $overload (@{$function->{overloads}}) {
1803 my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload);
1804 $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams);
1806 foreach my $parameterIndex (@neededArguments) {
1807 next if exists $fetchedArguments{$parameterIndex};
1808 push(@implContent, " JSValue arg$parameterIndex(state->argument($parameterIndex));\n");
1809 $fetchedArguments{$parameterIndex} = 1;
1812 my $conditionalString = $codeGenerator->GenerateConditionalString($overload->signature);
1813 push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
1815 push(@implContent, " if ($parametersCheck)\n");
1816 push(@implContent, " return ${functionName}$overload->{overloadIndex}(state);\n");
1817 push(@implContent, "#endif\n\n") if $conditionalString;
1820 if ($leastNumMandatoryParams >= 1) {
1821 push(@implContent, " if (UNLIKELY(argsCount < $leastNumMandatoryParams))\n");
1822 push(@implContent, " return throwVMError(state, createNotEnoughArgumentsError(state));\n");
1824 push(@implContent, <<END);
1825 return throwVMTypeError(state);
1831 sub GetNativeTypeForConversions
1833 my $interface = shift;
1834 my $interfaceName = $interface->name;
1835 $interfaceName = $codeGenerator->GetSVGTypeNeedingTearOff($interfaceName) if $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName);
1836 return $interfaceName;
1839 # See http://refspecs.linux-foundation.org/cxxabi-1.83.html.
1840 sub GetGnuVTableRefForInterface
1842 my $interface = shift;
1843 my $vtableName = GetGnuVTableNameForInterface($interface);
1847 my $typename = GetNativeTypeForConversions($interface);
1848 my $offset = GetGnuVTableOffsetForType($typename);
1849 return "&" . $vtableName . "[" . $offset . "]";
1852 sub GetGnuVTableNameForInterface
1854 my $interface = shift;
1855 my $typename = GetNativeTypeForConversions($interface);
1856 my $templatePosition = index($typename, "<");
1857 return "" if $templatePosition != -1;
1858 return "" if GetImplementationLacksVTableForInterface($interface);
1859 return "" if GetSkipVTableValidationForInterface($interface);
1860 return "_ZTV" . GetGnuMangledNameForInterface($interface);
1863 sub GetGnuMangledNameForInterface
1865 my $interface = shift;
1866 my $typename = GetNativeTypeForConversions($interface);
1867 my $templatePosition = index($typename, "<");
1868 if ($templatePosition != -1) {
1871 my $mangledType = length($typename) . $typename;
1872 my $namespace = GetNamespaceForInterface($interface);
1873 my $mangledNamespace = "N" . length($namespace) . $namespace;
1874 return $mangledNamespace . $mangledType . "E";
1877 sub GetGnuVTableOffsetForType
1879 my $typename = shift;
1880 if ($typename eq "SVGAElement"
1881 || $typename eq "SVGCircleElement"
1882 || $typename eq "SVGClipPathElement"
1883 || $typename eq "SVGDefsElement"
1884 || $typename eq "SVGEllipseElement"
1885 || $typename eq "SVGForeignObjectElement"
1886 || $typename eq "SVGGElement"
1887 || $typename eq "SVGImageElement"
1888 || $typename eq "SVGLineElement"
1889 || $typename eq "SVGPathElement"
1890 || $typename eq "SVGPolyElement"
1891 || $typename eq "SVGPolygonElement"
1892 || $typename eq "SVGPolylineElement"
1893 || $typename eq "SVGRectElement"
1894 || $typename eq "SVGSVGElement"
1895 || $typename eq "SVGGraphicsElement"
1896 || $typename eq "SVGSwitchElement"
1897 || $typename eq "SVGTextElement"
1898 || $typename eq "SVGUseElement") {
1904 # See http://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B_Name_Mangling.
1905 sub GetWinVTableRefForInterface
1907 my $interface = shift;
1908 my $vtableName = GetWinVTableNameForInterface($interface);
1909 return 0 if !$vtableName;
1910 return "__identifier(\"" . $vtableName . "\")";
1913 sub GetWinVTableNameForInterface
1915 my $interface = shift;
1916 my $typename = GetNativeTypeForConversions($interface);
1917 my $templatePosition = index($typename, "<");
1918 return "" if $templatePosition != -1;
1919 return "" if GetImplementationLacksVTableForInterface($interface);
1920 return "" if GetSkipVTableValidationForInterface($interface);
1921 return "??_7" . GetWinMangledNameForInterface($interface) . "6B@";
1924 sub GetWinMangledNameForInterface
1926 my $interface = shift;
1927 my $typename = GetNativeTypeForConversions($interface);
1928 my $namespace = GetNamespaceForInterface($interface);
1929 return $typename . "@" . $namespace . "@@";
1932 sub GetNamespaceForInterface
1934 my $interface = shift;
1935 return $interface->extendedAttributes->{"ImplementationNamespace"} || "WebCore";
1938 sub GetImplementationLacksVTableForInterface
1940 my $interface = shift;
1941 return $interface->extendedAttributes->{"ImplementationLacksVTable"};
1944 sub GetSkipVTableValidationForInterface
1946 my $interface = shift;
1947 return $interface->extendedAttributes->{"SkipVTableValidation"};
1950 # URL becomes url, but SetURL becomes setURL.
1954 my $ret = lcfirst($param);
1955 $ret =~ s/cSS/css/ if $ret =~ /^cSS/;
1956 $ret =~ s/dOM/dom/ if $ret =~ /^dOM/;
1957 $ret =~ s/hTML/html/ if $ret =~ /^hTML/;
1958 $ret =~ s/jS/js/ if $ret =~ /^jS/;
1959 $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
1960 $ret =~ s/xML/xml/ if $ret =~ /^xML/;
1961 $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
1963 # For HTML5 FileSystem API Flags attributes.
1964 # (create is widely used to instantiate an object and must be avoided.)
1965 $ret =~ s/^create/isCreate/ if $ret =~ /^create$/;
1966 $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/;
1971 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
1972 sub GetRuntimeEnableFunctionName
1974 my $signature = shift;
1976 # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::sharedFeatures().{FeatureName}Enabled() method.
1977 return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "VALUE_IS_MISSING");
1979 # Otherwise return a function named RuntimeEnabledFeatures::sharedFeatures().{methodName}Enabled().
1980 return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->name) . "Enabled";
1983 sub GetCastingHelperForThisObject
1985 my $interface = shift;
1986 my $interfaceName = $interface->name;
1988 return "jsNodeCast" if $interfaceName eq "Node";
1989 return "jsElementCast" if $interfaceName eq "Element";
1990 return "jsDocumentCast" if $interfaceName eq "Document";
1991 return "jsEventTargetCast" if $interfaceName eq "EventTarget";
1992 return "jsDynamicCast<JS$interfaceName*>";
1995 sub GetIndexedGetterExpression
1997 my $indexedGetterFunction = shift;
1998 if ($indexedGetterFunction->signature->type eq "DOMString") {
1999 return "jsStringOrUndefined(state, thisObject->wrapped().item(index))";
2001 return "toJS(state, thisObject->globalObject(), thisObject->wrapped().item(index))";
2004 sub GenerateImplementation
2006 my ($object, $interface, $enumerations, $dictionaries) = @_;
2008 my $interfaceName = $interface->name;
2009 my $className = "JS$interfaceName";
2011 my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
2012 my $hasRealParent = $interface->parent;
2013 my $hasParent = $hasLegacyParent || $hasRealParent;
2014 my $parentClassName = GetParentClassName($interface);
2015 my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
2016 my $eventTarget = $codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->name ne "EventTarget";
2017 my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
2019 my $namedGetterFunction = GetNamedGetterFunction($interface);
2020 my $indexedGetterFunction = GetIndexedGetterFunction($interface);
2022 # - Add default header template
2023 push(@implContentHeader, GenerateImplementationContentHeader($interface));
2025 $implIncludes{"JSDOMBinding.h"} = 1;
2026 $implIncludes{"<wtf/GetPtr.h>"} = 1;
2027 $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $indexedGetterFunction;
2029 my $implType = GetImplClassName($interfaceName);
2031 AddJSBuiltinIncludesIfNeeded($interface);
2035 push(@implContent, "\nusing namespace JSC;\n\n");
2036 push(@implContent, "namespace WebCore {\n\n");
2038 push(@implContent, GenerateEnumerationImplementationContent($interface, $enumerations));
2039 push(@implContent, GenerateDictionaryImplementationContent($interface, $dictionaries));
2041 my @functions = @{$interface->functions};
2042 push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
2044 my $numConstants = @{$interface->constants};
2045 my $numFunctions = @functions;
2046 my $numAttributes = @{$interface->attributes};
2048 if ($numFunctions > 0) {
2049 my $inAppleCopyright = 0;
2050 push(@implContent,"// Functions\n\n");
2051 foreach my $function (@functions) {
2052 next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2053 next if $function->signature->extendedAttributes->{"ForwardDeclareInHeader"};
2054 next if IsJSBuiltin($interface, $function);
2056 my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
2057 if ($needsAppleCopyright) {
2058 if (!$inAppleCopyright) {
2059 push(@implContent, $beginAppleCopyrightForHeaderFiles);
2060 $inAppleCopyright = 1;
2062 } elsif ($inAppleCopyright) {
2063 push(@implContent, $endAppleCopyright);
2064 $inAppleCopyright = 0;
2067 my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2068 push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2069 my $functionName = GetFunctionName($interface, $className, $function);
2070 push(@implContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
2071 push(@implContent, "#endif\n") if $conditionalString;
2074 push(@implContent, $endAppleCopyright) if $inAppleCopyright;
2076 push(@implContent, "\n");
2079 if ($numAttributes > 0 || NeedsConstructorProperty($interface)) {
2080 push(@implContent, "// Attributes\n\n");
2081 foreach my $attribute (@{$interface->attributes}) {
2082 next if $attribute->signature->extendedAttributes->{"ForwardDeclareInHeader"};
2083 next if IsJSBuiltin($interface, $attribute);
2085 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2086 push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2087 my $getter = GetAttributeGetterName($interface, $className, $attribute);
2088 push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
2089 if (!IsReadonly($attribute)) {
2090 my $setter = GetAttributeSetterName($interface, $className, $attribute);
2091 push(@implContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
2093 push(@implContent, "#endif\n") if $conditionalString;
2096 if (NeedsConstructorProperty($interface)) {
2097 my $getter = "js" . $interfaceName . "Constructor";
2098 push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
2101 my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2102 push(@implContent, "bool ${constructorFunctionName}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
2104 push(@implContent, "\n");
2107 GeneratePrototypeDeclaration(\@implContent, $className, $interface) if !HeaderNeedsPrototypeDeclaration($interface);
2109 GenerateConstructorDeclaration(\@implContent, $className, $interface) if NeedsConstructorProperty($interface);
2112 my @hashValue1 = ();
2113 my @hashValue2 = ();
2114 my @hashSpecials = ();
2115 my %conditionals = ();
2116 my $hashName = $className . "Table";
2117 my @runtimeEnabledFunctions = ();
2118 my @runtimeEnabledAttributes = ();
2120 # Generate hash table for properties on the instance.
2121 my $numInstanceProperties = GeneratePropertiesHashTable($object, $interface, 1,
2122 \@hashKeys, \@hashSpecials,
2123 \@hashValue1, \@hashValue2,
2124 \%conditionals, \@runtimeEnabledFunctions, \@runtimeEnabledAttributes);
2126 $object->GenerateHashTable($hashName, $numInstanceProperties,
2127 \@hashKeys, \@hashSpecials,
2128 \@hashValue1, \@hashValue2,
2129 \%conditionals, 0) if $numInstanceProperties > 0;
2131 # - Add all interface object (aka constructor) properties (constants, static attributes, static operations).
2132 if (NeedsConstructorProperty($interface)) {
2134 my $hashName = $className . "ConstructorTable";
2137 my @hashValue1 = ();
2138 my @hashValue2 = ();
2139 my @hashSpecials = ();
2140 my %conditionals = ();
2142 my $needsConstructorTable = 0;
2144 foreach my $constant (@{$interface->constants}) {
2145 my $name = $constant->name;
2146 push(@hashKeys, $name);
2147 push(@hashValue1, $constant->value);
2148 push(@hashValue2, "0");
2149 push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
2151 my $implementedBy = $constant->extendedAttributes->{"ImplementedBy"};
2152 if ($implementedBy) {
2153 $implIncludes{"${implementedBy}.h"} = 1;
2155 my $conditional = $constant->extendedAttributes->{"Conditional"};
2157 $conditionals{$name} = $conditional;
2163 foreach my $attribute (@{$interface->attributes}) {
2164 next unless ($attribute->isStatic);
2165 my $name = $attribute->signature->name;
2166 push(@hashKeys, $name);
2169 push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
2170 push(@specials, "ReadOnly") if IsReadonly($attribute);
2171 my $special = (@specials > 0) ? join(" | ", @specials) : "0";
2172 push(@hashSpecials, $special);
2174 my $getter = GetAttributeGetterName($interface, $className, $attribute);
2175 push(@hashValue1, $getter);
2177 if (IsReadonly($attribute)) {
2178 push(@hashValue2, "0");
2180 my $setter = GetAttributeSetterName($interface, $className, $attribute);
2181 push(@hashValue2, $setter);
2184 my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
2186 $conditionals{$name} = $conditional;
2192 foreach my $function (@{$interface->functions}) {
2193 next unless ($function->isStatic);
2194 next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2195 my $name = $function->signature->name;
2196 push(@hashKeys, $name);
2198 my $functionName = GetFunctionName($interface, $className, $function);
2199 push(@hashValue1, $functionName);
2201 my $functionLength = GetFunctionLength($function);
2202 push(@hashValue2, $functionLength);
2204 push(@hashSpecials, ComputeFunctionSpecial($interface, $function));
2206 my $conditional = $function->signature->extendedAttributes->{"Conditional"};
2208 $conditionals{$name} = $conditional;
2214 $object->GenerateHashTable($hashName, $hashSize,
2215 \@hashKeys, \@hashSpecials,
2216 \@hashValue1, \@hashValue2,
2217 \%conditionals, 1) if $hashSize > 0;
2219 push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($interface));
2221 my $protoClassName = "${className}Prototype";
2222 GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $visibleInterfaceName, $interface);
2223 if ($interface->extendedAttributes->{"NamedConstructor"}) {
2224 GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interface->extendedAttributes->{"NamedConstructor"}, $interface, "GeneratingNamedConstructor");
2228 # - Add functions and constants to a hashtable definition
2230 $hashName = $className . "PrototypeTable";
2237 @runtimeEnabledFunctions = ();
2238 @runtimeEnabledAttributes = ();
2240 # Generate hash table for properties on the prototype.
2241 my $numPrototypeProperties = GeneratePropertiesHashTable($object, $interface, 0,
2242 \@hashKeys, \@hashSpecials,
2243 \@hashValue1, \@hashValue2,
2244 \%conditionals, \@runtimeEnabledFunctions, \@runtimeEnabledAttributes);
2245 my $hashSize = $numPrototypeProperties;
2247 foreach my $constant (@{$interface->constants}) {
2248 my $name = $constant->name;
2250 push(@hashKeys, $name);
2251 push(@hashValue1, $constant->value);
2252 push(@hashValue2, "0");
2253 push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
2255 my $conditional = $constant->extendedAttributes->{"Conditional"};
2257 $conditionals{$name} = $conditional;
2263 my $justGenerateValueArray = !IsDOMGlobalObject($interface);
2265 $object->GenerateHashTable($hashName, $hashSize,
2266 \@hashKeys, \@hashSpecials,
2267 \@hashValue1, \@hashValue2,
2268 \%conditionals, $justGenerateValueArray);
2270 if ($justGenerateValueArray) {
2271 push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
2273 push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, &${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
2276 if (PrototypeHasStaticPropertyTable($interface) && !IsDOMGlobalObject($interface)) {
2277 push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
2278 push(@implContent, "{\n");
2279 push(@implContent, " Base::finishCreation(vm);\n");
2280 push(@implContent, " reifyStaticProperties(vm, ${className}PrototypeTableValues, *this);\n");
2282 my @runtimeEnabledProperties = @runtimeEnabledFunctions;
2283 push(@runtimeEnabledProperties, @runtimeEnabledAttributes);
2284 foreach my $functionOrAttribute (@runtimeEnabledProperties) {
2285 my $signature = $functionOrAttribute->signature;
2286 my $conditionalString = $codeGenerator->GenerateConditionalString($signature);
2287 push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2288 AddToImplIncludes("RuntimeEnabledFeatures.h");
2289 my $enable_function = GetRuntimeEnableFunctionName($signature);
2290 my $name = $signature->name;
2291 push(@implContent, " if (!${enable_function}()) {\n");
2292 push(@implContent, " Identifier propertyName = Identifier::fromString(&vm, reinterpret_cast<const LChar*>(\"$name\"), strlen(\"$name\"));\n");
2293 push(@implContent, " VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);\n");
2294 push(@implContent, " JSObject::deleteProperty(this, globalObject()->globalExec(), propertyName);\n");
2295 push(@implContent, " }\n");
2296 push(@implContent, "#endif\n") if $conditionalString;
2299 my $firstPrivateFunction = 1;
2300 foreach my $function (@{$interface->functions}) {
2301 next unless ($function->signature->extendedAttributes->{"PrivateIdentifier"});
2302 AddToImplIncludes("WebCoreJSClientData.h");
2303 push(@implContent, " JSVMClientData& clientData = *static_cast<JSVMClientData*>(vm.clientData);\n") if $firstPrivateFunction;
2304 $firstPrivateFunction = 0;
2305 push(@implContent, " putDirect(vm, clientData.builtinNames()." . $function->signature->name . "PrivateName(), JSFunction::create(vm, globalObject(), 0, String(), " . GetFunctionName($interface, $className, $function) . "), ReadOnly | DontEnum);\n");
2308 if ($interface->iterable) {
2309 addIterableProperties($interface, $className);
2312 push(@implContent, "}\n\n");
2315 if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {
2316 push(@implContent, "bool ${className}Prototype::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
2317 push(@implContent, "{\n");
2318 push(@implContent, " auto* thisObject = jsCast<${className}Prototype*>(cell);\n");
2319 push(@implContent, " bool putResult = false;\n");
2320 push(@implContent, " if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
2321 push(@implContent, " return putResult;\n");
2322 push(@implContent, " return Base::put(thisObject, state, propertyName, value, slot);\n");
2323 push(@implContent, "}\n\n");
2326 # - Initialize static ClassInfo object
2327 push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleInterfaceName}\", &Base::s_info, ");
2329 if ($numInstanceProperties > 0) {
2330 push(@implContent, "&${className}Table");
2332 push(@implContent, "0");
2334 push(@implContent, ", CREATE_METHOD_TABLE($className) };\n\n");
2336 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($interfaceName);
2337 my $svgPropertyOrListPropertyType;
2338 $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
2339 $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
2342 if ($interfaceName eq "DOMWindow") {
2343 AddIncludesForTypeInImpl("JSDOMWindowShell");
2344 push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* shell)\n");
2345 push(@implContent, " : $parentClassName(vm, structure, WTFMove(impl), shell)\n");
2346 push(@implContent, "{\n");
2347 push(@implContent, "}\n\n");
2348 } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
2349 AddIncludesForTypeInImpl($interfaceName);
2350 push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl)\n");
2351 push(@implContent, " : $parentClassName(vm, structure, WTFMove(impl))\n");
2352 push(@implContent, "{\n");
2353 push(@implContent, "}\n\n");
2354 } elsif (!NeedsImplementationClass($interface)) {
2355 push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject& globalObject)\n");
2356 push(@implContent, " : $parentClassName(structure, globalObject) { }\n\n");
2358 push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject& globalObject, Ref<$implType>&& impl)\n");
2359 push(@implContent, " : $parentClassName(structure, globalObject, WTFMove(impl))\n");
2360 push(@implContent, "{\n");
2361 push(@implContent, "}\n\n");
2364 if (IsDOMGlobalObject($interface)) {
2365 if ($interfaceName eq "DOMWindow") {
2366 push(@implContent, "void ${className}::finishCreation(VM& vm, JSDOMWindowShell* shell)\n");
2367 push(@implContent, "{\n");
2368 push(@implContent, " Base::finishCreation(vm, shell);\n\n");
2370 push(@implContent, "void ${className}::finishCreation(VM& vm, JSProxy* proxy)\n");
2371 push(@implContent, "{\n");
2372 push(@implContent, " Base::finishCreation(vm, proxy);\n\n");
2374 # Support for RuntimeEnabled attributes on global objects.
2375 foreach my $attribute (@{$interface->attributes}) {
2376 next unless $attribute->signature->extendedAttributes->{"EnabledAtRuntime"};
2378 AddToImplIncludes("RuntimeEnabledFeatures.h");
2379 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2380 push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2381 my $enable_function = GetRuntimeEnableFunctionName($attribute->signature);
2382 my $attributeName = $attribute->signature->name;
2383 push(@implContent, " if (${enable_function}()) {\n");
2384 my $getter = GetAttributeGetterName($interface, $className, $attribute);
2385 my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interface, $className, $attribute);
2386 push(@implContent, " auto* customGetterSetter = CustomGetterSetter::create(vm, $getter, $setter);\n");
2387 my $jscAttributes = GetJSCAttributesForAttribute($interface, $attribute);
2388 push(@implContent, " putDirectCustomAccessor(vm, vm.propertyNames->$attributeName, customGetterSetter, attributesForStructure($jscAttributes));\n");
2389 push(@implContent, " }\n");
2390 push(@implContent, "#endif\n") if $conditionalString;
2393 # Support PrivateIdentifier attributes on global objects
2394 foreach my $attribute (@{$interface->attributes}) {
2395 next unless $attribute->signature->extendedAttributes->{"PrivateIdentifier"};
2397 AddToImplIncludes("WebCoreJSClientData.h");
2398 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2399 my $attributeName = $attribute->signature->name;
2400 my $getter = GetAttributeGetterName($interface, $className, $attribute);
2402 push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2403 push(@implContent, " putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames()." . $attributeName . "PrivateName(), CustomGetterSetter::create(vm, $getter, nullptr), attributesForStructure(DontDelete | ReadOnly));\n");
2404 push(@implContent, "#endif\n") if $conditionalString;
2407 # Support for RuntimeEnabled operations on global objects.
2408 foreach my $function (@{$interface->functions}) {
2409 next unless $function->signature->extendedAttributes->{"EnabledAtRuntime"};
2410 next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2412 AddToImplIncludes("RuntimeEnabledFeatures.h");
2413 my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2414 push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2415 my $enable_function = GetRuntimeEnableFunctionName($function->signature);
2416 my $functionName = $function->signature->name;
2417 my $implementationFunction = GetFunctionName($interface, $className, $function);
2418 my $functionLength = GetFunctionLength($function);
2419 my $jsAttributes = ComputeFunctionSpecial($interface, $function);
2420 push(@implContent, " if (${enable_function}())\n");
2422 my $propertyName = "vm.propertyNames->$functionName";
2423 if ($function->signature->extendedAttributes->{"PrivateIdentifier"}) {
2424 $propertyName = "static_cast<JSVMClientData*>(vm.clientData)->builtinNames()." . $functionName . "PrivateName()";
2426 if (IsJSBuiltin($interface, $function)) {
2427 push(@implContent, " putDirectBuiltinFunction(vm, this, $propertyName, $implementationFunction(vm), attributesForStructure($jsAttributes));\n");
2429 push(@implContent, " putDirectNativeFunction(vm, this, $propertyName, $functionLength, $implementationFunction, NoIntrinsic, attributesForStructure($jsAttributes));\n");
2431 push(@implContent, "#endif\n") if $conditionalString;
2433 push(@implContent, "}\n\n");
2436 unless (ShouldUseGlobalObjectPrototype($interface)) {
2437 push(@implContent, "JSObject* ${className}::createPrototype(VM& vm, JSGlobalObject* globalObject)\n");
2438 push(@implContent, "{\n");
2439 if ($interface->parent) {
2440 my $parentClassNameForPrototype = "JS" . $interface->parent;
2441 push(@implContent, " return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, ${parentClassNameForPrototype}::prototype(vm, globalObject)));\n");
2443 my $prototype = $interface->isException ? "errorPrototype" : "objectPrototype";
2444 push(@implContent, " return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, globalObject->${prototype}()));\n");
2446 push(@implContent, "}\n\n");
2448 push(@implContent, "JSObject* ${className}::prototype(VM& vm, JSGlobalObject* globalObject)\n");
2449 push(@implContent, "{\n");
2450 push(@implContent, " return getDOMPrototype<${className}>(vm, globalObject);\n");
2451 push(@implContent, "}\n\n");
2455 push(@implContent, "void ${className}::destroy(JSC::JSCell* cell)\n");
2456 push(@implContent, "{\n");
2457 push(@implContent, " ${className}* thisObject = static_cast<${className}*>(cell);\n");
2458 push(@implContent, " thisObject->${className}::~${className}();\n");
2459 push(@implContent, "}\n\n");
2462 my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
2466 if (!$interface->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
2467 push(@implContent, "bool ${className}::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)\n");
2468 push(@implContent, "{\n");
2469 push(@implContent, " auto* thisObject = jsCast<${className}*>(object);\n");
2470 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2471 push(@implContent, GenerateGetOwnPropertySlotBody($interface, $className, 0));
2472 push(@implContent, "}\n\n");
2475 if ($indexedGetterFunction || $namedGetterFunction
2476 || $interface->extendedAttributes->{"CustomNamedGetter"}
2477 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
2478 push(@implContent, "bool ${className}::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot)\n");
2479 push(@implContent, "{\n");
2480 push(@implContent, " auto* thisObject = jsCast<${className}*>(object);\n");
2481 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2483 # Sink the int-to-string conversion that happens when we create a PropertyName
2484 # to the point where we actually need it.
2485 my $generatedPropertyName = 0;
2486 my $propertyNameGeneration = sub {
2487 if ($generatedPropertyName) {
2490 push(@implContent, " Identifier propertyName = Identifier::from(state, index);\n");
2491 $generatedPropertyName = 1;
2494 if ($indexedGetterFunction) {
2495 if ($indexedGetterFunction->signature->type eq "DOMString") {
2496 push(@implContent, " if (LIKELY(index <= MAX_ARRAY_INDEX)) {\n");
2498 push(@implContent, " if (LIKELY(index < thisObject->wrapped().length())) {\n");
2500 # Assume that if there's a setter, the index will be writable
2501 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2502 push(@implContent, " unsigned attributes = DontDelete;\n");
2504 push(@implContent, " unsigned attributes = DontDelete | ReadOnly;\n");
2506 push(@implContent, " slot.setValue(thisObject, attributes, " . GetIndexedGetterExpression($indexedGetterFunction) . ");\n");
2507 push(@implContent, " return true;\n");
2508 push(@implContent, " }\n");
2511 # Indexing an object with an integer that is not a supported property index should not call the named property getter.
2512 # https://heycam.github.io/webidl/#idl-indexed-properties
2513 if (!$indexedGetterFunction && ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"})) {
2514 &$propertyNameGeneration();
2516 # This condition is to make sure we use the subclass' named getter instead of the base class one when possible.
2517 push(@implContent, " if (thisObject->classInfo() == info()) {\n");
2518 push(@implContent, " JSValue value;\n");
2519 push(@implContent, " if (thisObject->nameGetter(state, propertyName, value)) {\n");
2520 push(@implContent, " slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, value);\n");
2521 push(@implContent, " return true;\n");
2522 push(@implContent, " }\n");
2523 push(@implContent, " }\n");
2524 $implIncludes{"wtf/text/AtomicString.h"} = 1;
2527 if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
2528 &$propertyNameGeneration();
2529 push(@implContent, " if (thisObject->getOwnPropertySlotDelegate(state, propertyName, slot))\n");
2530 push(@implContent, " return true;\n");
2533 push(@implContent, " return Base::getOwnPropertySlotByIndex(thisObject, state, index, slot);\n");
2534 push(@implContent, "}\n\n");
2538 $numAttributes = $numAttributes + 1 if NeedsConstructorProperty($interface);
2539 if ($numAttributes > 0) {
2540 foreach my $attribute (@{$interface->attributes}) {
2541 next if IsJSBuiltin($interface, $attribute);
2543 my $name = $attribute->signature->name;
2544 my $type = $attribute->signature->type;
2545 $codeGenerator->AssertNotSequenceType($type);
2546 my $getFunctionName = GetAttributeGetterName($interface, $className, $attribute);
2547 my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->extendedAttributes->{"ImplementedAs"} || $name);
2548 my $getterExceptionsWithMessage = $attribute->signature->extendedAttributes->{"GetterRaisesExceptionWithMessage"};
2549 my $getterExceptions = $attribute->signature->extendedAttributes->{"GetterRaisesException"} || $getterExceptionsWithMessage;
2551 if ($getterExceptions) {
2552 $implIncludes{"ExceptionCode.h"} = 1;
2555 my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2556 push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2558 push(@implContent, "EncodedJSValue ${getFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
2559 push(@implContent, "{\n");
2561 push(@implContent, " UNUSED_PARAM(state);\n");
2562 push(@implContent, " UNUSED_PARAM(thisValue);\n");
2564 if (!$attribute->isStatic || $attribute->signature->type =~ /Constructor$/) {
2565 push(@implContent, " JSValue decodedThisValue = JSValue::decode(thisValue);\n");
2566 my $castingFunction = $interface->extendedAttributes->{"CustomProxyToJSObject"} ? "to${className}" : GetCastingHelperForThisObject($interface);
2567 # http://heycam.github.io/webidl/#ImplicitThis
2568 if ($interface->extendedAttributes->{"ImplicitThis"}) {
2569 push(@implContent, " auto* castedThis = decodedThisValue.isUndefinedOrNull() ? $castingFunction(state->thisValue().toThis(state, NotStrictMode)) : $castingFunction(decodedThisValue);\n");
2571 push(@implContent, " auto* castedThis = $castingFunction(decodedThisValue);\n");
2573 push(@implContent, " if (UNLIKELY(!castedThis)) {\n");
2574 if ($attribute->signature->extendedAttributes->{"LenientThis"}) {
2575 push(@implContent, " return JSValue::encode(jsUndefined());\n");
2576 } elsif (InterfaceRequiresAttributesOnInstanceForCompatibility($interface)) {
2577 # Fallback to trying to searching the prototype chain for compatibility reasons.
2578 push(@implContent, " JSObject* thisObject = JSValue::decode(thisValue).getObject();\n");
2579 push(@implContent, " for (thisObject = thisObject ? thisObject->getPrototypeDirect().getObject() : nullptr; thisObject; thisObject = thisObject->getPrototypeDirect().getObject()) {\n");
2580 push(@implContent, " if ((castedThis = " . GetCastingHelperForThisObject($interface) . "(thisObject)))\n");
2581 push(@implContent, " break;\n");
2582 push(@implContent, " }\n");
2583 push(@implContent, " if (!castedThis)\n");
2584 push(@implContent, " return throwGetterTypeError(*state, \"$interfaceName\", \"$name\");\n");
2585 push(@implContent, " reportDeprecatedGetterError(*state, \"$interfaceName\", \"$name\");\n");
2587 push(@implContent, " return throwGetterTypeError(*state, \"$interfaceName\", \"$name\");\n");
2589 push(@implContent, " }\n");
2593 if ($getterExceptions && !HasCustomGetter($attribute->signature->extendedAttributes)) {
2594 push(@arguments, "ec");
2595 if ($getterExceptionsWithMessage) {
2596 push(@implContent, " ExceptionCodeWithMessage ec;\n");
2598 push(@implContent, " ExceptionCode ec = 0;\n");
2602 # Global constructors can be disabled at runtime.
2603 if ($attribute->signature->type =~ /Constructor$/) {
2604 if ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) {
2605 AddToImplIncludes("Frame.h");
2606 AddToImplIncludes("Settings.h");
2607 my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{"EnabledBySetting"}) . "Enabled";
2608 push(@implContent, " if (UNLIKELY(!castedThis->wrapped().frame()))\n");
2609 push(@implContent, " return JSValue::encode(jsUndefined());\n");
2610 push(@implContent, " Settings& settings = castedThis->wrapped().frame()->settings();\n");
2611 push(@implContent, " if (!settings.$enable_function())\n");
2612 push(@implContent, " return JSValue::encode(jsUndefined());\n");
2616 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2617 $needsVisitChildren = 1;
2620 if ($interface->extendedAttributes->{"CheckSecurity"} &&
2621 !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"} &&
2622 !$attribute->signature->extendedAttributes->{"DoNotCheckSecurityOnGetter"}) {
2623 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, castedThis->wrapped()))\n");
2624 push(@implContent, " return JSValue::encode(jsUndefined());\n");
2627 if ($attribute->signature->extendedAttributes->{"Nondeterministic"}) {
2628 AddToImplIncludes("MemoizedDOMResult.h", "WEB_REPLAY");
2629 AddToImplIncludes("<replay/InputCursor.h>", "WEB_REPLAY");
2630 AddToImplIncludes("<wtf/NeverDestroyed.h>", "WEB_REPLAY");
2632 push(@implContent, "#if ENABLE(WEB_REPLAY)\n");
2633 push(@implContent, " JSGlobalObject* globalObject = state->lexicalGlobalObject();\n");
2634 push(@implContent, " InputCursor& cursor = globalObject->inputCursor();\n");
2636 my $nativeType = GetNativeType($interface, $type);
2637 my $memoizedType = GetNativeTypeForMemoization($interface, $type);
2638 my $exceptionCode = $getterExceptionsWithMessage ? "ec.code" : ($getterExceptions ? "ec" : "0");
2639 push(@implContent, " static NeverDestroyed<const AtomicString> bindingName(\"$interfaceName.$name\", AtomicString::ConstructFromLiteral);\n");
2640 push(@implContent, " if (cursor.isCapturing()) {\n");
2641 push(@implContent, " $memoizedType memoizedResult = castedThis->wrapped().$implGetterFunctionName(" . join(", ", @arguments) . ");\n");
2642 push(@implContent, " cursor.appendInput<MemoizedDOMResult<$memoizedType>>(bindingName.get().string(), memoizedResult, $exceptionCode);\n");
2643 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "memoizedResult", "castedThis") . ";\n");
2644 push(@implContent, " setDOMException(state, ec);\n") if $getterExceptions;
2645 push(@implContent, " return JSValue::encode(result);\n");
2646 push(@implContent, " }\n");
2647 push(@implContent, "\n");
2648 push(@implContent, " if (cursor.isReplaying()) {\n");
2649 push(@implContent, " $memoizedType memoizedResult;\n");
2650 push(@implContent, " MemoizedDOMResultBase* input = cursor.fetchInput<MemoizedDOMResultBase>();\n");
2651 push(@implContent, " if (input && input->convertTo<$memoizedType>(memoizedResult)) {\n");
2652 # FIXME: the generated code should report an error if an input cannot be fetched or converted.
2653 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "memoizedResult", "castedThis") . ";\n");
2654 push(@implContent, " setDOMException(state, input->exceptionCode());\n") if $getterExceptions;
2655 push(@implContent, " return JSValue::encode(result);\n");
2656 push(@implContent, " }\n");
2657 push(@implContent, " }\n");
2658 push(@implContent, "#endif\n");
2659 } # attribute Nondeterministic
2661 if (HasCustomGetter($attribute->signature->extendedAttributes)) {
2662 push(@implContent, " return JSValue::encode(castedThis->$implGetterFunctionName(*state));\n");
2663 } elsif ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
2664 $implIncludes{"JSDOMBinding.h"} = 1;
2665 push(@implContent, " auto& impl = castedThis->wrapped();\n");
2666 push(@implContent, " return JSValue::encode(shouldAllowAccessToNode(state, impl." . $attribute->signature->name . "()) ? " . NativeToJSValue($attribute->signature, 0, $interface, "impl.$implGetterFunctionName()", "castedThis") . " : jsNull());\n");
2667 } elsif ($type eq "EventHandler") {
2668 $implIncludes{"EventNames.h"} = 1;
2669 my $getter = $attribute->signature->extendedAttributes->{"WindowEventHandler"} ? "windowEventHandlerAttribute"
2670 : $attribute->signature->extendedAttributes->{"DocumentEventHandler"} ? "documentEventHandlerAttribute"
2671 : "eventHandlerAttribute";
2672 my $eventName = EventHandlerAttributeEventName($attribute);
2673 push(@implContent, " UNUSED_PARAM(state);\n");
2674 push(@implContent, " return JSValue::encode($getter(castedThis->wrapped(), $eventName));\n");
2675 } elsif ($attribute->signature->type =~ /Constructor$/) {
2676 my $constructorType = $attribute->signature->type;
2677 $constructorType =~ s/Constructor$//;
2678 # When Constructor attribute is used by DOMWindow.idl, it's correct to pass castedThis as the global object
2679 # When JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject()
2680 if ($interfaceName eq "DOMWindow") {
2681 my $named = ($constructorType =~ /Named$/) ? "Named" : "";
2682 $constructorType =~ s/Named$//;
2683 push(@implContent, " return JSValue::encode(JS" . $constructorType . "::get${named}Constructor(state->vm(), castedThis));\n");
2685 AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2686 push(@implContent, " return JSValue::encode(JS" . $constructorType . "::getConstructor(state->vm(), castedThis->globalObject()));\n");
2688 } elsif (!$attribute->signature->extendedAttributes->{"GetterRaisesException"} && !$attribute->signature->extendedAttributes->{"GetterRaisesExceptionWithMessage"}) {
2690 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2691 $cacheIndex = $currentCachedAttribute;
2692 $currentCachedAttribute++;
2693 push(@implContent, " if (JSValue cachedValue = castedThis->m_" . $attribute->signature->name . ".get())\n");
2694 push(@implContent, " return JSValue::encode(cachedValue);\n");
2697 my @callWithArgs = GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "JSValue::encode(jsUndefined())");
2699 if ($svgListPropertyType) {
2700 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "castedThis->wrapped().$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
2701 } elsif ($svgPropertyOrListPropertyType) {
2702 push(@implContent, " $svgPropertyOrListPropertyType& impl = castedThis->wrapped().propertyReference();\n");
2703 if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
2704 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "impl", "castedThis") . ";\n");
2706 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "impl.$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
2710 my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
2711 if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
2712 my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
2713 $implIncludes{"${implementedBy}.h"} = 1;
2714 $functionName = "WebCore::${implementedBy}::${functionName}";
2715 unshift(@arguments, "impl") if !$attribute->isStatic;
2716 } elsif ($attribute->isStatic) {
2717 $functionName = "${interfaceName}::${functionName}";
2719 $functionName = "impl.${functionName}";
2722 unshift(@arguments, @callWithArgs);
2723 my $jsType = NativeToJSValue($attribute->signature, 0, $interface, "${functionName}(" . join(", ", @arguments) . ")", "castedThis");
2724 push(@implContent, " auto& impl = castedThis->wrapped();\n") if !$attribute->isStatic;
2725 if ($codeGenerator->IsSVGAnimatedType($type)) {
2726 push(@implContent, " auto obj = $jsType;\n");
2727 push(@implContent, " JSValue result = toJS(state, castedThis->globalObject(), obj.get());\n");
2729 push(@implContent, " JSValue result = $jsType;\n");
2733 push(@implContent, " castedThis->m_" . $attribute->signature->name . ".set(state->vm(), castedThis, result);\n") if ($attribute->signature->extendedAttributes->{"CachedAttribute"});
2734 push(@implContent, " return JSValue::encode(result);\n");
2737 unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "JSValue::encode(jsUndefined())"));
2739 if ($svgPropertyOrListPropertyType) {
2740 push(@implContent, " $svgPropertyOrListPropertyType impl(*castedThis->wrapped());\n");
2741 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
2743 push(@implContent, " auto& impl = castedThis->wrapped();\n");
2744 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
2747 push(@implContent, " setDOMException(state, ec);\n");
2749 push(@implContent, " return JSValue::encode(result);\n");
2752 push(@implContent, "}\n\n");
2754 push(@implContent, "#endif\n") if $attributeConditionalString;
2756 push(@implContent, "\n");
2759 if (NeedsConstructorProperty($interface)) {
2760 my $constructorFunctionName = "js" . $interfaceName . "Constructor";
2762 push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
2763 push(@implContent, "{\n");
2764 push(@implContent, " ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue));\n");
2765 push(@implContent, " if (UNLIKELY(!domObject))\n");
2766 push(@implContent, " return throwVMTypeError(state);\n");
2768 if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
2769 push(@implContent, " return JSValue::encode(${className}::getConstructor(state->vm(), domObject->globalObject()));\n");
2771 push(@implContent, " JSValue constructor = ${className}Constructor::create(state->vm(), ${className}Constructor::createStructure(state->vm(), *domObject->globalObject(), domObject->globalObject()->objectPrototype()), *jsCast<JSDOMGlobalObject*>(domObject->globalObject()));\n");
2772 push(@implContent, " // Shadowing constructor property to ensure reusing the same constructor object\n");
2773 push(@implContent, " domObject->putDirect(state->vm(), state->propertyNames().constructor, constructor, DontEnum | ReadOnly);\n");
2774 push(@implContent, " return JSValue::encode(constructor);\n");
2776 push(@implContent, "}\n\n");
2779 my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2781 push(@implContent, "bool ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
2782 push(@implContent, "{\n");
2783 push(@implContent, " JSValue value = JSValue::decode(encodedValue);\n");
2784 push(@implContent, " ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue));\n");
2785 push(@implContent, " if (UNLIKELY(!domObject)) {\n");
2786 push(@implContent, " throwVMTypeError(state);\n");
2787 push(@implContent, " return false;\n");
2788 push(@implContent, " }\n");
2790 push(@implContent, " // Shadowing a built-in constructor\n");
2792 push(@implContent, " return domObject->putDirect(state->vm(), state->propertyNames().constructor, value);\n");
2793 push(@implContent, "}\n\n");
2795 my $hasCustomSetter = $interface->extendedAttributes->{"CustomNamedSetter"}
2796 || $interface->extendedAttributes->{"CustomIndexedSetter"};
2798 if ($hasCustomSetter) {
2799 if (!$interface->extendedAttributes->{"CustomPutFunction"}) {
2800 push(@implContent, "bool ${className}::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
2801 push(@implContent, "{\n");
2802 push(@implContent, " auto* thisObject = jsCast<${className}*>(cell);\n");
2803 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2804 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2805 push(@implContent, " if (Optional<uint32_t> index = parseIndex(propertyName)) {\n");
2806 push(@implContent, " thisObject->indexSetter(state, index.value(), value);\n");
2807 push(@implContent, " return true;\n");
2808 push(@implContent, " }\n");
2810 if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2811 push(@implContent, " bool putResult = false;\n");
2812 push(@implContent, " if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
2813 push(@implContent, " return putResult;\n");
2816 push(@implContent, " return Base::put(thisObject, state, propertyName, value, slot);\n");
2817 push(@implContent, "}\n\n");
2819 if ($interface->extendedAttributes->{"CustomIndexedSetter"} || $interface->extendedAttributes->{"CustomNamedSetter"}) {
2820 push(@implContent, "bool ${className}::putByIndex(JSCell* cell, ExecState* state, unsigned index, JSValue value, bool shouldThrow)\n");
2821 push(@implContent, "{\n");
2822 push(@implContent, " auto* thisObject = jsCast<${className}*>(cell);\n");
2823 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2825 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2826 push(@implContent, " if (LIKELY(index <= MAX_ARRAY_INDEX)) {\n");
2827 push(@implContent, " thisObject->indexSetter(state, index, value);\n");
2828 push(@implContent, " return true;\n");
2829 push(@implContent, " }\n");
2832 if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2833 push(@implContent, " Identifier propertyName = Identifier::from(state, index);\n");
2834 push(@implContent, " PutPropertySlot slot(thisObject, shouldThrow);\n");
2835 push(@implContent, " bool putResult = false;\n");
2836 push(@implContent, " if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
2837 push(@implContent, " return putResult;\n");
2840 push(@implContent, " return Base::putByIndex(cell, state, index, value, shouldThrow);\n");
2841 push(@implContent, "}\n\n");
2846 foreach my $attribute (@{$interface->attributes}) {
2847 if (!IsReadonly($attribute)) {
2848 next if IsJSBuiltin($interface, $attribute);
2850 my $name = $attribute->signature->name;
2851 my $type = $attribute->signature->type;
2852 my $putFunctionName = GetAttributeSetterName($interface, $className, $attribute);
2853 my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
2854 my $setterRaisesExceptionWithMessage = $attribute->signature->extendedAttributes->{"SetterRaisesExceptionWithMessage"};
2855 my $setterRaisesException = $attribute->signature->extendedAttributes->{"SetterRaisesException"} || $setterRaisesExceptionWithMessage;
2857 if ($setterRaisesException) {
2858 $implIncludes{"ExceptionCode.h"} = 1;
2861 my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2862 push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2864 push(@implContent, "bool ${putFunctionName}(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
2865 push(@implContent, "{\n");
2866 push(@implContent, " JSValue value = JSValue::decode(encodedValue);\n");
2867 push(@implContent, " UNUSED_PARAM(thisValue);\n") if !$attribute->isStatic;
2868 if (!$attribute->isStatic) {
2869 if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
2870 push(@implContent, " ${className}* castedThis = to${className}(JSValue::decode(thisValue));\n");
2872 push(@implContent, " ${className}* castedThis = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
2874 push(@implContent, " if (UNLIKELY(!castedThis)) {\n");
2875 if ($attribute->signature->extendedAttributes->{"LenientThis"}) {
2876 push(@implContent, " return false;\n");
2877 } elsif (InterfaceRequiresAttributesOnInstanceForCompatibility($interface)) {
2878 # Fallback to trying to searching the prototype chain for compatibility reasons.
2879 push(@implContent, " JSObject* thisObject = JSValue::decode(thisValue).getObject();\n");
2880 push(@implContent, " for (thisObject = thisObject ? thisObject->getPrototypeDirect().getObject() : nullptr; thisObject; thisObject = thisObject->getPrototypeDirect().getObject()) {\n");
2881 push(@implContent, " if ((castedThis = " . GetCastingHelperForThisObject($interface) . "(thisObject)))\n");
2882 push(@implContent, " break;\n");
2883 push(@implContent, " }\n");
2884 push(@implContent, " if (!castedThis)\n");
2885 push(@implContent, " return throwSetterTypeError(*state, \"$interfaceName\", \"$name\");\n");
2886 push(@implContent, " reportDeprecatedSetterError(*state, \"$interfaceName\", \"$name\");\n");
2888 push(@implContent, " return throwSetterTypeError(*state, \"$interfaceName\", \"$name\");\n");
2890 push(@implContent, " }\n");
2892 if ($interface->extendedAttributes->{"CheckSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2893 if ($interfaceName eq "DOMWindow") {
2894 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, castedThis->wrapped()))\n");
2896 push(@implContent, " if (!shouldAllowAccessToFrame(state, castedThis->wrapped().frame()))\n");
2898 push(@implContent, " return false;\n");
2901 if (HasCustomSetter($attribute->signature->extendedAttributes)) {
2902 push(@implContent, " castedThis->set$implSetterFunctionName(*state, value);\n");
2903 push(@implContent, " return true;\n");
2904 } elsif ($type eq "EventHandler") {
2905 $implIncludes{"JSEventListener.h"} = 1;
2906 my $eventName = EventHandlerAttributeEventName($attribute);
2907 # FIXME: Find a way to do this special case without hardcoding the class and attribute names here.
2908 if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerGlobalScope")) and $name eq "onerror") {
2909 $implIncludes{"JSErrorHandler.h"} = 1;
2910 push(@implContent, " castedThis->wrapped().setAttributeEventListener($eventName, createJSErrorHandler(state, value, castedThis));\n");
2912 $implIncludes{"JSEventListener.h"} = 1;
2913 my $setter = $attribute->signature->extendedAttributes->{"WindowEventHandler"} ? "setWindowEventHandlerAttribute"
2914 : $attribute->signature->extendedAttributes->{"DocumentEventHandler"} ? "setDocumentEventHandlerAttribute"
2915 : "setEventHandlerAttribute";
2916 push(@implContent, " $setter(*state, *castedThis, castedThis->wrapped(), $eventName, value);\n");
2918 push(@implContent, " return true;\n");
2919 } elsif ($type =~ /Constructor$/) {
2920 my $constructorType = $type;
2921 $constructorType =~ s/Constructor$//;
2922 # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
2923 # We do not generate the header file for NamedConstructor of class XXXX,
2924 # since we generate the NamedConstructor declaration into the header file of class XXXX.
2925 if ($constructorType ne "any" and $constructorType !~ /Named$/) {
2926 AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2928 push(@implContent, " // Shadowing a built-in constructor.\n");
2929 push(@implContent, " return castedThis->putDirect(state->vm(), Identifier::fromString(state, \"$name\"), value);\n");
2930 } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
2931 push(@implContent, " // Shadowing a built-in property.\n");
2932 if (AttributeShouldBeOnInstance($interface, $attribute)) {
2933 push(@implContent, " return replaceStaticPropertySlot(state->vm(), castedThis, Identifier::fromString(state, \"$name\"), value);\n");
2935 push(@implContent, " return castedThis->putDirect(state->vm(), Identifier::fromString(state, \"$name\"), value);\n");
2938 if (!$attribute->isStatic) {
2939 my $putForwards = $attribute->signature->extendedAttributes->{"PutForwards"};
2941 my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->extendedAttributes->{"ImplementedAs"} || $name);
2942 if ($attribute->signature->isNullable) {
2943 push(@implContent, " RefPtr<${type}> forwardedImpl = castedThis->wrapped().${implGetterFunctionName}();\n");
2944 push(@implContent, " if (!forwardedImpl)\n");
2945 push(@implContent, " return false;\n");
2946 push(@implContent, " auto& impl = *forwardedImpl;\n");
2948 # Attribute is not nullable, the implementation is expected to return a reference.
2949 push(@implContent, " Ref<${type}> forwardedImpl = castedThis->wrapped().${implGetterFunctionName}();\n");
2950 push(@implContent, " auto& impl = forwardedImpl.get();\n");
2952 $attribute = $codeGenerator->GetAttributeFromInterface($interface, $type, $putForwards);
2954 push(@implContent, " auto& impl = castedThis->wrapped();\n");
2957 if ($setterRaisesExceptionWithMessage) {
2958 push(@implContent, " ExceptionCodeWithMessage ec;\n");
2959 } elsif ($setterRaisesException) {
2960 push(@implContent, " ExceptionCode ec = 0;\n");
2963 my $shouldPassByReference = ShouldPassWrapperByReference($attribute->signature, $interface);
2965 # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
2966 # interface type, then if the incoming value does not implement that interface, a TypeError
2967 # is thrown rather than silently passing NULL to the C++ code.
2968 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to
2969 # both strings and numbers, so do not throw TypeError if the attribute is of these types.
2970 my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $attribute->signature, "value", $attribute->signature->extendedAttributes->{"Conditional"});
2971 if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"} && !$shouldPassByReference && $codeGenerator->IsWrapperType($type)) {
2972 $implIncludes{"<runtime/Error.h>"} = 1;
2973 push(@implContent, " " . GetNativeTypeFromSignature($interface, $attribute->signature) . " nativeValue = nullptr;\n");
2974 push(@implContent, " if (!value.isUndefinedOrNull()) {\n");
2975 push(@implContent, " nativeValue = $nativeValue;\n");
2976 if ($mayThrowException) {
2977 push(@implContent, " if (UNLIKELY(state->hadException()))\n");
2978 push(@implContent, " return false;\n");
2980 push(@implContent, " if (UNLIKELY(!nativeValue)) {\n");
2981 push(@implContent, " throwAttributeTypeError(*state, \"$interfaceName\", \"$name\", \"$type\");\n");
2982 push(@implContent, " return false;\n");
2983 push(@implContent, " }\n");
2984 push(@implContent, " }\n");
2986 push(@implContent, " auto nativeValue = $nativeValue;\n");
2987 if ($mayThrowException) {
2988 push(@implContent, " if (UNLIKELY(state->hadException()))\n");
2989 push(@implContent, " return false;\n");
2993 if ($codeGenerator->IsEnumType($type)) {
2994 push (@implContent, " if (UNLIKELY(!nativeValue))\n");
2995 push (@implContent, " return false;\n");
2998 if ($shouldPassByReference) {
2999 push(@implContent, " if (UNLIKELY(!nativeValue)) {\n");
3000 push(@implContent, " throwAttributeTypeError(*state, \"$interfaceName\", \"$name\", \"$type\");\n");
3001 push(@implContent, " return false;\n");
3002 push(@implContent, " }\n");
3005 if ($svgPropertyOrListPropertyType) {
3006 if ($svgPropertyType) {
3007 push(@implContent, " if (impl.isReadOnly()) {\n");
3008 push(@implContent, " setDOMException(state, NO_MODIFICATION_ALLOWED_ERR);\n");
3009 push(@implContent, " return false;\n");
3010 push(@implContent, " }\n");
3011 $implIncludes{"ExceptionCode.h"} = 1;
3013 push(@implContent, " $svgPropertyOrListPropertyType& podImpl = impl.propertyReference();\n");
3014 if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
3015 push(@implContent, " podImpl = nativeValue;\n");
3017 push(@implContent, " podImpl.set$implSetterFunctionName(nativeValue");
3018 push(@implContent, ", ec") if $setterRaisesException;
3019 push(@implContent, ");\n");
3020 push(@implContent, " setDOMException(state, ec);\n") if $setterRaisesException;
3022 if ($svgPropertyType) {
3023 if ($setterRaisesExceptionWithMessage) {
3024 push(@implContent, " if (LIKELY(!ec.code))\n");
3025 push(@implContent, " impl.commitChange();\n");
3026 } elsif ($setterRaisesException) {
3027 push(@implContent, " if (LIKELY(!ec))\n");
3028 push(@implContent, " impl.commitChange();\n");
3030 push(@implContent, " impl.commitChange();\n");
3033 push(@implContent, " return true;\n");
3035 my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
3036 if ($codeGenerator->IsTypedArrayType($type) and not $type eq "ArrayBuffer") {
3037 push(@arguments, "nativeValue.get()");
3038 } elsif ($codeGenerator->IsEnumType($type)) {
3039 push(@arguments, "nativeValue.value()");
3041 push(@arguments, $shouldPassByReference ? "*nativeValue" : "WTFMove(nativeValue)");
3043 if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
3044 my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
3045 AddToImplIncludes("${implementedBy}.h", $attribute->signature->extendedAttributes->{"Conditional"});
3046 unshift(@arguments, "impl") if !$attribute->isStatic;
3047 $functionName = "WebCore::${implementedBy}::${functionName}";
3048 } elsif ($attribute->isStatic) {
3049 $functionName = "${interfaceName}::${functionName}";
3051 $functionName = "impl.${functionName}";
3054 unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"SetterCallWith"}, \@implContent, "false"));
3055 unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "false"));
3057 push(@arguments, "ec") if $setterRaisesException;
3058 push(@implContent, " ${functionName}(" . join(", ", @arguments) . ");\n");
3059 push(@implContent, " setDOMException(state, ec);\n") if $setterRaisesException;
3060 push(@implContent, " return true;\n");
3064 push(@implContent, "}\n\n");
3065 push(@implContent, "#endif\n") if $attributeConditionalString;
3066 push(@implContent, "\n");
3070 if (($indexedGetterFunction || $namedGetterFunction) && !$interface->extendedAttributes->{"CustomEnumerateProperty"}) {
3071 push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* state, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
3072 push(@implContent, "{\n");
3073 push(@implContent, " auto* thisObject = jsCast<${className}*>(object);\n");
3074 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
3075 if ($indexedGetterFunction) {
3076 push(@implContent, " for (unsigned i = 0, count = thisObject->wrapped().length(); i < count; ++i)\n");
3077 push(@implContent, " propertyNames.add(Identifier::from(state, i));\n");
3079 if ($namedGetterFunction) {
3080 # FIXME: We may need to add an IDL extended attribute at some point if an interface needs enumerable named properties.
3081 push(@implContent, " if (mode.includeDontEnumProperties()) {\n");
3082 push(@implContent, " for (auto& propertyName : thisObject->wrapped().supportedPropertyNames())\n");
3083 push(@implContent, " propertyNames.add(Identifier::fromString(state, propertyName));\n");
3084 push(@implContent, " }\n");
3086 push(@implContent, " Base::getOwnPropertyNames(thisObject, state, propertyNames, mode);\n");
3087 push(@implContent, "}\n\n");
3090 if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
3091 push(@implContent, "JSValue ${className}::getConstructor(VM& vm, const JSGlobalObject* globalObject)\n{\n");
3092 push(@implContent, " return getDOMConstructor<${className}Constructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));\n");
3093 push(@implContent, "}\n\n");
3094 if ($interface->extendedAttributes->{"NamedConstructor"}) {
3095 push(@implContent, "JSValue ${className}::getNamedConstructor(VM& vm, JSGlobalObject* globalObject)\n{\n");
3096 push(@implContent, " return getDOMConstructor<${className}NamedConstructor>(vm, *jsCast<JSDOMGlobalObject*>(globalObject));\n");
3097 push(@implContent, "}\n\n");
3102 if ($numFunctions > 0) {
3103 my $inAppleCopyright = 0;
3104 foreach my $function (@{$interface->functions}) {
3105 next if IsJSBuiltin($interface, $function);
3106 my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
3107 if ($needsAppleCopyright) {
3108 if (!$inAppleCopyright) {
3109 push(@implContent, $beginAppleCopyrightForSourceFiles);
3110 $inAppleCopyright = 1;
3112 } elsif ($inAppleCopyright) {
3113 push(@implContent, $endAppleCopyright);
3114 $inAppleCopyright = 0;
3117 my $isCustom = HasCustomMethod($function->signature->extendedAttributes);
3118 my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
3120 die "RaisesException and RaisesExceptionWithMessage are mutually exclusive" if $function->signature->extendedAttributes->{"RaisesException"} && $function->signature->extendedAttributes->{"RaisesExceptionWithMessage"};
3122 my $raisesExceptionWithMessage = $function->signature->extendedAttributes->{"RaisesExceptionWithMessage"};
3123 my $raisesException = $function->signature->extendedAttributes->{"RaisesException"} || $raisesExceptionWithMessage;
3125 next if $isCustom && $isOverloaded && $function->{overloadIndex} > 1;
3127 AddIncludesForTypeInImpl($function->signature->type) unless $isCustom or IsReturningPromise($function);
3129 my $functionName = GetFunctionName($interface, $className, $function);
3131 my $conditional = $function->signature->extendedAttributes->{"Conditional"};
3133 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
3134 push(@implContent, "#if ${conditionalString}\n");
3137 my $functionReturn = "EncodedJSValue JSC_HOST_CALL";
3138 if (!$isCustom && $isOverloaded) {
3139 # Append a number to an overloaded method's name to make it unique:
3140 $functionName = $functionName . $function->{overloadIndex};
3141 # Make this function static to avoid compiler warnings, since we don't generate a prototype for it in the header.
3142 $functionReturn = "static inline EncodedJSValue";
3145 my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
3147 if (IsReturningPromise($function) && !$isCustom) {
3148 AddToImplIncludes("JSDOMPromise.h");
3150 push(@implContent, <<END);
3151 static EncodedJSValue ${functionName}Promise(ExecState*, JSPromiseDeferred*);
3152 ${functionReturn} ${functionName}(ExecState* state)
3154 return JSValue::encode(callPromiseFunction(*state, ${functionName}Promise));
3157 static inline EncodedJSValue ${functionName}Promise(ExecState* state, JSPromiseDeferred* promiseDeferred)
3161 push(@implContent, "${functionReturn} ${functionName}(ExecState* state)\n");
3164 push(@implContent, "{\n");
3166 $implIncludes{"<runtime/Error.h>"} = 1;
3168 if ($function->signature->extendedAttributes->{"InvokesCustomElementLifecycleCallbacks"}) {
3169 push(@implContent, "#if ENABLE(CUSTOM_ELEMENTS)\n");
3170 push(@implContent, " CustomElementLifecycleProcessingStack customElementLifecycleProcessingStack;\n");
3171 push(@implContent, "#endif\n");
3172 $implIncludes{"LifecycleCallbackQueue.h"} = 1;
3175 if ($function->isStatic) {
3177 GenerateArgumentsCountCheck(\@implContent, $function, $interface);
3178 push(@implContent, " return JSValue::encode(${className}::" . $functionImplementationName . "(state));\n");
3180 GenerateArgumentsCountCheck(\@implContent, $function, $interface);
3182 if ($raisesExceptionWithMessage) {
3183 push(@implContent, " ExceptionCodeWithMessage ec;\n");
3184 } elsif ($raisesException) {
3185 push(@implContent, " ExceptionCode ec = 0;\n");
3188 my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
3189 GenerateImplementationFunctionCall($function, $functionString, " ", $svgPropertyType, $interface);
3192 GenerateFunctionCastedThis($interface, $className, $function);
3194 if ($interface->extendedAttributes->{"CheckSecurity"} and
3195 !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
3196 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, castedThis->wrapped()))\n");
3197 push(@implContent, " return JSValue::encode(jsUndefined());\n");
3201 push(@implContent, " return JSValue::encode(castedThis->" . $functionImplementationName . "(*state));\n");
3203 push(@implContent, " auto& impl = castedThis->wrapped();\n");
3204 if ($svgPropertyType) {
3205 push(@implContent, " if (impl.isReadOnly()) {\n");
3206 push(@implContent, " setDOMException(state, NO_MODIFICATION_ALLOWED_ERR);\n");
3207 push(@implContent, " return JSValue::encode(jsUndefined());\n");
3208 push(@implContent, " }\n");
3209 push(@implContent, " $svgPropertyType& podImpl = impl.propertyReference();\n");
3210 $implIncludes{"ExceptionCode.h"} = 1;
3213 # EventTarget needs to do some extra checks if castedThis is a JSDOMWindow.
3214 if ($interface->name eq "EventTarget") {
3215 $implIncludes{"DOMWindow.h"} = 1;
3216 push(@implContent, " if (auto* window = castedThis->wrapped().toDOMWindow()) {\n");
3217 push(@implContent, " if (!window->frame() || !BindingSecurity::shouldAllowAccessToDOMWindow(state, *window))\n");
3218 push(@implContent, " return JSValue::encode(jsUndefined());\n");
3219 push(@implContent, " }\n");
3222 GenerateArgumentsCountCheck(\@implContent, $function, $interface);
3224 if ($raisesExceptionWithMessage) {
3225 push(@implContent, " ExceptionCodeWithMessage ec;\n");
3226 } elsif ($raisesException) {
3227 push(@implContent, " ExceptionCode ec = 0;\n");
3230 if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) {
3231 push(@implContent, " if (!shouldAllowAccessToNode(state, impl." . $function->signature->name . "(" . ($raisesException ? "ec" : "") .")))\n");
3232 push(@implContent, " return JSValue::encode(jsNull());\n");
3233 $implIncludes{"JSDOMBinding.h"} = 1;
3236 my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
3237 GenerateImplementationFunctionCall($function, $functionString, " ", $svgPropertyType, $interface);
3241 push(@implContent, "}\n\n");
3242 push(@implContent, "#endif\n\n") if $conditional;
3244 # Generate a function dispatching call to the rest of the overloads.
3245 GenerateOverloadedFunction($function, $interface) if !$isCustom && $isOverloaded && $function->{overloadIndex} == @{$function->{overloads}};
3248 push(@implContent, $endAppleCopyright) if $inAppleCopyright;
3252 if ($interface->iterable) {
3253 GenerateImplementationIterableFunctions($interface);
3256 if ($needsVisitChildren) {
3257 push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n");
3258 push(@implContent, "{\n");
3259 push(@implContent, " auto* thisObject = jsCast<${className}*>(cell);\n");
3260 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
3261 push(@implContent, " Base::visitChildren(thisObject, visitor);\n");
3262 if ($codeGenerator->InheritsInterface($interface, "EventTarget")) {
3263 push(@implContent, " thisObject->wrapped().visitJSEventListeners(visitor);\n");
3265 push(@implContent, " thisObject->visitAdditionalChildren(visitor);\n") if $interface->extendedAttributes->{"JSCustomMarkFunction"};
3266 if ($interface->extendedAttributes->{"ReportExtraMemoryCost"}) {
3267 push(@implContent, " visitor.reportExtraMemoryVisited(thisObject->wrapped().memoryCost());\n");
3268 if ($interface->extendedAttributes->{"ReportExternalMemoryCost"}) {;
3269 push(@implContent, "#if ENABLE(RESOURCE_USAGE)\n");
3270 push(@implContent, " visitor.reportExternalMemoryVisited(thisObject->wrapped().externalMemoryCost());\n");
3271 push(@implContent, "#endif\n");
3274 if ($numCachedAttributes > 0) {
3275 foreach (@{$interface->attributes}) {
3277 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
3278 push(@implContent, " visitor.append(&thisObject->m_" . $attribute->signature->name . ");\n");
3282 push(@implContent, "}\n\n");
3285 if (InstanceNeedsEstimatedSize($interface)) {
3286 push(@implContent, "size_t ${className}::estimatedSize(JSCell* cell)\n");
3287 push(@implContent, "{\n");
3288 push(@implContent, " auto* thisObject = jsCast<${className}*>(cell);\n");
3289 push(@implContent, " return Base::estimatedSize(thisObject) + thisObject->wrapped().memoryCost();\n");
3290 push(@implContent, "}\n\n");
3293 # Cached attributes are indeed allowed when there is a custom mark/visitChildren function.
3294 # The custom function must make sure to account for the cached attribute.
3295 # Uncomment the below line to temporarily enforce generated mark functions when cached attributes are present.
3296 # die "Can't generate binding for class with cached attribute and custom mark." if (($numCachedAttributes > 0) and ($interface->extendedAttributes->{"JSCustomMarkFunction"}));
3298 if ($indexedGetterFunction) {
3299 if ($indexedGetterFunction->signature->type eq "DOMString") {
3300 $implIncludes{"URL.h"} = 1;
3302 if ($interfaceName =~ /^HTML\w*Collection$/ or $interfaceName eq "RadioNodeList") {
3303 $implIncludes{"JSNode.h"} = 1;
3304 $implIncludes{"Node.h"} = 1;
3308 if (ShouldGenerateWrapperOwnerCode($hasParent, $interface) && !GetCustomIsReachable($interface)) {
3309 push(@implContent, "bool JS${interfaceName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)\n");
3310 push(@implContent, "{\n");
3311 # All ActiveDOMObjects implement hasPendingActivity(), but not all of them
3312 # increment their C++ reference counts when hasPendingActivity() becomes
3313 # true. As a result, ActiveDOMObjects can be prematurely destroyed before
3314 # their pending activities complete. To wallpaper over this bug, JavaScript
3315 # wrappers unconditionally keep ActiveDOMObjects with pending activity alive.
3316 # FIXME: Fix this lifetime issue in the DOM, and move this hasPendingActivity
3317 # check just above the (GetGenerateIsReachable($interface) eq "Impl") check below.
3318 my $emittedJSCast = 0;
3319 if ($codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
3320 push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
3322 push(@implContent, " if (js${interfaceName}->wrapped().hasPendingActivity())\n");
3323 push(@implContent, " return true;\n");
3325 if ($codeGenerator->InheritsInterface($interface, "EventTarget")) {
3326 if (!$emittedJSCast) {
3327 push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
3330 push(@implContent, " if (js${interfaceName}->wrapped().isFiringEventListeners())\n");
3331 push(@implContent, " return true;\n");
3333 if ($codeGenerator->InheritsInterface($interface, "Node")) {
3334 if (!$emittedJSCast) {
3335 push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
3338 push(@implContent, " if (JSNodeOwner::isReachableFromOpaqueRoots(handle, 0, visitor))\n");
3339 push(@implContent, " return true;\n");
3341 if (GetGenerateIsReachable($interface)) {
3342 if (!$emittedJSCast) {
3343 push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
3348 if (GetGenerateIsReachable($interface) eq "Impl") {
3349 $rootString = " ${implType}* root = &js${interfaceName}->wrapped();\n";
3350 } elsif (GetGenerateIsReachable($interface) eq "ImplWebGLRenderingContext") {
3351 $rootString = " WebGLRenderingContextBase* root = WTF::getPtr(js${interfaceName}->wrapped().context());\n";
3352 } elsif (GetGenerateIsReachable($interface) eq "ImplFrame") {
3353 $rootString = " Frame* root = WTF::getPtr(js${interfaceName}->wrapped().frame());\n";
3354 $rootString .= " if (!root)\n";
3355 $rootString .= " return false;\n";
3356 } elsif (GetGenerateIsReachable($interface) eq "ImplDocument") {
3357 $rootString = " Document* root = WTF::getPtr(js${interfaceName}->wrapped().document());\n";
3358 $rootString .= " if (!root)\n";
3359 $rootString .= " return false;\n";
3360 } elsif (GetGenerateIsReachable($interface) eq "ImplElementRoot") {
3361 $implIncludes{"Element.h"} = 1;
3362 $implIncludes{"JSNodeCustom.h"} = 1;
3363 $rootString = " Element* element = WTF::getPtr(js${interfaceName}->wrapped().element());\n";
3364 $rootString .= " if (!element)\n";
3365 $rootString .= " return false;\n";
3366 $rootString .= " void* root = WebCore::root(element);\n";
3367 } elsif ($interfaceName eq "CanvasRenderingContext") {
3368 $implIncludes{"Element.h"} = 1;
3369 $implIncludes{"JSNodeCustom.h"} = 1;
3370 $rootString = " void* root = WebCore::root(js${interfaceName}->wrapped().canvas());\n";
3371 } elsif (GetGenerateIsReachable($interface) eq "ImplOwnerNodeRoot") {
3372 $implIncludes{"Element.h"} = 1;
3373 $implIncludes{"JSNodeCustom.h"} = 1;
3374 $rootString = " void* root = WebCore::root(js${interfaceName}->wrapped().ownerNode());\n";
3376 $rootString = " void* root = WebCore::root(&js${interfaceName}->wrapped());\n";
3379 push(@implContent, $rootString);
3380 push(@implContent, " return visitor.containsOpaqueRoot(root);\n");
3382 if (!$emittedJSCast) {
3383 push(@implContent, " UNUSED_PARAM(handle);\n");
3385 push(@implContent, " UNUSED_PARAM(visitor);\n");
3386 push(@implContent, " return false;\n");
3388 push(@implContent, "}\n\n");
3391 if (ShouldGenerateWrapperOwnerCode($hasParent, $interface) && !$interface->extendedAttributes->{"JSCustomFinalize"}) {
3392 push(@implContent, "void JS${interfaceName}Owner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)\n");
3393 push(@implContent, "{\n");
3394 push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
3395 push(@implContent, " auto& world = *static_cast<DOMWrapperWorld*>(context);\n");
3396 push(@implContent, " uncacheWrapper(world, &js${interfaceName}->wrapped(), js${interfaceName});\n");
3397 push(@implContent, "}\n\n");
3400 if (ShouldGenerateToJSImplementation($hasParent, $interface)) {
3401 my $vtableNameGnu = GetGnuVTableNameForInterface($interface);
3402 my $vtableRefGnu = GetGnuVTableRefForInterface($interface);
3403 my $vtableRefWin = GetWinVTableRefForInterface($interface);
3405 push(@implContent, <<END) if $vtableNameGnu;
3406 #if ENABLE(BINDING_INTEGRITY)
3408 #pragma warning(disable: 4483)
3409 extern "C" { extern void (*const ${vtableRefWin}[])(); }
3411 extern "C" { extern void* ${vtableNameGnu}[]; }