Update serializer and iterator binding generated code
[WebKit-https.git] / Source / WebCore / bindings / scripts / CodeGeneratorJS.pm
1 #
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.
15 #
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.
20 #
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.
25 #
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.
30
31
32 package CodeGeneratorJS;
33
34 use strict;
35 use constant FileNamePrefix => "JS";
36 use Carp qw<longmess>;
37 use Data::Dumper;
38 use Hasher;
39
40 my $codeGenerator;
41 my $writeDependencies;
42
43 my @headerContentHeader = ();
44 my @headerContent = ();
45 my %headerIncludes = ();
46 my %headerTrailingIncludes = ();
47
48 my @implContentHeader = ();
49 my @implContent = ();
50 my %implIncludes = ();
51 my @depsContent = ();
52 my $numCachedAttributes = 0;
53 my $currentCachedAttribute = 0;
54
55 my $beginAppleCopyrightForHeaderFiles = <<END;
56 // ------- Begin Apple Copyright -------
57 /*
58  * Copyright (C) 2008, Apple Inc. All rights reserved.
59  *
60  * Permission is granted by Apple to use this file to the extent
61  * necessary to relink with LGPL WebKit files.
62  *
63  * No license or rights are granted by Apple expressly or by
64  * implication, estoppel, or otherwise, to Apple patents and
65  * trademarks. For the sake of clarity, no license or rights are
66  * granted by Apple expressly or by implication, estoppel, or otherwise,
67  * under any Apple patents, copyrights and trademarks to underlying
68  * implementations of any application programming interfaces (APIs)
69  * or to any functionality that is invoked by calling any API.
70  */
71
72 END
73 my $beginAppleCopyrightForSourceFiles = <<END;
74 // ------- Begin Apple Copyright -------
75 /*
76  * Copyright (C) 2008, Apple Inc. All rights reserved.
77  *
78  * No license or rights are granted by Apple expressly or by implication,
79  * estoppel, or otherwise, to Apple copyrights, patents, trademarks, trade
80  * secrets or other rights.
81  */
82
83 END
84 my $endAppleCopyright   = <<END;
85 // ------- End Apple Copyright   -------
86
87 END
88
89 # Default .h template
90 my $headerTemplate = << "EOF";
91 /*
92     This file is part of the WebKit open source project.
93     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
94
95     This library is free software; you can redistribute it and/or
96     modify it under the terms of the GNU Library General Public
97     License as published by the Free Software Foundation; either
98     version 2 of the License, or (at your option) any later version.
99
100     This library is distributed in the hope that it will be useful,
101     but WITHOUT ANY WARRANTY; without even the implied warranty of
102     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
103     Library General Public License for more details.
104
105     You should have received a copy of the GNU Library General Public License
106     along with this library; see the file COPYING.LIB.  If not, write to
107     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
108     Boston, MA 02110-1301, USA.
109 */
110 EOF
111
112 sub assert
113 {
114     my $message = shift;
115
116     my $mess = longmess();
117     print Dumper($mess);
118
119     die $message;
120 }
121
122 # Default constructor
123 sub new
124 {
125     my $object = shift;
126     my $reference = { };
127
128     $codeGenerator = shift;
129     $writeDependencies = shift;
130
131     bless($reference, $object);
132     return $reference;
133 }
134
135 sub GenerateDictionary
136 {
137     my ($object, $dictionary) = @_;
138
139     my $className = GetDictionaryClassName($dictionary->name);
140     $object->GenerateDictionaryHeader($dictionary, $className);
141     $object->GenerateDictionaryImplementation($dictionary, $className);
142 }
143
144 sub GenerateInterface
145 {
146     my ($object, $interface, $defines, $enumerations, $dictionaries) = @_;
147
148     $codeGenerator->LinkOverloadedFunctions($interface);
149     AddStringifierOperationIfNeeded($interface);
150
151     if ($interface->isCallback) {
152         $object->GenerateCallbackHeader($interface, $enumerations, $dictionaries);
153         $object->GenerateCallbackImplementation($interface, $enumerations, $dictionaries);
154     } else {
155         $object->GenerateHeader($interface, $enumerations, $dictionaries);
156         $object->GenerateImplementation($interface, $enumerations, $dictionaries);
157     }
158 }
159
160 sub AddStringifierOperationIfNeeded
161 {
162     my $interface = shift;
163
164     foreach my $attribute (@{$interface->attributes}) {
165         next unless $attribute->isStringifier;
166
167         my $stringifier = domFunction->new();
168         $stringifier->signature(domSignature->new());
169         my $extendedAttributeList = {};
170         $extendedAttributeList->{ImplementedAs} = $attribute->signature->name;
171         $stringifier->signature->extendedAttributes($extendedAttributeList);
172         $stringifier->signature->name("toString");
173         die "stringifier can only be used on attributes of String types" unless $codeGenerator->IsStringType($attribute->signature->type);
174         $stringifier->signature->type($attribute->signature->type);
175         push(@{$interface->functions}, $stringifier);
176         last;
177     }
178 }
179
180 sub EventHandlerAttributeEventName
181 {
182     my $attribute = shift;
183     my $eventType = $attribute->signature->extendedAttributes->{ImplementedAs} || $attribute->signature->name;
184
185     # Remove the "on" prefix.
186     $eventType = substr($eventType, 2);
187
188     return "eventNames().${eventType}Event";
189 }
190
191 sub GetParentClassName
192 {
193     my $interface = shift;
194
195     return $interface->extendedAttributes->{JSLegacyParent} if $interface->extendedAttributes->{JSLegacyParent};
196     return "JSDOMObject" unless NeedsImplementationClass($interface);
197     return "JSDOMWrapper<" . GetImplClassName($interface->name) . ">" unless $interface->parent;
198     return "JS" . $interface->parent;
199 }
200
201 sub GetCallbackClassName
202 {
203     my $className = shift;
204
205     return "JS$className";
206 }
207
208 sub GetJSCallbackDataType
209 {
210     my $callbackInterface = shift;
211
212     return $callbackInterface->extendedAttributes->{IsWeakCallback} ? "JSCallbackDataWeak" : "JSCallbackDataStrong";
213 }
214
215 sub AddIncludesForTypeInImpl
216 {
217     my $type = shift;
218     my $isCallback = @_ ? shift : 0;
219     
220     AddIncludesForType($type, $isCallback, \%implIncludes);
221 }
222
223 sub AddIncludesForTypeInHeader
224 {
225     my $type = shift;
226     my $isCallback = @_ ? shift : 0;
227     
228     AddIncludesForType($type, $isCallback, \%headerIncludes);
229 }
230
231 sub GetExportMacroForJSClass
232 {
233     my $interface = shift;
234
235     return $interface->extendedAttributes->{ExportMacro} . " " if $interface->extendedAttributes->{ExportMacro};
236     return "";
237 }
238
239 sub AddIncludesForType
240 {
241     my $type = shift;
242     my $isCallback = shift;
243     my $includesRef = shift;
244
245     return if $codeGenerator->SkipIncludeHeader($type);
246     
247     # When we're finished with the one-file-per-class reorganization, we won't need these special cases.
248     if ($isCallback && $codeGenerator->IsWrapperType($type)) {
249         $includesRef->{"JS${type}.h"} = 1;
250     } elsif ($codeGenerator->IsSequenceOrFrozenArrayType($type)) {
251         my $innerType = $codeGenerator->GetSequenceOrFrozenArrayInnerType($type);
252         if ($codeGenerator->IsRefPtrType($innerType)) {
253             $includesRef->{"JS${innerType}.h"} = 1;
254             $includesRef->{"${innerType}.h"} = 1;
255         }
256         $includesRef->{"<runtime/JSArray.h>"} = 1;
257     } else {
258         # default, include the same named file
259         $includesRef->{"${type}.h"} = 1;
260     }
261 }
262
263 sub AddToImplIncludesForIDLType
264 {
265     my ($idlType, $conditional) = @_;
266
267     return if $codeGenerator->SkipIncludeHeader($idlType->name);
268
269     if ($idlType->isUnion) {
270         AddToImplIncludes("<wtf/Variant.h>", $conditional);
271
272         foreach my $memberType (@{$idlType->subtypes}) {
273             AddToImplIncludesForIDLType($memberType, $conditional);
274         }
275
276         return;
277     }
278
279     if ($codeGenerator->IsSequenceOrFrozenArrayType($idlType->name)) {
280         AddToImplIncludesForIDLType(@{$idlType->subtypes}[0], $conditional);
281         return;
282     }
283
284     if ($codeGenerator->IsExternalDictionaryType($idlType->name)) {
285         AddToImplIncludes("JS" . $idlType->name . ".h", $conditional);
286         return;
287     }
288
289     if ($codeGenerator->IsWrapperType($idlType->name)) {
290         AddToImplIncludes("JS" . $idlType->name . ".h", $conditional);
291         return;
292     }
293 }
294
295 sub AddToImplIncludes
296 {
297     my $header = shift;
298     my $conditional = shift;
299
300     if (not $conditional) {
301         $implIncludes{$header} = 1;
302     } elsif (not exists($implIncludes{$header})) {
303         $implIncludes{$header} = $conditional;
304     } else {
305         my $oldValue = $implIncludes{$header};
306         $implIncludes{$header} = "$oldValue|$conditional" if $oldValue ne 1;
307     }
308 }
309
310 sub IsReadonly
311 {
312     my $attribute = shift;
313     return $attribute->isReadOnly && !$attribute->signature->extendedAttributes->{Replaceable} && !$attribute->signature->extendedAttributes->{PutForwards};
314 }
315
316 sub AddClassForwardIfNeeded
317 {
318     my $interfaceName = shift;
319
320     # SVGAnimatedLength/Number/etc. are not classes so they can't be forward declared as classes.
321     return if $codeGenerator->IsSVGAnimatedType($interfaceName);
322     return if $codeGenerator->IsTypedArrayType($interfaceName);
323
324     push(@headerContent, "class $interfaceName;\n\n");
325 }
326
327 sub GetGenerateIsReachable
328 {
329     my $interface = shift;
330     return $interface->extendedAttributes->{GenerateIsReachable};
331 }
332
333 sub GetCustomIsReachable
334 {
335     my $interface = shift;
336     return $interface->extendedAttributes->{CustomIsReachable};
337 }
338
339 sub IsDOMGlobalObject
340 {
341     my $interface = shift;
342     return $interface->name eq "DOMWindow" || $codeGenerator->InheritsInterface($interface, "WorkerGlobalScope") || $interface->name eq "TestGlobalObject";
343 }
344
345 sub ShouldUseGlobalObjectPrototype
346 {
347     my $interface = shift;
348
349     # For workers, the global object is a DedicatedWorkerGlobalScope.
350     return 0 if $interface->name eq "WorkerGlobalScope";
351
352     return IsDOMGlobalObject($interface);
353 }
354
355 sub ShouldCacheAttribute
356 {
357     my $attribute = shift;
358
359     return 1 if $attribute->signature->extendedAttributes->{CachedAttribute};
360     return 1 if $attribute->signature->extendedAttributes->{SameObject};
361     return 0;
362 }
363
364 sub GenerateGetOwnPropertySlotBody
365 {
366     my ($interface, $className, $inlined) = @_;
367
368     my $namespaceMaybe = ($inlined ? "JSC::" : "");
369     my $namedGetterFunction = GetNamedGetterFunction($interface);
370     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
371
372     my @getOwnPropertySlotImpl = ();
373
374     my $ownPropertyCheck = sub {
375         push(@getOwnPropertySlotImpl, "    if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot))\n");
376         push(@getOwnPropertySlotImpl, "        return true;\n");
377     };
378
379     # FIXME: As per the Web IDL specification, the prototype check is supposed to skip "named properties objects":
380     # https://heycam.github.io/webidl/#dfn-named-property-visibility
381     # https://heycam.github.io/webidl/#dfn-named-properties-object
382     my $prototypeCheck = sub {
383         push(@getOwnPropertySlotImpl, "    ${namespaceMaybe}JSValue proto = thisObject->getPrototypeDirect();\n");
384         push(@getOwnPropertySlotImpl, "    if (proto.isObject() && jsCast<${namespaceMaybe}JSObject*>(proto)->hasProperty(state, propertyName))\n");
385         push(@getOwnPropertySlotImpl, "        return false;\n\n");
386     };
387
388     if ($indexedGetterFunction) {
389         push(@getOwnPropertySlotImpl, "    Optional<uint32_t> optionalIndex = parseIndex(propertyName);\n");
390
391         # If the item function returns a string then we let the TreatReturnedNullStringAs handle the cases
392         # where the index is out of range.
393         if ($indexedGetterFunction->signature->type eq "DOMString") {
394             push(@getOwnPropertySlotImpl, "    if (optionalIndex) {\n");
395         } else {
396             push(@getOwnPropertySlotImpl, "    if (optionalIndex && optionalIndex.value() < thisObject->wrapped().length()) {\n");
397         }
398         push(@getOwnPropertySlotImpl, "        unsigned index = optionalIndex.value();\n");
399         # Assume that if there's a setter, the index will be writable
400         if ($interface->extendedAttributes->{CustomIndexedSetter}) {
401             push(@getOwnPropertySlotImpl, "        unsigned attributes = 0;\n");
402         } else {
403             push(@getOwnPropertySlotImpl, "        unsigned attributes = ${namespaceMaybe}ReadOnly;\n");
404         }
405         push(@getOwnPropertySlotImpl, "        slot.setValue(thisObject, attributes, " . GetIndexedGetterExpression($indexedGetterFunction) . ");\n");
406         push(@getOwnPropertySlotImpl, "        return true;\n");
407         push(@getOwnPropertySlotImpl, "    }\n");
408     }
409
410     my $hasNamedGetter = $namedGetterFunction || $interface->extendedAttributes->{CustomNamedGetter};
411     if ($hasNamedGetter) {
412         if (!$interface->extendedAttributes->{OverrideBuiltins}) {
413             &$ownPropertyCheck();
414             &$prototypeCheck();
415         }
416
417         # The "thisObject->classInfo() == info()" check is to make sure we use the subclass' named getter
418         # instead of the base class one when possible.
419         if ($indexedGetterFunction) {
420             # Indexing an object with an integer that is not a supported property index should not call the named property getter.
421             # https://heycam.github.io/webidl/#idl-indexed-properties
422             push(@getOwnPropertySlotImpl, "    if (!optionalIndex && thisObject->classInfo() == info()) {\n");
423         } else {
424             push(@getOwnPropertySlotImpl, "    if (thisObject->classInfo() == info()) {\n");
425         }
426         push(@getOwnPropertySlotImpl, "        JSValue value;\n");
427         push(@getOwnPropertySlotImpl, "        if (thisObject->nameGetter(state, propertyName, value)) {\n");
428         push(@getOwnPropertySlotImpl, "            slot.setValue(thisObject, ReadOnly | DontEnum, value);\n");
429         push(@getOwnPropertySlotImpl, "            return true;\n");
430         push(@getOwnPropertySlotImpl, "        }\n");
431         push(@getOwnPropertySlotImpl, "    }\n");
432         if ($inlined) {
433             $headerIncludes{"wtf/text/AtomicString.h"} = 1;
434         } else {
435             $implIncludes{"wtf/text/AtomicString.h"} = 1;
436         }
437     }
438
439     if ($interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}) {
440         push(@getOwnPropertySlotImpl, "    if (thisObject->getOwnPropertySlotDelegate(state, propertyName, slot))\n");
441         push(@getOwnPropertySlotImpl, "        return true;\n");
442     }
443
444     if (!$hasNamedGetter || $interface->extendedAttributes->{OverrideBuiltins}) {
445         &$ownPropertyCheck();
446     }
447
448     push(@getOwnPropertySlotImpl, "    return false;\n");
449
450     return @getOwnPropertySlotImpl;
451 }
452
453 sub GenerateHeaderContentHeader
454 {
455     my $interface = shift;
456     my $className = "JS" . $interface->name;
457
458     my @headerContentHeader;
459     if ($interface->extendedAttributes->{AppleCopyright}) {
460         @headerContentHeader = split("\r", $beginAppleCopyrightForHeaderFiles);
461     } else {
462         @headerContentHeader = split("\r", $headerTemplate);
463     }
464
465     push(@headerContentHeader, "\n#pragma once\n\n");
466
467     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
468     push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
469     return @headerContentHeader;
470 }
471
472 sub GenerateImplementationContentHeader
473 {
474     my $interface = shift;
475     my $className = "JS" . $interface->name;
476
477     my @implContentHeader;
478     if ($interface->extendedAttributes->{AppleCopyright}) {
479         @implContentHeader = split("\r", $beginAppleCopyrightForSourceFiles);
480     } else {
481         @implContentHeader = split("\r", $headerTemplate);
482     }
483
484     push(@implContentHeader, "\n#include \"config.h\"\n");
485     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
486     push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;
487     push(@implContentHeader, "#include \"$className.h\"\n\n");
488     return @implContentHeader;
489 }
490
491 sub NeedsImplementationClass
492 {
493     my ($interface) = @_;
494
495     return 0 if $interface->extendedAttributes->{JSBuiltin};
496     return 1;
497 }
498
499 sub ShouldGenerateToWrapped
500 {
501     my ($hasParent, $interface) = @_;
502
503     return 0 if not NeedsImplementationClass($interface);
504     return 1 if !$hasParent or $interface->extendedAttributes->{JSGenerateToNativeObject};
505     return 1 if $interface->parent && $interface->parent eq "EventTarget";
506     return 0;
507 }
508
509 sub ShouldGenerateWrapperOwnerCode
510 {
511     my ($hasParent, $interface) = @_;
512
513     return 0 if not NeedsImplementationClass($interface);
514     return 1 if !$hasParent;
515     return 1 if GetGenerateIsReachable($interface);
516     return 1 if GetCustomIsReachable($interface);
517     return 1 if $interface->extendedAttributes->{JSCustomFinalize};
518     return 1 if $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject");
519     return 0;
520 }
521
522 sub ShouldGenerateToJSDeclaration
523 {
524     my ($hasParent, $interface) = @_;
525
526     return 0 if ($interface->extendedAttributes->{SuppressToJSObject});
527     return 0 if not NeedsImplementationClass($interface);
528     return 0 if $interface->extendedAttributes->{CustomProxyToJSObject};
529     return 1 if (!$hasParent or $interface->extendedAttributes->{JSGenerateToJSObject} or $interface->extendedAttributes->{CustomToJSObject});
530     return 1 if $interface->parent && $interface->parent eq "EventTarget";
531     return 1 if $interface->extendedAttributes->{Constructor} or $interface->extendedAttributes->{NamedConstructor};
532     return 0;
533 }
534
535 sub ShouldGenerateToJSImplementation
536 {
537     my ($hasParent, $interface) = @_;
538
539     return 0 if not ShouldGenerateToJSDeclaration($hasParent, $interface);
540     return 1 if not $interface->extendedAttributes->{CustomToJSObject};
541     return 0;
542 }
543
544 sub GetAttributeGetterName
545 {
546     my ($interface, $className, $attribute) = @_;
547
548     return $codeGenerator->WK_lcfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name) if $attribute->isStatic;
549     return GetJSBuiltinFunctionName($className, $attribute) if IsJSBuiltin($interface, $attribute);
550     return "js" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
551 }
552
553 sub GetAttributeSetterName
554 {
555     my ($interface, $className, $attribute) = @_;
556
557     return "set" . $codeGenerator->WK_ucfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name) if $attribute->isStatic;
558     return "set" . $codeGenerator->WK_ucfirst(GetJSBuiltinFunctionName($className, $attribute)) if IsJSBuiltin($interface, $attribute);
559     return "setJS" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
560 }
561
562 sub GetFunctionName
563 {
564     my ($interface, $className, $function) = @_;
565
566     return GetJSBuiltinFunctionName($className, $function) if IsJSBuiltin($interface, $function);
567
568     my $functionName = $function->signature->name;
569     $functionName = "SymbolIterator" if $functionName eq "[Symbol.Iterator]";
570
571     my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
572     return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($functionName);
573 }
574
575 sub GetSpecialAccessorFunctionForType
576 {
577     my $interface = shift;
578     my $special = shift;
579     my $firstParameterType = shift;
580     my $numberOfParameters = shift;
581
582     foreach my $function (@{$interface->functions}, @{$interface->anonymousFunctions}) {
583         my $specials = $function->signature->specials;
584         my $specialExists = grep { $_ eq $special } @$specials;
585         my $parameters = $function->parameters;
586         if ($specialExists and scalar(@$parameters) == $numberOfParameters and $parameters->[0]->type eq $firstParameterType) {
587             return $function;
588         }
589     }
590
591     return 0;
592 }
593
594 sub HasComplexGetOwnProperty
595 {
596     my $interface = shift;
597     return $interface->extendedAttributes->{CheckSecurity}
598         || IsDOMGlobalObject($interface)
599         || InstanceOverridesGetOwnPropertySlot($interface);
600 }
601
602 sub InterfaceRequiresAttributesOnInstance
603 {
604     my $interface = shift;
605     my $interfaceName = $interface->name;
606
607     # FIXME: All these return 1 if ... should ideally be removed.
608     # Some of them are unavoidable due to DOM weirdness, in which case we should
609     # add an IDL attribute for them.
610
611     # FIXME: We should be able to drop this once <rdar://problem/24466097> is fixed.
612     return 1 if $interface->isException;
613
614     # FIXME: Add support for [PrimaryGlobal] / [Global].
615     return 1 if IsDOMGlobalObject($interface) && $interface->name ne "WorkerGlobalScope";
616
617     return 0;
618 }
619
620 sub AttributeShouldBeOnInstance
621 {
622     my $interface = shift;
623     my $attribute = shift;
624
625     # FIXME: The bindings generator does not support putting runtime-enabled attributes on the instance yet (except for global objects).
626     return 0 if $attribute->signature->extendedAttributes->{EnabledAtRuntime} && !IsDOMGlobalObject($interface);
627
628     return 1 if InterfaceRequiresAttributesOnInstance($interface);
629     return 1 if $attribute->signature->type =~ /Constructor$/;
630
631     # [Unforgeable] attributes should be on the instance.
632     # https://heycam.github.io/webidl/#Unforgeable
633     return 1 if IsUnforgeable($interface, $attribute);
634
635     if ($interface->extendedAttributes->{CheckSecurity}) {
636         return 0 if $attribute->signature->extendedAttributes->{DoNotCheckSecurity};
637         return 0 if $attribute->signature->extendedAttributes->{DoNotCheckSecurityOnGetter};
638         return 1;
639     }
640
641     return 0;
642 }
643
644 # https://heycam.github.io/webidl/#es-operations
645 sub OperationShouldBeOnInstance
646 {
647     my $interface = shift;
648     my $function = shift;
649
650     # FIXME: Add support for [PrimaryGlobal] / [Global].
651     return 1 if IsDOMGlobalObject($interface) && $interface->name ne "WorkerGlobalScope";
652
653     # FIXME: The bindings generator does not support putting runtime-enabled operations on the instance yet (except for global objects).
654     return 0 if $function->signature->extendedAttributes->{EnabledAtRuntime};
655
656     # [Unforgeable] operations should be on the instance. https://heycam.github.io/webidl/#Unforgeable
657     return 1 if IsUnforgeable($interface, $function);
658
659     return 0;
660 }
661
662 sub GetJSCAttributesForAttribute
663 {
664     my $interface = shift;
665     my $attribute = shift;
666
667     my @specials = ();
668     push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute);
669
670     # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable.
671     my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
672     push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{NotEnumerable} || $is_global_constructor);
673     push(@specials, "ReadOnly") if IsReadonly($attribute);
674     push(@specials, "CustomAccessor") unless $is_global_constructor or IsJSBuiltin($interface, $attribute);
675     push(@specials, "DOMJITAttribute") if $attribute->signature->extendedAttributes->{"DOMJIT"};
676     push(@specials, "Accessor | Builtin") if  IsJSBuiltin($interface, $attribute);
677     return (@specials > 0) ? join(" | ", @specials) : "0";
678 }
679
680 sub GetIndexedGetterFunction
681 {
682     my $interface = shift;
683     return GetSpecialAccessorFunctionForType($interface, "getter", "unsigned long", 1);
684 }
685
686 sub GetNamedGetterFunction
687 {
688     my $interface = shift;
689     return GetSpecialAccessorFunctionForType($interface, "getter", "DOMString", 1);
690 }
691
692 sub InstanceFunctionCount
693 {
694     my $interface = shift;
695     my $count = 0;
696
697     foreach my $function (@{$interface->functions}) {
698         $count++ if OperationShouldBeOnInstance($interface, $function);
699     }
700
701     return $count;
702 }
703
704 sub PrototypeFunctionCount
705 {
706     my $interface = shift;
707     my $count = 0;
708
709     foreach my $function (@{$interface->functions}) {
710         $count++ if !$function->isStatic && !OperationShouldBeOnInstance($interface, $function);
711     }
712
713     $count += scalar @{$interface->iterable->functions} if $interface->iterable;
714     $count += scalar @{$interface->serializable->functions} if $interface->serializable;
715
716     return $count;
717 }
718
719 sub InstancePropertyCount
720 {
721     my $interface = shift;
722     my $count = 0;
723     foreach my $attribute (@{$interface->attributes}) {
724         $count++ if AttributeShouldBeOnInstance($interface, $attribute);
725     }
726     $count += InstanceFunctionCount($interface);
727     return $count;
728 }
729
730 sub PrototypePropertyCount
731 {
732     my $interface = shift;
733     my $count = 0;
734     foreach my $attribute (@{$interface->attributes}) {
735         $count++ if !AttributeShouldBeOnInstance($interface, $attribute);
736     }
737     $count += PrototypeFunctionCount($interface);
738     $count++ if NeedsConstructorProperty($interface);
739     return $count;
740 }
741
742 sub InstanceOverridesGetOwnPropertySlot
743 {
744     my $interface = shift;
745     return $interface->extendedAttributes->{CustomGetOwnPropertySlot}
746         || $interface->extendedAttributes->{CustomNamedGetter}
747         || $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}
748         || GetIndexedGetterFunction($interface)
749         || GetNamedGetterFunction($interface);
750 }
751
752 sub PrototypeHasStaticPropertyTable
753 {
754     my $interface = shift;
755     my $numConstants = @{$interface->constants};
756     return $numConstants > 0 || PrototypePropertyCount($interface) > 0;
757 }
758
759 sub InstanceOverridesPutImplementation
760 {
761     my $interface = shift;
762     return $interface->extendedAttributes->{CustomNamedSetter}
763         || $interface->extendedAttributes->{CustomIndexedSetter};
764 }
765
766 sub InstanceOverridesPutDeclaration
767 {
768     my $interface = shift;
769     return $interface->extendedAttributes->{CustomPutFunction}
770         || $interface->extendedAttributes->{CustomNamedSetter}
771         || $interface->extendedAttributes->{CustomIndexedSetter};
772 }
773
774 sub InstanceNeedsVisitChildren
775 {
776     my $interface = shift;
777     return $interface->extendedAttributes->{JSCustomMarkFunction}
778         || $codeGenerator->InheritsInterface($interface, "EventTarget")
779         || $interface->name eq "EventTarget"
780         || $interface->extendedAttributes->{ReportExtraMemoryCost}
781         || IsJSBuiltinConstructor($interface)
782 }
783
784 sub InstanceNeedsEstimatedSize
785 {
786     my $interface = shift;
787     return $interface->extendedAttributes->{ReportExtraMemoryCost};
788 }
789
790 sub GetImplClassName
791 {
792     my $name = shift;
793
794     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($name);
795     return $svgNativeType if $svgNativeType;
796
797     return $name;
798 }
799
800 sub IsClassNameWordBoundary
801 {
802     my ($name, $i) = @_;
803
804     # Interpret negative numbers as distance from end of string, just as the substr function does.
805     $i += length($name) if $i < 0;
806
807     return 0 if $i < 0;
808     return 1 if $i == 0;
809     return 1 if $i == length($name);
810     return 0 if $i > length($name);
811
812     my $checkString = substr($name, $i - 1);
813     return $checkString =~ /^[^A-Z][A-Z]/ || $checkString =~ /^[A-Z][A-Z][^A-Z]/;
814 }
815
816 sub IsPrefixRemovable
817 {
818     my ($class, $name, $i) = @_;
819
820     return IsClassNameWordBoundary($name, $i)
821         && (IsClassNameWordBoundary($class, $i) && substr($class, 0, $i) eq substr($name, 0, $i)
822             || IsClassNameWordBoundary($class, -$i) && substr($class, -$i) eq substr($name, 0, $i));
823 }
824
825 sub GetNestedClassName
826 {
827     my ($interface, $name) = @_;
828
829     my $class = GetImplClassName($interface->name);
830     my $member = $codeGenerator->WK_ucfirst($name);
831
832     # Since the enumeration name will be nested in the class name's namespace, remove any words
833     # that happen to match the start or end of the class name. If an enumeration is named TrackType or
834     # TextTrackType, and the class is named TextTrack, then we will get a name like TextTrack::Type.
835     my $memberLength = length($member);
836     my $longestPrefixLength = 0;
837     if ($member =~ /^[A-Z]./) {
838         for (my $i = 2; $i < $memberLength - 1; $i++) {
839             $longestPrefixLength = $i if IsPrefixRemovable($class, $member, $i);
840         }
841     }
842     $member = substr($member, $longestPrefixLength);
843
844     return "${class}::$member";
845 }
846
847 sub GetEnumerationClassName
848 {
849     my ($name, $interface) = @_;
850
851     if ($codeGenerator->HasEnumImplementationNameOverride($name)) {
852         return $codeGenerator->GetEnumImplementationNameOverride($name);
853     }
854
855     return $name unless defined($interface);
856     return GetNestedClassName($interface, $name);
857 }
858
859 sub GetEnumerationValueName
860 {
861     my ($name) = @_;
862
863     return "EmptyString" if $name eq "";
864     $name = join("", map { $codeGenerator->WK_ucfirst($_) } split("-", $name));
865     $name = "_$name" if $name =~ /^\d/;
866     return $name;
867 }
868
869 sub GenerateEnumerationsImplementationContent
870 {
871     my ($interface, $enumerations) = @_;
872
873     return "" unless @$enumerations;
874
875     my $result = "";
876     foreach my $enumeration (@$enumerations) {
877         my $name = $enumeration->name;
878
879         my $className = GetEnumerationClassName($name, $interface);
880
881         # FIXME: A little ugly to have this be a side effect instead of a return value.
882         AddToImplIncludes("<runtime/JSString.h>");
883
884         my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
885         $result .= "#if ${conditionalString}\n\n" if $conditionalString;
886
887         # Take an ExecState* instead of an ExecState& to match the jsStringWithCache from JSString.h.
888         # FIXME: Change to take VM& instead of ExecState*.
889         $result .= "JSString* jsStringWithCache(ExecState* state, $className enumerationValue)\n";
890         $result .= "{\n";
891         # FIXME: Might be nice to make this global be "const", but NeverDestroyed does not currently support that.
892         # FIXME: Might be nice to make the entire array be NeverDestroyed instead of each value, but not sure what the syntax for that is.
893         $result .= "    static NeverDestroyed<const String> values[] = {\n";
894         foreach my $value (@{$enumeration->values}) {
895             if ($value eq "") {
896                 $result .= "        emptyString(),\n";
897             } else {
898                 $result .= "        ASCIILiteral(\"$value\"),\n";
899             }
900         }
901         $result .= "    };\n";
902         my $index = 0;
903         foreach my $value (@{$enumeration->values}) {
904             my $enumerationValueName = GetEnumerationValueName($value);
905             $result .= "    static_assert(static_cast<size_t>(${className}::$enumerationValueName) == $index, \"${className}::$enumerationValueName is not $index as expected\");\n";
906             $index++;
907         }
908         $result .= "    ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values));\n";
909         $result .= "    return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);\n";
910         $result .= "}\n\n";
911
912         # FIXME: Change to take VM& instead of ExecState&.
913         # FIXME: Consider using toStringOrNull to make exception checking faster.
914         # FIXME: Consider finding a more efficient way to match against all the strings quickly.
915         $result .= "template<> Optional<$className> parseEnumeration<$className>(ExecState& state, JSValue value)\n";
916         $result .= "{\n";
917         $result .= "    auto stringValue = value.toWTFString(&state);\n";
918         foreach my $value (@{$enumeration->values}) {
919             my $enumerationValueName = GetEnumerationValueName($value);
920             if ($value eq "") {
921                 $result .= "    if (stringValue.isEmpty())\n";
922             } else {
923                 $result .= "    if (stringValue == \"$value\")\n";
924             }
925             $result .= "        return ${className}::${enumerationValueName};\n";
926         }
927         $result .= "    return Nullopt;\n";
928         $result .= "}\n\n";
929
930         # FIXME: A little ugly to have this be a side effect instead of a return value.
931         AddToImplIncludes("JSDOMConvert.h");
932
933         $result .= "template<> $className convertEnumeration<$className>(ExecState& state, JSValue value)\n";
934         $result .= "{\n";
935         $result .= "    VM& vm = state.vm();\n";
936         $result .= "    auto throwScope = DECLARE_THROW_SCOPE(vm);\n";
937         $result .= "    auto result = parseEnumeration<$className>(state, value);\n";
938         $result .= "    if (UNLIKELY(!result)) {\n";
939         $result .= "        throwTypeError(&state, throwScope);\n";
940         $result .= "        return { };\n";
941         $result .= "    }\n";
942         $result .= "    return result.value();\n";
943         $result .= "}\n\n";
944
945         $result .= "template<> const char* expectedEnumerationValues<$className>()\n";
946         $result .= "{\n";
947         $result .= "    return \"\\\"" . join ("\\\", \\\"", @{$enumeration->values}) . "\\\"\";\n";
948         $result .= "}\n\n";
949
950         $result .= "#endif\n\n" if $conditionalString;
951     }
952     return $result;
953 }
954
955 sub GenerateEnumerationsHeaderContent
956 {
957     my ($interface, $enumerations) = @_;
958
959     return "" unless @$enumerations;
960
961     # FIXME: Could optimize this to only generate the parts of each enumeration that are actually
962     # used, which would require iterating over everything in the interface.
963
964     $headerIncludes{"JSDOMConvert.h"} = 1;
965
966     my $result = "";
967
968     foreach my $enumeration (@$enumerations) {
969         my $name = $enumeration->name;
970
971         my $className = GetEnumerationClassName($name, $interface);
972
973         my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
974         $result .= "#if ${conditionalString}\n\n" if $conditionalString;
975
976         $result .= "JSC::JSString* jsStringWithCache(JSC::ExecState*, $className);\n\n";
977
978         $result .= "template<> struct JSValueTraits<$className> {\n";
979         $result .= "    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, $className value) { return jsStringWithCache(state, value); }\n";
980         $result .= "};\n\n";
981
982         $result .= "template<> Optional<$className> parseEnumeration<$className>(JSC::ExecState&, JSC::JSValue);\n";
983         $result .= "template<> $className convertEnumeration<$className>(JSC::ExecState&, JSC::JSValue);\n";
984         $result .= "template<> const char* expectedEnumerationValues<$className>();\n\n";
985
986         $result .= "#endif\n\n" if $conditionalString;
987     }
988     return $result;
989 }
990
991 sub GetDictionaryClassName
992 {
993     my ($name, $interface) = @_;
994
995     if ($codeGenerator->HasDictionaryImplementationNameOverride($name)) {
996         return $codeGenerator->GetDictionaryImplementationNameOverride($name);
997     }
998
999     return $name if $codeGenerator->IsExternalDictionaryType($name);
1000     return $name unless defined($interface);
1001     return GetNestedClassName($interface, $name);
1002 }
1003
1004 sub GenerateDefaultValue
1005 {
1006     my ($interface, $member) = @_;
1007
1008     my $defaultValue = $member->default;
1009
1010     if ($codeGenerator->IsEnumType($member->type)) {
1011         # FIXME: Would be nice to report an error if the value does not have quote marks around it.
1012         # FIXME: Would be nice to report an error if the value is not one of the enumeration values.
1013         my $className = GetEnumerationClassName($member->type, $interface);
1014         my $enumerationValueName = GetEnumerationValueName(substr($defaultValue, 1, -1));
1015         return $className . "::" . $enumerationValueName;
1016     }
1017     if ($defaultValue eq "null") {
1018         return "jsNull()" if $member->type eq "any";
1019         return "nullptr" if $codeGenerator->IsWrapperType($member->type) || $codeGenerator->IsTypedArrayType($member->type);
1020         return "String()" if $codeGenerator->IsStringType($member->type);
1021         return "Nullopt";
1022     }
1023     return "{ }" if $defaultValue eq "[]";
1024     return "jsUndefined()" if $defaultValue eq "undefined";
1025
1026     return $defaultValue;
1027 }
1028
1029 sub ShouldAllowNonFiniteForFloatingPointType
1030 {
1031     my $type = shift;
1032
1033     die "Can only be called with floating point types" unless $codeGenerator->IsFloatingPointType($type);
1034     return $type eq "unrestricted double" || $type eq "unrestricted float";
1035 }
1036
1037 sub GenerateConversionRuleWithLeadingComma
1038 {
1039     my ($interface, $member) = @_;
1040
1041     if ($codeGenerator->IsFloatingPointType($member->type)) {
1042         return ", " . (ShouldAllowNonFiniteForFloatingPointType($member->type) ? "ShouldAllowNonFinite::Yes" : "ShouldAllowNonFinite::No");
1043     }
1044     return ", " . GetIntegerConversionConfiguration($member) if $codeGenerator->IsIntegerType($member->type);
1045     return "";
1046 }
1047
1048 sub GenerateDictionaryHeaderContent
1049 {
1050     my ($dictionary, $className) = @_;
1051
1052     my $result = "";
1053     my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
1054     $result .= "#if ${conditionalString}\n\n" if $conditionalString;
1055     $result .= "template<> Optional<$className> convertDictionary<$className>(JSC::ExecState&, JSC::JSValue);\n\n";
1056     $result .= "#endif\n\n" if $conditionalString;
1057     return $result;
1058 }
1059
1060 sub GenerateDictionariesHeaderContent
1061 {
1062     my ($interface, $allDictionaries) = @_;
1063
1064     return "" unless @$allDictionaries;
1065
1066     $headerIncludes{"JSDOMConvert.h"} = 1;
1067
1068     my $result = "";
1069     foreach my $dictionary (@$allDictionaries) {
1070         $headerIncludes{$interface->name . ".h"} = 1;
1071         my $className = GetDictionaryClassName($dictionary->name, $interface);
1072         $result .= GenerateDictionaryHeaderContent($dictionary, $className);
1073     }
1074     return $result;
1075 }
1076
1077 sub GenerateDictionaryImplementationContent
1078 {
1079     my ($dictionary, $className, $interface) = @_;
1080
1081     my $result = "";
1082
1083     my $name = $dictionary->name;
1084
1085     my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
1086     $result .= "#if ${conditionalString}\n\n" if $conditionalString;
1087
1088     # FIXME: A little ugly to have this be a side effect instead of a return value.
1089     AddToImplIncludes("JSDOMConvert.h");
1090
1091     # https://heycam.github.io/webidl/#es-dictionary
1092     $result .= "template<> Optional<$className> convertDictionary<$className>(ExecState& state, JSValue value)\n";
1093     $result .= "{\n";
1094     $result .= "    VM& vm = state.vm();\n";
1095     $result .= "    auto throwScope = DECLARE_THROW_SCOPE(vm);\n";
1096     $result .= "    bool isNullOrUndefined = value.isUndefinedOrNull();\n";
1097     $result .= "    auto* object = isNullOrUndefined ? nullptr : value.getObject();\n";
1098     # 1. If Type(V) is not Undefined, Null or Object, then throw a TypeError.
1099     $result .= "    if (UNLIKELY(!isNullOrUndefined && !object)) {\n";
1100     $result .= "        throwTypeError(&state, throwScope);\n";
1101     $result .= "        return Nullopt;\n";
1102     $result .= "    }\n";
1103
1104     # 2. If V is a native RegExp object, then throw a TypeError.
1105     # FIXME: This RegExp special handling is likely to go away in the specification.
1106     $result .= "    if (UNLIKELY(object && object->type() == RegExpObjectType)) {\n";
1107     $result .= "        throwTypeError(&state, throwScope);\n";
1108     $result .= "        return Nullopt;\n";
1109     $result .= "    }\n";
1110
1111     # 3. Let dict be an empty dictionary value of type D; every dictionary member is initially considered to be not present.
1112
1113     # 4. Let dictionaries be a list consisting of D and all of D’s inherited dictionaries, in order from least to most derived.
1114     my @dictionaries;
1115     push(@dictionaries, $dictionary);
1116     my $parentName = $dictionary->parent;
1117     while (defined($parentName)) {
1118         my $parentDictionary = $codeGenerator->GetDictionaryByName($parentName);
1119         assert("Unable to find definition for dictionary named '" . $parentName . "'!") unless defined($parentDictionary);
1120         unshift(@dictionaries, $parentDictionary);
1121         $parentName = $parentDictionary->parent;
1122     }
1123
1124     my $arguments = "";
1125     my $comma = "";
1126
1127     $result .= "    $className result;\n";
1128
1129     # 5. For each dictionary dictionary in dictionaries, in order:
1130     foreach my $dictionary (@dictionaries) {
1131         # For each dictionary member member declared on dictionary, in lexicographical order:
1132         my @sortedMembers = sort { $a->name cmp $b->name } @{$dictionary->members};
1133         foreach my $member (@sortedMembers) {
1134             $member->default("undefined") if $member->idlType->name eq "any" and !defined($member->default); # Use undefined as default value for member of type 'any' unless specified otherwise.
1135
1136             my $idlType = $member->idlType;
1137             AddToImplIncludesForIDLType($idlType);
1138
1139             # 5.1. Let key be the identifier of member.
1140             my $key = $member->name;
1141
1142             # 5.2. Let value be an ECMAScript value, depending on Type(V):
1143             $result .= "    JSValue ${key}Value = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, \"${key}\"));\n";
1144
1145             my $IDLType = GetIDLType($interface, $idlType);
1146
1147             # 5.3. If value is not undefined, then:
1148             $result .= "    if (!${key}Value.isUndefined()) {\n";
1149
1150             # FIXME: We should figure out a way to merge these two cases.
1151             if ($codeGenerator->IsDictionaryType($idlType->name)) {
1152                 $result .= "        auto ${key}Optional = convert<${IDLType}>(state, ${key}Value);\n";
1153                 $result .= "        RETURN_IF_EXCEPTION(throwScope, Nullopt);\n";
1154                 $result .= "        result.$key = ${key}Optional.value();\n";
1155             } else {
1156                 $result .= "        result.$key = convert<${IDLType}>(state, ${key}Value);\n";
1157                 $result .= "        RETURN_IF_EXCEPTION(throwScope, Nullopt);\n";
1158             }
1159
1160             # Value is undefined.
1161             # 5.4. Otherwise, if value is undefined but the dictionary member has a default value, then:
1162             if ($member->isOptional && defined $member->default) {
1163                 $result .= "    } else\n";
1164                 $result .= "        result.$key = " . GenerateDefaultValue($interface, $member) . ";\n";
1165             } elsif (!$member->isOptional) {
1166                 # 5.5. Otherwise, if value is undefined and the dictionary member is a required dictionary member, then throw a TypeError.
1167                 $result .= "    } else {\n";
1168                 $result .= "        throwTypeError(&state, throwScope);\n";
1169                 $result .= "        return Nullopt;\n";
1170                 $result .= "    }\n";
1171             } else {
1172                 $result .= "    }\n";
1173             }
1174         }
1175     }
1176
1177     $result .= "    return WTFMove(result);\n";
1178     $result .= "}\n\n";
1179     $result .= "#endif\n\n" if $conditionalString;
1180
1181     return $result;
1182 }
1183
1184 sub GenerateDictionariesImplementationContent
1185 {
1186     my ($interface, $allDictionaries) = @_;
1187
1188     my $result = "";
1189     foreach my $dictionary (@$allDictionaries) {
1190         my $className = GetDictionaryClassName($dictionary->name, $interface);
1191         $result .= GenerateDictionaryImplementationContent($dictionary, $className, $interface);
1192     }
1193     return $result;
1194 }
1195
1196 sub GetJSTypeForNode
1197 {
1198     my ($codeGenerator, $interface) = @_;
1199
1200     if ($codeGenerator->InheritsInterface($interface, "Document")) {
1201         return "JSDocumentWrapperType";
1202     }
1203     if ($codeGenerator->InheritsInterface($interface, "DocumentFragment")) {
1204         return "JSDocumentFragmentNodeType";
1205     }
1206     if ($codeGenerator->InheritsInterface($interface, "DocumentType")) {
1207         return "JSDocumentTypeNodeType";
1208     }
1209     if ($codeGenerator->InheritsInterface($interface, "ProcessingInstruction")) {
1210         return "JSProcessingInstructionNodeType";
1211     }
1212     if ($codeGenerator->InheritsInterface($interface, "CDATASection")) {
1213         return "JSCDATASectionNodeType";
1214     }
1215     if ($codeGenerator->InheritsInterface($interface, "Attr")) {
1216         return "JSAttrNodeType";
1217     }
1218     if ($codeGenerator->InheritsInterface($interface, "Comment")) {
1219         return "JSCommentNodeType";
1220     }
1221     if ($codeGenerator->InheritsInterface($interface, "Text")) {
1222         return "JSTextNodeType";
1223     }
1224     if ($codeGenerator->InheritsInterface($interface, "Element")) {
1225         return "JSElementType";
1226     }
1227     return "JSNodeType";
1228 }
1229
1230 sub GenerateHeader
1231 {
1232     my ($object, $interface, $enumerations, $dictionaries) = @_;
1233
1234     my $interfaceName = $interface->name;
1235     my $className = "JS$interfaceName";
1236     my %structureFlags = ();
1237
1238     my $hasLegacyParent = $interface->extendedAttributes->{JSLegacyParent};
1239     my $hasRealParent = $interface->parent;
1240     my $hasParent = $hasLegacyParent || $hasRealParent;
1241     my $parentClassName = GetParentClassName($interface);
1242     my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
1243
1244     # - Add default header template and header protection
1245     push(@headerContentHeader, GenerateHeaderContentHeader($interface));
1246
1247     if ($hasParent) {
1248         $headerIncludes{"$parentClassName.h"} = 1;
1249     } else {
1250         $headerIncludes{"JSDOMWrapper.h"} = 1;
1251         if ($interface->isException) {
1252             $headerIncludes{"<runtime/ErrorPrototype.h>"} = 1;
1253         }
1254     }
1255
1256     $headerIncludes{"<runtime/CallData.h>"} = 1 if $interface->extendedAttributes->{CustomCall};
1257
1258     $headerIncludes{"$interfaceName.h"} = 1 if $hasParent && $interface->extendedAttributes->{JSGenerateToNativeObject};
1259
1260     $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
1261
1262     my $implType = GetImplClassName($interfaceName);
1263     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($interfaceName);
1264     my $svgPropertyOrListPropertyType;
1265     $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
1266     $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
1267
1268     my $numConstants = @{$interface->constants};
1269     my $numAttributes = @{$interface->attributes};
1270     my $numFunctions = @{$interface->functions};
1271
1272     push(@headerContent, "\nnamespace WebCore {\n\n");
1273
1274     if ($codeGenerator->IsSVGAnimatedType($interfaceName)) {
1275         $headerIncludes{"$interfaceName.h"} = 1;
1276     } else {
1277         # Implementation class forward declaration
1278         if (IsDOMGlobalObject($interface)) {
1279             AddClassForwardIfNeeded($interfaceName) unless $svgPropertyOrListPropertyType;
1280         }
1281     }
1282
1283     AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow";
1284     AddClassForwardIfNeeded("JSDictionary") if $codeGenerator->IsConstructorTemplate($interface, "Event");
1285
1286     my $exportMacro = GetExportMacroForJSClass($interface);
1287
1288     # Class declaration
1289     push(@headerContent, "class $exportMacro$className : public $parentClassName {\n");
1290
1291     # Static create methods
1292     push(@headerContent, "public:\n");
1293     push(@headerContent, "    using Base = $parentClassName;\n");
1294     push(@headerContent, "    using DOMWrapped = $implType;\n") if $interface->parent;
1295
1296     if ($interfaceName eq "DOMWindow") {
1297         push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* windowShell)\n");
1298         push(@headerContent, "    {\n");
1299         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl), windowShell);\n");
1300         push(@headerContent, "        ptr->finishCreation(vm, windowShell);\n");
1301         push(@headerContent, "        vm.heap.addFinalizer(ptr, destroy);\n");
1302         push(@headerContent, "        return ptr;\n");
1303         push(@headerContent, "    }\n\n");
1304     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1305         push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSC::JSProxy* proxy)\n");
1306         push(@headerContent, "    {\n");
1307         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl));\n");
1308         push(@headerContent, "        ptr->finishCreation(vm, proxy);\n");
1309         push(@headerContent, "        vm.heap.addFinalizer(ptr, destroy);\n");
1310         push(@headerContent, "        return ptr;\n");
1311         push(@headerContent, "    }\n\n");
1312     } elsif ($interface->extendedAttributes->{MasqueradesAsUndefined}) {
1313         AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
1314         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
1315         push(@headerContent, "    {\n");
1316         push(@headerContent, "        globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(globalObject->vm(), \"Allocated masquerading object\");\n");
1317         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
1318         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1319         push(@headerContent, "        return ptr;\n");
1320         push(@headerContent, "    }\n\n");
1321     } elsif (!NeedsImplementationClass($interface)) {
1322         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject)\n");
1323         push(@headerContent, "    {\n");
1324         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject);\n");
1325         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1326         push(@headerContent, "        return ptr;\n");
1327         push(@headerContent, "    }\n\n");  
1328     } else {
1329         AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
1330         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
1331         push(@headerContent, "    {\n");
1332         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
1333         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1334         push(@headerContent, "        return ptr;\n");
1335         push(@headerContent, "    }\n\n");
1336     }
1337
1338     push(@headerContent, "    static const bool needsDestruction = false;\n\n") if IsDOMGlobalObject($interface);
1339
1340     $structureFlags{"JSC::HasStaticPropertyTable"} = 1 if InstancePropertyCount($interface) > 0;
1341
1342     # Prototype
1343     unless (ShouldUseGlobalObjectPrototype($interface)) {
1344         push(@headerContent, "    static JSC::JSObject* createPrototype(JSC::VM&, JSC::JSGlobalObject*);\n");
1345         push(@headerContent, "    static JSC::JSObject* prototype(JSC::VM&, JSC::JSGlobalObject*);\n");
1346     }
1347
1348     # JSValue to implementation type
1349     if (ShouldGenerateToWrapped($hasParent, $interface)) {
1350         my $nativeType = GetNativeType($interface, $implType);
1351         if ($interface->name eq "XPathNSResolver") {
1352             push(@headerContent, "    static $nativeType toWrapped(JSC::ExecState&, JSC::JSValue);\n");
1353         } else {
1354             my $export = "";
1355             $export = "WEBCORE_EXPORT " if $interface->extendedAttributes->{ExportToWrappedFunction};
1356             push(@headerContent, "    static $export$nativeType toWrapped(JSC::JSValue);\n");
1357         }
1358     }
1359
1360     $headerTrailingIncludes{"${className}Custom.h"} = 1 if $interface->extendedAttributes->{JSCustomHeader};
1361
1362     my $namedGetterFunction = GetNamedGetterFunction($interface);
1363     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
1364
1365     my $hasNamedGetter = $namedGetterFunction
1366         || $interface->extendedAttributes->{CustomNamedGetter};
1367
1368     my $hasComplexGetter = $indexedGetterFunction
1369         || $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}
1370         || $interface->extendedAttributes->{CustomGetOwnPropertySlot}
1371         || $hasNamedGetter;
1372
1373     my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
1374
1375     if ($hasNamedGetter) {
1376         if ($interface->extendedAttributes->{OverrideBuiltins}) {
1377             $structureFlags{"JSC::GetOwnPropertySlotIsImpure"} = 1;
1378         } else {
1379             $structureFlags{"JSC::GetOwnPropertySlotIsImpureForPropertyAbsence"} = 1;
1380         }
1381     }
1382     $structureFlags{"JSC::NewImpurePropertyFiresWatchpoints"} = 1 if $interface->extendedAttributes->{NewImpurePropertyFiresWatchpoints};
1383     $structureFlags{"JSC::TypeOfShouldCallGetCallData"} = 1 if $interface->extendedAttributes->{CustomCall};
1384
1385     # Getters
1386     if ($hasGetter) {
1387         push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
1388         push(@headerContent, "    bool getOwnPropertySlotDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n") if $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor};
1389         $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
1390
1391         if ($hasComplexGetter) {
1392             push(@headerContent, "    static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n");
1393             $structureFlags{"JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero"} = 1;
1394         }
1395     }
1396
1397     my $overridesPut = InstanceOverridesPutDeclaration($interface);
1398
1399     # Getters
1400     if ($overridesPut) {
1401         push(@headerContent, "    static bool put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1402         push(@headerContent, "    static bool putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n");
1403         push(@headerContent, "    bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&, bool& putResult);\n") if $interface->extendedAttributes->{CustomNamedSetter};
1404     }
1405
1406     if (!$hasParent) {
1407         push(@headerContent, "    static void destroy(JSC::JSCell*);\n");
1408     }
1409
1410     # Class info
1411     if ($interfaceName eq "Node") {
1412         push(@headerContent, "\n");
1413         push(@headerContent, "protected:\n");
1414         push(@headerContent, "    static const JSC::ClassInfo s_info;\n");
1415         push(@headerContent, "public:\n");
1416         push(@headerContent, "    static const JSC::ClassInfo* info() { return &s_info; }\n\n");
1417     } else {
1418         push(@headerContent, "\n");
1419         push(@headerContent, "    DECLARE_INFO;\n\n");
1420     }
1421
1422     # Structure ID
1423     $structureFlags{"JSC::ImplementsHasInstance | JSC::ImplementsDefaultHasInstance"} = 1 if $interfaceName eq "DOMWindow";
1424     push(@headerContent, "    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
1425     push(@headerContent, "    {\n");
1426     if (IsDOMGlobalObject($interface)) {
1427         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info());\n");
1428     } elsif ($codeGenerator->InheritsInterface($interface, "Node")) {
1429         my $type = GetJSTypeForNode($codeGenerator, $interface);
1430         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType($type), StructureFlags), info());\n");
1431     } else {
1432         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n");
1433     }
1434     push(@headerContent, "    }\n\n");
1435
1436     # Custom pushEventHandlerScope function
1437     push(@headerContent, "    JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{JSCustomPushEventHandlerScope};
1438
1439     # Custom call functions
1440     push(@headerContent, "    static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $interface->extendedAttributes->{CustomCall};
1441
1442     # Custom deleteProperty function
1443     push(@headerContent, "    static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{CustomDeleteProperty};
1444     push(@headerContent, "    static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{CustomDeleteProperty};
1445
1446     # Custom getPropertyNames function exists on DOMWindow
1447     if ($interfaceName eq "DOMWindow") {
1448         push(@headerContent, "    static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1449         push(@headerContent, "    static void getGenericPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1450         push(@headerContent, "    static void getStructurePropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1451         push(@headerContent, "    static uint32_t getEnumerableLength(JSC::ExecState*, JSC::JSObject*);\n");
1452         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
1453     }
1454
1455     # Custom getOwnPropertyNames function
1456     if ($interface->extendedAttributes->{CustomEnumerateProperty} || $indexedGetterFunction || $namedGetterFunction) {
1457         push(@headerContent, "    static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1458         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;       
1459     }
1460
1461     # Custom defineOwnProperty function
1462     push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{JSCustomDefineOwnProperty};
1463
1464     # Custom getPrototype / setPrototype functions.
1465     push (@headerContent, "    static JSC::JSValue getPrototype(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{CustomGetPrototype};
1466     push (@headerContent, "    static bool setPrototype(JSC::JSObject*, JSC::ExecState*, JSC::JSValue, bool shouldThrowIfCantSet);\n") if $interface->extendedAttributes->{CustomSetPrototype};
1467
1468     # Custom preventExtensions function.
1469     push(@headerContent, "    static bool preventExtensions(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{CustomPreventExtensions};
1470     
1471     $structureFlags{"JSC::MasqueradesAsUndefined"} = 1 if $interface->extendedAttributes->{MasqueradesAsUndefined};
1472
1473     # Constructor object getter
1474     unless ($interface->extendedAttributes->{NoInterfaceObject}) {
1475         push(@headerContent, "    static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);\n");
1476         push(@headerContent, "    static JSC::JSValue getNamedConstructor(JSC::VM&, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{NamedConstructor};
1477     }
1478
1479     my $numCustomFunctions = 0;
1480     my $numCustomAttributes = 0;
1481
1482     my $hasForwardDeclaringFunctions = 0;
1483     my $hasForwardDeclaringAttributes = 0;
1484
1485     my $hasDOMJITAttributes = 0;
1486
1487     # Attribute and function enums
1488     if ($numAttributes > 0) {
1489         foreach (@{$interface->attributes}) {
1490             my $attribute = $_;
1491             $numCustomAttributes++ if HasCustomGetter($attribute->signature->extendedAttributes);
1492             $numCustomAttributes++ if HasCustomSetter($attribute->signature->extendedAttributes);
1493             if (ShouldCacheAttribute($attribute)) {
1494                 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1495                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1496                 push(@headerContent, "    mutable JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->signature->name . ";\n");
1497                 $numCachedAttributes++;
1498                 $needsVisitChildren = 1;
1499                 push(@headerContent, "#endif\n") if $conditionalString;
1500             }
1501             $hasDOMJITAttributes = 1 if $attribute->signature->extendedAttributes->{"DOMJIT"};
1502
1503             $hasForwardDeclaringAttributes = 1 if $attribute->signature->extendedAttributes->{ForwardDeclareInHeader};
1504         }
1505     }
1506
1507     # visit function
1508     if ($needsVisitChildren) {
1509         push(@headerContent, "    static void visitChildren(JSCell*, JSC::SlotVisitor&);\n");
1510         push(@headerContent, "    void visitAdditionalChildren(JSC::SlotVisitor&);\n") if $interface->extendedAttributes->{JSCustomMarkFunction};
1511         push(@headerContent, "\n");
1512     }
1513
1514     if (InstanceNeedsEstimatedSize($interface)) {
1515         push(@headerContent, "    static size_t estimatedSize(JSCell*);\n");
1516     }
1517
1518     if ($numCustomAttributes > 0) {
1519         push(@headerContent, "\n    // Custom attributes\n");
1520
1521         foreach my $attribute (@{$interface->attributes}) {
1522             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1523             if (HasCustomGetter($attribute->signature->extendedAttributes)) {
1524                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1525                 my $methodName = $codeGenerator->WK_lcfirst($attribute->signature->name);
1526                 push(@headerContent, "    JSC::JSValue " . $methodName . "(JSC::ExecState&) const;\n");
1527                 push(@headerContent, "#endif\n") if $conditionalString;
1528             }
1529             if (HasCustomSetter($attribute->signature->extendedAttributes) && !IsReadonly($attribute)) {
1530                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1531                 push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState&, JSC::JSValue);\n");
1532                 push(@headerContent, "#endif\n") if $conditionalString;
1533             }
1534         }
1535     }
1536
1537     foreach my $function (@{$interface->functions}) {
1538         $numCustomFunctions++ if HasCustomMethod($function->signature->extendedAttributes);
1539         $hasForwardDeclaringFunctions = 1 if $function->signature->extendedAttributes->{ForwardDeclareInHeader};
1540     }
1541
1542     if ($numCustomFunctions > 0) {
1543         my $inAppleCopyright = 0;
1544         push(@headerContent, "\n    // Custom functions\n");
1545         foreach my $function (@{$interface->functions}) {
1546             if ($function->signature->extendedAttributes->{AppleCopyright}) {
1547                 if (!$inAppleCopyright) {
1548                     push(@headerContent, $beginAppleCopyrightForHeaderFiles);
1549                     $inAppleCopyright = 1;
1550                 }
1551             } elsif ($inAppleCopyright) {
1552                 push(@headerContent, $endAppleCopyright);
1553                 $inAppleCopyright = 0;
1554             }
1555             next unless HasCustomMethod($function->signature->extendedAttributes);
1556             next if $function->{overloads} && $function->{overloadIndex} != 1;
1557             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1558             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1559             my $functionImplementationName = $function->signature->extendedAttributes->{ImplementedAs} || $codeGenerator->WK_lcfirst($function->signature->name);
1560             push(@headerContent, "    " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState&);\n");
1561             push(@headerContent, "#endif\n") if $conditionalString;
1562         }
1563         push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
1564     }
1565
1566     if (NeedsImplementationClass($interface)) {
1567         if ($hasParent) {
1568             push(@headerContent, "    $interfaceName& wrapped() const\n");
1569             push(@headerContent, "    {\n");
1570             push(@headerContent, "        return static_cast<$interfaceName&>(Base::wrapped());\n");
1571             push(@headerContent, "    }\n");
1572         }
1573     }
1574
1575     # structure flags
1576     if (%structureFlags) {
1577         push(@headerContent, "public:\n");
1578         push(@headerContent, "    static const unsigned StructureFlags = ");
1579         foreach my $structureFlag (sort (keys %structureFlags)) {
1580             push(@headerContent, $structureFlag . " | ");
1581         }
1582         push(@headerContent, "Base::StructureFlags;\n");
1583     }
1584
1585     push(@headerContent, "protected:\n");
1586
1587     # Constructor
1588     if ($interfaceName eq "DOMWindow") {
1589         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&, JSDOMWindowShell*);\n");
1590     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1591         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&);\n");
1592     } elsif (!NeedsImplementationClass($interface)) {
1593         push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject&);\n\n");
1594      } else {
1595         push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject&, Ref<$implType>&&);\n\n");
1596         push(@headerContent, "    void finishCreation(JSC::VM& vm)\n");
1597         push(@headerContent, "    {\n");
1598         push(@headerContent, "        Base::finishCreation(vm);\n");
1599         push(@headerContent, "        ASSERT(inherits(info()));\n");
1600         push(@headerContent, "    }\n\n");
1601     }
1602
1603     if (IsDOMGlobalObject($interface)) {
1604         if ($interfaceName eq "DOMWindow") {
1605             push(@headerContent, "    void finishCreation(JSC::VM&, JSDOMWindowShell*);\n");
1606         } else {
1607             push(@headerContent, "    void finishCreation(JSC::VM&, JSC::JSProxy*);\n");
1608         }
1609     }
1610
1611     push(@headerContent, "    void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n") if $interface->extendedAttributes->{CustomIndexedSetter};
1612
1613     if ($namedGetterFunction || $interface->extendedAttributes->{CustomNamedGetter}) {
1614         push(@headerContent, "private:\n");
1615         push(@headerContent, "    bool nameGetter(JSC::ExecState*, JSC::PropertyName, JSC::JSValue&);\n");
1616     }
1617
1618     push(@headerContent, "};\n\n");
1619
1620     if (ShouldGenerateWrapperOwnerCode($hasParent, $interface)) {
1621         if ($interfaceName ne "Node" && $codeGenerator->InheritsInterface($interface, "Node")) {
1622             $headerIncludes{"JSNode.h"} = 1;
1623             push(@headerContent, "class JS${interfaceName}Owner : public JSNodeOwner {\n");
1624         } else {
1625             push(@headerContent, "class JS${interfaceName}Owner : public JSC::WeakHandleOwner {\n");
1626         }
1627         $headerIncludes{"<wtf/NeverDestroyed.h>"} = 1;
1628         push(@headerContent, "public:\n");
1629         push(@headerContent, "    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
1630         push(@headerContent, "    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
1631         push(@headerContent, "};\n");
1632         push(@headerContent, "\n");
1633         push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, $implType*)\n");
1634         push(@headerContent, "{\n");
1635         push(@headerContent, "    static NeverDestroyed<JS${interfaceName}Owner> owner;\n");
1636         push(@headerContent, "    return &owner.get();\n");
1637         push(@headerContent, "}\n");
1638         push(@headerContent, "\n");
1639         push(@headerContent, "inline void* wrapperKey($implType* wrappableObject)\n");
1640         push(@headerContent, "{\n");
1641         push(@headerContent, "    return wrappableObject;\n");
1642         push(@headerContent, "}\n");
1643         push(@headerContent, "\n");
1644     }
1645     if (ShouldGenerateToJSDeclaration($hasParent, $interface)) {
1646         # Node and NodeList have custom inline implementations which thus cannot be exported.
1647         # FIXME: The special case for Node and NodeList should probably be implemented via an IDL attribute.
1648         if ($implType eq "Node" or $implType eq "NodeList") {
1649             push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType&);\n");
1650         } else {
1651             push(@headerContent, $exportMacro."JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType&);\n");
1652         }
1653         push(@headerContent, "inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, $implType* impl) { return impl ? toJS(state, globalObject, *impl) : JSC::jsNull(); }\n");
1654
1655         push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, Ref<$implType>&&);\n");
1656         push(@headerContent, "inline JSC::JSValue toJSNewlyCreated(JSC::ExecState* state, JSDOMGlobalObject* globalObject, RefPtr<$implType>&& impl) { return impl ? toJSNewlyCreated(state, globalObject, impl.releaseNonNull()) : JSC::jsNull(); }\n");
1657    }
1658
1659     push(@headerContent, "\n");
1660
1661     GeneratePrototypeDeclaration(\@headerContent, $className, $interface) if HeaderNeedsPrototypeDeclaration($interface);
1662
1663     if ($hasForwardDeclaringFunctions) {
1664         my $inAppleCopyright = 0;
1665         push(@headerContent,"// Functions\n\n");
1666         foreach my $function (@{$interface->functions}) {
1667             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1668             next unless $function->signature->extendedAttributes->{ForwardDeclareInHeader};
1669
1670             if ($function->signature->extendedAttributes->{AppleCopyright}) {
1671                 if (!$inAppleCopyright) {
1672                     push(@headerContent, $beginAppleCopyrightForHeaderFiles);
1673                     $inAppleCopyright = 1;
1674                 }
1675             } elsif ($inAppleCopyright) {
1676                 push(@headerContent, $endAppleCopyright);
1677                 $inAppleCopyright = 0;
1678             }
1679
1680             my $conditionalAttribute = getConditionalForFunctionConsideringOverloads($function);
1681             my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
1682             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1683             my $functionName = GetFunctionName($interface, $className, $function);
1684             push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
1685             push(@headerContent, "#endif\n") if $conditionalString;
1686         }
1687
1688         push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
1689         push(@headerContent,"\n");
1690     }
1691
1692     if ($hasForwardDeclaringAttributes) {
1693         push(@headerContent,"// Attributes\n\n");
1694         foreach my $attribute (@{$interface->attributes}) {
1695             next unless $attribute->signature->extendedAttributes->{ForwardDeclareInHeader};
1696
1697             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1698             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1699             my $getter = GetAttributeGetterName($interface, $className, $attribute);
1700             push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
1701             if (!IsReadonly($attribute)) {
1702                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
1703                 push(@headerContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
1704             }
1705             push(@headerContent, "#endif\n") if $conditionalString;
1706         }
1707     }
1708
1709     if ($hasDOMJITAttributes) {
1710         $headerIncludes{"<domjit/DOMJITGetterSetter.h>"} = 1;
1711         push(@headerContent,"// DOMJIT emitters for attributes\n\n");
1712         foreach my $attribute (@{$interface->attributes}) {
1713             next unless $attribute->signature->extendedAttributes->{"DOMJIT"};
1714
1715             my $interfaceName = $interface->name;
1716             my $className = $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name);
1717             my $domJITClassName = $className . "DOMJIT";
1718
1719             push(@headerContent, "JSC::DOMJIT::GetterSetter* domJITGetterSetterFor$className(void);\n");
1720
1721             push(@headerContent, "class $domJITClassName : public JSC::DOMJIT::GetterSetter {\n");
1722             push(@headerContent, "public:\n");
1723             push(@headerContent, "    $domJITClassName();\n");
1724             push(@headerContent, "#if ENABLE(JIT)\n");
1725             push(@headerContent, "    Ref<JSC::DOMJIT::Patchpoint> checkDOM() override;\n");
1726             push(@headerContent, "    Ref<JSC::DOMJIT::CallDOMPatchpoint> callDOM() override;\n");
1727             push(@headerContent, "#endif\n");
1728             push(@headerContent, "};\n\n");
1729         }
1730     }
1731
1732     if (HasCustomConstructor($interface)) {
1733         push(@headerContent, "// Custom constructor\n");
1734         push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState&);\n\n");
1735     }
1736
1737     if ($codeGenerator->IsConstructorTemplate($interface, "Event")) {
1738         push(@headerContent, "bool fill${interfaceName}Init(${interfaceName}Init&, JSDictionary&);\n\n");
1739     }
1740
1741     if (NeedsImplementationClass($interface)) {
1742         push(@headerContent, "template<> struct JSDOMWrapperConverterTraits<${implType}> {\n");
1743         push(@headerContent, "    using WrapperClass = ${className};\n");
1744         push(@headerContent, "};\n");
1745     }
1746
1747     push(@headerContent, GenerateEnumerationsHeaderContent($interface, $enumerations));
1748     push(@headerContent, GenerateDictionariesHeaderContent($interface, $dictionaries));
1749
1750     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
1751     push(@headerContent, "\n} // namespace WebCore\n");
1752     push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
1753
1754     if ($interface->extendedAttributes->{AppleCopyright}) {
1755         push(@headerContent, "\n");
1756         push(@headerContent, split("\r", $endAppleCopyright));
1757     }
1758
1759     # - Generate dependencies.
1760     if ($writeDependencies) {
1761         my @ancestors;
1762         $codeGenerator->ForAllParents($interface, sub {
1763             my $currentInterface = shift;
1764             push(@ancestors, $currentInterface->name);
1765         }, 0);
1766         for my $dictionary (@$dictionaries) {
1767             my $parentName = $dictionary->parent;
1768             while (defined($parentName)) {
1769                 push(@ancestors, $parentName) if $codeGenerator->IsExternalDictionaryType($parentName);
1770                 my $parentDictionary = $codeGenerator->GetDictionaryByName($parentName);
1771                 assert("Unable to find definition for dictionary named '" . $parentName . "'!") unless defined($parentDictionary);
1772                 $parentName = $parentDictionary->parent;
1773             }
1774         }
1775         push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestors), "\n");
1776         push(@depsContent, map { "$_.idl :\n" } @ancestors);
1777     }
1778 }
1779
1780 sub GeneratePropertiesHashTable
1781 {
1782     my ($object, $interface, $isInstance, $hashKeys, $hashSpecials, $hashValue1, $hashValue2, $conditionals, $runtimeEnabledFunctions, $runtimeEnabledAttributes) = @_;
1783
1784     # FIXME: These should be functions on $interface.
1785     my $interfaceName = $interface->name;
1786     my $className = "JS$interfaceName";
1787     
1788     # - Add all properties in a hashtable definition
1789     my $propertyCount = $isInstance ? InstancePropertyCount($interface) : PrototypePropertyCount($interface);
1790
1791     if (!$isInstance && NeedsConstructorProperty($interface)) {
1792         die if !$propertyCount;
1793         push(@$hashKeys, "constructor");
1794         my $getter = "js" . $interfaceName . "Constructor";
1795         push(@$hashValue1, $getter);
1796
1797         my $setter = "setJS" . $interfaceName . "Constructor";
1798         push(@$hashValue2, $setter);
1799         push(@$hashSpecials, "DontEnum");
1800     }
1801
1802     return 0 if !$propertyCount;
1803
1804     foreach my $attribute (@{$interface->attributes}) {
1805         next if ($attribute->isStatic);
1806         next if AttributeShouldBeOnInstance($interface, $attribute) != $isInstance;
1807
1808         # Global objects add RuntimeEnabled attributes after creation so do not add them to the static table.
1809         if (IsDOMGlobalObject($interface) && $attribute->signature->extendedAttributes->{EnabledAtRuntime}) {
1810             $propertyCount -= 1;
1811             next;
1812         }
1813
1814         my $name = $attribute->signature->name;
1815         push(@$hashKeys, $name);
1816
1817         my $special = GetJSCAttributesForAttribute($interface, $attribute);
1818         push(@$hashSpecials, $special);
1819
1820         if ($attribute->signature->extendedAttributes->{"DOMJIT"}) {
1821             push(@$hashValue1, "domJITGetterSetterFor" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name));
1822             push(@$hashValue2, "0");
1823         } else {
1824             my $getter = GetAttributeGetterName($interface, $className, $attribute);
1825             push(@$hashValue1, $getter);
1826
1827             if (IsReadonly($attribute)) {
1828                 push(@$hashValue2, "0");
1829             } else {
1830                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
1831                 push(@$hashValue2, $setter);
1832             }
1833         }
1834
1835         my $conditional = $attribute->signature->extendedAttributes->{Conditional};
1836         $conditionals->{$name} = $conditional if $conditional;
1837
1838         if ($attribute->signature->extendedAttributes->{EnabledAtRuntime}) {
1839             die "We currently do not support [EnabledAtRuntime] attributes on the instance (except for global objects)." if $isInstance;
1840             push(@$runtimeEnabledAttributes, $attribute);
1841         }
1842     }
1843
1844     my @functions = @{$interface->functions};
1845     push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
1846     push(@functions, @{$interface->serializable->functions}) if $interface->serializable;
1847     foreach my $function (@functions) {
1848         next if ($function->signature->extendedAttributes->{PrivateIdentifier} and not $function->signature->extendedAttributes->{PublicIdentifier});
1849         next if ($function->isStatic);
1850         next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1851         next if OperationShouldBeOnInstance($interface, $function) != $isInstance;
1852         next if $function->signature->name eq "[Symbol.Iterator]";
1853
1854         # Global objects add RuntimeEnabled operations after creation so do not add them to the static table.
1855         if (IsDOMGlobalObject($interface) && $function->signature->extendedAttributes->{EnabledAtRuntime}) {
1856             $propertyCount -= 1;
1857             next;
1858         }
1859
1860         my $name = $function->signature->name;
1861         push(@$hashKeys, $name);
1862
1863         my $functionName = GetFunctionName($interface, $className, $function);
1864         push(@$hashValue1, $functionName);
1865
1866         my $functionLength = GetFunctionLength($function);
1867         push(@$hashValue2, $functionLength);
1868
1869         push(@$hashSpecials, ComputeFunctionSpecial($interface, $function));
1870
1871         my $conditional = getConditionalForFunctionConsideringOverloads($function);
1872         $conditionals->{$name} = $conditional if $conditional;
1873
1874         if ($function->signature->extendedAttributes->{EnabledAtRuntime}) {
1875             die "We currently do not support [EnabledAtRuntime] operations on the instance (except for global objects)." if $isInstance;
1876             push(@$runtimeEnabledFunctions, $function);
1877         }
1878     }
1879
1880     return $propertyCount;
1881 }
1882
1883 sub IsNullableType
1884 {
1885     my $type = shift;
1886
1887     return substr($type, -1) eq "?";
1888 }
1889
1890 sub StripNullable
1891 {
1892     my $type = shift;
1893
1894     chop($type) if IsNullableType($type);
1895     return $type;
1896 }
1897
1898 # This computes an effective overload set for a given operation / constructor,
1899 # which represents the allowable invocations.This set is used as input for
1900 # the Web IDL overload resolution algorithm.
1901 # http://heycam.github.io/webidl/#dfn-effective-overload-set
1902 sub ComputeEffectiveOverloadSet
1903 {
1904     my ($overloads) = @_;
1905
1906     my %allSets;
1907     my $addTuple = sub {
1908         my $tuple = shift;
1909         # The Web IDL specification uses a flat set of tuples but we use a hash where the key is the
1910         # number of parameters and the value is the set of tuples for the given number of parameters.
1911         my $length = scalar(@{@$tuple[1]});
1912         if (!exists($allSets{$length})) {
1913             $allSets{$length} = [ $tuple ];
1914         } else {
1915             push(@{$allSets{$length}}, $tuple);
1916         }
1917     };
1918
1919     my $m = LengthOfLongestFunctionParameterList($overloads);
1920     foreach my $overload (@{$overloads}) {
1921         my $n = @{$overload->parameters};
1922         my @t;
1923         my @o;
1924         my $isVariadic = 0;
1925         foreach my $parameter (@{$overload->parameters}) {
1926             push(@t, $parameter->isNullable ? $parameter->type . "?" : $parameter->type);
1927             if ($parameter->isOptional) {
1928                 push(@o, "optional");
1929             } elsif ($parameter->isVariadic) {
1930                 push(@o, "variadic");
1931                 $isVariadic = 1;
1932             } else {
1933                 push(@o, "required");
1934             }
1935         }
1936         &$addTuple([$overload, [@t], [@o]]);
1937         if ($isVariadic) {
1938             my @newT = @t;
1939             my @newO = @o;
1940             for (my $i = $n; $i < $m; $i++) {
1941                 push(@newT, $t[-1]);
1942                 push(@newO, "variadic");
1943                 &$addTuple([$overload, [@newT], [@newO]]);
1944             }
1945         }
1946         for (my $i = $n - 1; $i >= 0; $i--) {
1947             my $parameter = @{$overload->parameters}[$i];
1948             last unless ($parameter->isOptional || $parameter->isVariadic);
1949             pop(@t);
1950             pop(@o);
1951             &$addTuple([$overload, [@t], [@o]]);
1952         }
1953     }
1954     return %allSets;
1955 }
1956
1957 # Determines if two types are distinguishable in the context of overload resolution,
1958 # according to the Web IDL specification:
1959 # http://heycam.github.io/webidl/#dfn-distinguishable
1960 sub AreTypesDistinguishableForOverloadResolution
1961 {
1962     my ($typeA, $typeB) = @_;
1963
1964     my $isDictionary = sub {
1965         my $type = shift;
1966         return $type eq "Dictionary" || $codeGenerator->IsDictionaryType($type);
1967     };
1968     my $isCallbackFunctionOrDictionary = sub {
1969         my $type = shift;
1970         return $codeGenerator->IsFunctionOnlyCallbackInterface($type) || &$isDictionary($type);
1971     };
1972
1973     # FIXME: The WebIDL mandates this but this currently does not work because some of our IDL is wrong.
1974     # return 0 if IsNullableType($typeA) && IsNullableType($typeB);
1975
1976     $typeA = StripNullable($typeA);
1977     $typeB = StripNullable($typeB);
1978
1979     return 0 if $typeA eq $typeB;
1980     return 0 if $typeA eq "object" or $typeB eq "object";
1981     return 0 if $codeGenerator->IsNumericType($typeA) && $codeGenerator->IsNumericType($typeB);
1982     return 0 if $codeGenerator->IsStringOrEnumType($typeA) && $codeGenerator->IsStringOrEnumType($typeB);
1983     return 0 if &$isDictionary($typeA) && &$isDictionary($typeB);
1984     return 0 if $codeGenerator->IsCallbackInterface($typeA) && $codeGenerator->IsCallbackInterface($typeB);
1985     return 0 if &$isCallbackFunctionOrDictionary($typeA) && &$isCallbackFunctionOrDictionary($typeB);
1986     return 0 if $codeGenerator->IsSequenceOrFrozenArrayType($typeA) && $codeGenerator->IsSequenceOrFrozenArrayType($typeB);
1987     # FIXME: return 0 if typeA and typeB are both exception types.
1988     return 1;
1989 }
1990
1991 # If there is more than one entry in an effective overload set that has a given type list length,
1992 # then for those entries there must be an index i such that for each pair of entries the types
1993 # at index i are distinguishable. The lowest such index is termed the distinguishing argument index.
1994 # http://heycam.github.io/webidl/#dfn-distinguishing-argument-index
1995 sub GetDistinguishingArgumentIndex
1996 {
1997     my ($function, $S) = @_;
1998
1999     # FIXME: Consider all the tuples, not just the 2 first ones?
2000     my $firstTupleTypes = @{@{$S}[0]}[1];
2001     my $secondTupleTypes = @{@{$S}[1]}[1];
2002     for (my $index = 0; $index < scalar(@$firstTupleTypes); $index++) {
2003         return $index if AreTypesDistinguishableForOverloadResolution(@{$firstTupleTypes}[$index], @{$secondTupleTypes}[$index]);
2004     }
2005     die "Undistinguishable overloads for operation " . $function->signature->name . " with length: " . scalar(@$firstTupleTypes);
2006 }
2007
2008 sub GetOverloadThatMatches
2009 {
2010     my ($S, $parameterIndex, $matches) = @_;
2011
2012     for my $tuple (@{$S}) {
2013         my $type = @{@{$tuple}[1]}[$parameterIndex];
2014         my $optionality = @{@{$tuple}[2]}[$parameterIndex];
2015         my $isNullable = IsNullableType($type);
2016         return @{$tuple}[0] if $matches->(StripNullable($type), $optionality, $isNullable);
2017     }
2018 }
2019
2020 sub getConditionalForFunctionConsideringOverloads
2021 {
2022     my $function = shift;
2023
2024     return $function->signature->extendedAttributes->{Conditional} unless $function->{overloads};
2025
2026     my %conditions;
2027     foreach my $overload (@{$function->{overloads}}) {
2028         my $conditional = $overload->signature->extendedAttributes->{Conditional};
2029         return unless $conditional;
2030         $conditions{$conditional} = 1;
2031     }
2032     return join("|", keys %conditions);
2033 }
2034
2035 # Implements the overload resolution algorithm, as defined in the Web IDL specification:
2036 # http://heycam.github.io/webidl/#es-overloads
2037 sub GenerateOverloadedFunctionOrConstructor
2038 {
2039     my ($function, $interface, $isConstructor) = @_;
2040     my %allSets = ComputeEffectiveOverloadSet($function->{overloads});
2041
2042     my $interfaceName = $interface->name;
2043     my $className = "JS$interfaceName";
2044     my $functionName;
2045     if ($isConstructor) {
2046         $functionName = "construct${className}";
2047     } else {
2048         my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
2049         $functionName = "js${interfaceName}${kind}Function" . $codeGenerator->WK_ucfirst($function->signature->name);
2050     }
2051
2052     my $generateOverloadCallIfNecessary = sub {
2053         my ($overload, $condition) = @_;
2054         return unless $overload;
2055         my $conditionalString = $codeGenerator->GenerateConditionalString($overload->signature);
2056         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2057         push(@implContent, "        if ($condition)\n    ") if $condition;
2058         push(@implContent, "        return ${functionName}$overload->{overloadIndex}(state);\n");
2059         push(@implContent, "#endif\n") if $conditionalString;
2060     };
2061     my $isOptionalParameter = sub {
2062         my ($type, $optionality, $isNullable) = @_;
2063         return $optionality eq "optional";
2064     };
2065     my $isDictionaryParameter = sub {
2066         my ($type, $optionality, $isNullable) = @_;
2067         return $type eq "Dictionary" || $codeGenerator->IsDictionaryType($type);
2068     };
2069     my $isNullableOrDictionaryParameter = sub {
2070         my ($type, $optionality, $isNullable) = @_;
2071         return $isNullable || &$isDictionaryParameter($type, $optionality, $isNullable);
2072     };
2073     my $isRegExpOrObjectParameter = sub {
2074         my ($type, $optionality, $isNullable) = @_;
2075         return $type eq "RegExp" || $type eq "object";
2076     };
2077     my $isObjectOrErrorParameter = sub {
2078         my ($type, $optionality, $isNullable) = @_;
2079         return $type eq "object" || $type eq "Error";
2080     };
2081     my $isObjectOrErrorOrDOMExceptionParameter = sub {
2082         my ($type, $optionality, $isNullable) = @_;
2083         return 1 if &$isObjectOrErrorParameter($type, $optionality, $isNullable);
2084         return $type eq "DOMException";
2085     };
2086     my $isObjectOrCallbackFunctionParameter = sub {
2087         my ($type, $optionality, $isNullable) = @_;
2088         return $type eq "object" || $codeGenerator->IsFunctionOnlyCallbackInterface($type);
2089     };
2090     my $isSequenceOrFrozenArrayParameter = sub {
2091         my ($type, $optionality, $isNullable) = @_;
2092         return $codeGenerator->IsSequenceOrFrozenArrayType($type);
2093     };
2094     my $isDictionaryOrObjectOrCallbackInterfaceParameter = sub {
2095         my ($type, $optionality, $isNullable) = @_;
2096         return 1 if &$isDictionaryParameter($type, $optionality, $isNullable);
2097         return 1 if $type eq "object";
2098         return 1 if $codeGenerator->IsCallbackInterface($type) && !$codeGenerator->IsFunctionOnlyCallbackInterface($type);
2099         return 0;
2100     };
2101     my $isBooleanParameter = sub {
2102         my ($type, $optionality, $isNullable) = @_;
2103         return $type eq "boolean";
2104     };
2105     my $isNumericParameter = sub {
2106         my ($type, $optionality, $isNullable) = @_;
2107         return $codeGenerator->IsNumericType($type);
2108     };
2109     my $isStringOrEnumParameter = sub {
2110         my ($type, $optionality, $isNullable) = @_;
2111         return $codeGenerator->IsStringOrEnumType($type);
2112     };
2113     my $isAnyParameter = sub {
2114         my ($type, $optionality, $isNullable) = @_;
2115         return $type eq "any";
2116     };
2117
2118     my $maxArgCount = LengthOfLongestFunctionParameterList($function->{overloads});
2119
2120     my $conditionalAttribute = getConditionalForFunctionConsideringOverloads($function);
2121     my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
2122     push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2123     if ($isConstructor) {
2124         push(@implContent, "template<> EncodedJSValue JSC_HOST_CALL ${className}Constructor::construct(ExecState* state)\n");
2125     } else {
2126         push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* state)\n");
2127     }
2128     push(@implContent, <<END);    
2129 {
2130     VM& vm = state->vm();
2131     auto throwScope = DECLARE_THROW_SCOPE(vm);
2132     UNUSED_PARAM(throwScope);
2133     size_t argsCount = std::min<size_t>($maxArgCount, state->argumentCount());
2134 END
2135
2136     for my $length ( sort keys %allSets ) {
2137         push(@implContent, <<END);
2138     if (argsCount == $length) {
2139 END
2140         my $S = $allSets{$length};
2141         if (scalar(@$S) > 1) {
2142             my $d = GetDistinguishingArgumentIndex($function, $S);
2143             push(@implContent, "        JSValue distinguishingArg = state->uncheckedArgument($d);\n");
2144
2145             my $overload = GetOverloadThatMatches($S, $d, \&$isOptionalParameter);
2146             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isUndefined()");
2147
2148             $overload = GetOverloadThatMatches($S, $d, \&$isNullableOrDictionaryParameter);
2149             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isUndefinedOrNull()");
2150
2151             for my $tuple (@{$S}) {
2152                 my $overload = @{$tuple}[0];
2153                 my $type = StripNullable(@{@{$tuple}[1]}[$d]);
2154                 if ($codeGenerator->IsWrapperType($type) || $codeGenerator->IsTypedArrayType($type)) {
2155                     if ($type eq "DOMWindow") {
2156                         AddToImplIncludes("JSDOMWindowShell.h");
2157                         &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && (asObject(distinguishingArg)->inherits(JSDOMWindowShell::info()) || asObject(distinguishingArg)->inherits(JSDOMWindow::info()))");
2158                     } else {
2159                         &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->inherits(JS${type}::info())");
2160                     }
2161                 }
2162             }
2163
2164             $overload = GetOverloadThatMatches($S, $d, \&$isRegExpOrObjectParameter);
2165             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() == RegExpObjectType");
2166
2167             $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrErrorOrDOMExceptionParameter);
2168             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->inherits(JSDOMCoreException::info())");
2169
2170             $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrErrorParameter);
2171             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() == ErrorInstanceType");
2172
2173             $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrCallbackFunctionParameter);
2174             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isFunction()");
2175
2176             # FIXME: Avoid invoking GetMethod(object, Symbol.iterator) again in convert<IDLSequence<T>>(...).
2177             $overload = GetOverloadThatMatches($S, $d, \&$isSequenceOrFrozenArrayParameter);
2178             &$generateOverloadCallIfNecessary($overload, "hasIteratorMethod(*state, distinguishingArg)");
2179
2180             $overload = GetOverloadThatMatches($S, $d, \&$isDictionaryOrObjectOrCallbackInterfaceParameter);
2181             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() != RegExpObjectType");
2182
2183             my $booleanOverload = GetOverloadThatMatches($S, $d, \&$isBooleanParameter);
2184             &$generateOverloadCallIfNecessary($booleanOverload, "distinguishingArg.isBoolean()");
2185
2186             my $numericOverload = GetOverloadThatMatches($S, $d, \&$isNumericParameter);
2187             &$generateOverloadCallIfNecessary($numericOverload, "distinguishingArg.isNumber()");
2188
2189             # Fallbacks.
2190             $overload = GetOverloadThatMatches($S, $d, \&$isStringOrEnumParameter);
2191             if ($overload) {
2192                 &$generateOverloadCallIfNecessary($overload);
2193             } elsif ($numericOverload) {
2194                 &$generateOverloadCallIfNecessary($numericOverload);
2195             } elsif ($booleanOverload) {
2196                 &$generateOverloadCallIfNecessary($booleanOverload);
2197             } else {
2198                 $overload = GetOverloadThatMatches($S, $d, \&$isAnyParameter);
2199                 &$generateOverloadCallIfNecessary($overload);
2200             }
2201         } else {
2202             # Only 1 overload with this number of parameters.
2203             my $overload = @{@{$S}[0]}[0];
2204             &$generateOverloadCallIfNecessary($overload);
2205         }
2206         push(@implContent, <<END);
2207     }
2208 END
2209     }
2210     my $minArgCount = GetFunctionLength($function);
2211     if ($minArgCount > 0) {
2212         push(@implContent, "    return argsCount < $minArgCount ? throwVMError(state, throwScope, createNotEnoughArgumentsError(state)) : throwVMTypeError(state, throwScope);\n")
2213     } else {
2214         push(@implContent, "    return throwVMTypeError(state, throwScope);\n")
2215     }
2216     push(@implContent, "}\n");
2217     push(@implContent, "#endif\n") if $conditionalString;
2218     push(@implContent, "\n");
2219 }
2220
2221 # As per Web IDL specification, the length of a function Object is its number of mandatory parameters.
2222 sub GetFunctionLength
2223 {
2224     my $function = shift;
2225
2226     my $getOverloadLength = sub {
2227         my $function = shift;
2228
2229         my $length = 0;
2230         foreach my $parameter (@{$function->parameters}) {
2231             last if $parameter->isOptional || $parameter->isVariadic;
2232             $length++;
2233         }
2234         return $length;
2235     };
2236
2237     my $length = &$getOverloadLength($function);
2238     foreach my $overload (@{$function->{overloads}}) {
2239         my $newLength = &$getOverloadLength($overload);
2240         $length = $newLength if $newLength < $length;
2241     }
2242     return $length;
2243 }
2244
2245 sub LengthOfLongestFunctionParameterList
2246 {
2247     my ($overloads) = @_;
2248     my $result = 0;
2249     foreach my $overload (@{$overloads}) {
2250         my @parameters = @{$overload->parameters};
2251         $result = @parameters if $result < @parameters;
2252     }
2253     return $result;
2254 }
2255
2256 sub GetNativeTypeForConversions
2257 {
2258     my $interface = shift;
2259     my $interfaceName = $interface->name;
2260     $interfaceName = $codeGenerator->GetSVGTypeNeedingTearOff($interfaceName) if $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName);
2261     return $interfaceName;
2262 }
2263
2264 # See http://refspecs.linux-foundation.org/cxxabi-1.83.html.
2265 sub GetGnuVTableRefForInterface
2266 {
2267     my $interface = shift;
2268     my $vtableName = GetGnuVTableNameForInterface($interface);
2269     if (!$vtableName) {
2270         return "0";
2271     }
2272     my $typename = GetNativeTypeForConversions($interface);
2273     my $offset = GetGnuVTableOffsetForType($typename);
2274     return "&" . $vtableName . "[" . $offset . "]";
2275 }
2276
2277 sub GetGnuVTableNameForInterface
2278 {
2279     my $interface = shift;
2280     my $typename = GetNativeTypeForConversions($interface);
2281     my $templatePosition = index($typename, "<");
2282     return "" if $templatePosition != -1;
2283     return "" if GetImplementationLacksVTableForInterface($interface);
2284     return "" if GetSkipVTableValidationForInterface($interface);
2285     return "_ZTV" . GetGnuMangledNameForInterface($interface);
2286 }
2287
2288 sub GetGnuMangledNameForInterface
2289 {
2290     my $interface = shift;
2291     my $typename = GetNativeTypeForConversions($interface);
2292     my $templatePosition = index($typename, "<");
2293     if ($templatePosition != -1) {
2294         return "";
2295     }
2296     my $mangledType = length($typename) . $typename;
2297     my $namespace = GetNamespaceForInterface($interface);
2298     my $mangledNamespace =  "N" . length($namespace) . $namespace;
2299     return $mangledNamespace . $mangledType . "E";
2300 }
2301
2302 sub GetGnuVTableOffsetForType
2303 {
2304     my $typename = shift;
2305     if ($typename eq "SVGAElement"
2306         || $typename eq "SVGCircleElement"
2307         || $typename eq "SVGClipPathElement"
2308         || $typename eq "SVGDefsElement"
2309         || $typename eq "SVGEllipseElement"
2310         || $typename eq "SVGForeignObjectElement"
2311         || $typename eq "SVGGElement"
2312         || $typename eq "SVGImageElement"
2313         || $typename eq "SVGLineElement"
2314         || $typename eq "SVGPathElement"
2315         || $typename eq "SVGPolyElement"
2316         || $typename eq "SVGPolygonElement"
2317         || $typename eq "SVGPolylineElement"
2318         || $typename eq "SVGRectElement"
2319         || $typename eq "SVGSVGElement"
2320         || $typename eq "SVGGraphicsElement"
2321         || $typename eq "SVGSwitchElement"
2322         || $typename eq "SVGTextElement"
2323         || $typename eq "SVGUseElement") {
2324         return "3";
2325     }
2326     return "2";
2327 }
2328
2329 # See http://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B_Name_Mangling.
2330 sub GetWinVTableRefForInterface
2331 {
2332     my $interface = shift;
2333     my $vtableName = GetWinVTableNameForInterface($interface);
2334     return 0 if !$vtableName;
2335     return "__identifier(\"" . $vtableName . "\")";
2336 }
2337
2338 sub GetWinVTableNameForInterface
2339 {
2340     my $interface = shift;
2341     my $typename = GetNativeTypeForConversions($interface);
2342     my $templatePosition = index($typename, "<");
2343     return "" if $templatePosition != -1;
2344     return "" if GetImplementationLacksVTableForInterface($interface);
2345     return "" if GetSkipVTableValidationForInterface($interface);
2346     return "??_7" . GetWinMangledNameForInterface($interface) . "6B@";
2347 }
2348
2349 sub GetWinMangledNameForInterface
2350 {
2351     my $interface = shift;
2352     my $typename = GetNativeTypeForConversions($interface);
2353     my $namespace = GetNamespaceForInterface($interface);
2354     return $typename . "@" . $namespace . "@@";
2355 }
2356
2357 sub GetNamespaceForInterface
2358 {
2359     my $interface = shift;
2360     return $interface->extendedAttributes->{ImplementationNamespace} || "WebCore";
2361 }
2362
2363 sub GetImplementationLacksVTableForInterface
2364 {
2365     my $interface = shift;
2366     return $interface->extendedAttributes->{ImplementationLacksVTable};
2367 }
2368
2369 sub GetSkipVTableValidationForInterface
2370 {
2371     my $interface = shift;
2372     return $interface->extendedAttributes->{SkipVTableValidation};
2373 }
2374
2375 # URL becomes url, but SetURL becomes setURL.
2376 sub ToMethodName
2377 {
2378     my $param = shift;
2379     my $ret = lcfirst($param);
2380     $ret =~ s/cSS/css/ if $ret =~ /^cSS/;
2381     $ret =~ s/dOM/dom/ if $ret =~ /^dOM/;
2382     $ret =~ s/hTML/html/ if $ret =~ /^hTML/;
2383     $ret =~ s/jS/js/ if $ret =~ /^jS/;
2384     $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
2385     $ret =~ s/xML/xml/ if $ret =~ /^xML/;
2386     $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
2387
2388     # For HTML5 FileSystem API Flags attributes.
2389     # (create is widely used to instantiate an object and must be avoided.)
2390     $ret =~ s/^create/isCreate/ if $ret =~ /^create$/;
2391     $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/;
2392
2393     return $ret;
2394 }
2395
2396 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
2397 sub GetRuntimeEnableFunctionName
2398 {
2399     my $signature = shift;
2400
2401     # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::sharedFeatures().{FeatureName}Enabled() method.
2402     return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->extendedAttributes->{EnabledAtRuntime}) . "Enabled" if ($signature->extendedAttributes->{EnabledAtRuntime} && $signature->extendedAttributes->{EnabledAtRuntime} ne "VALUE_IS_MISSING");
2403
2404     # Otherwise return a function named RuntimeEnabledFeatures::sharedFeatures().{methodName}Enabled().
2405     return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->name) . "Enabled";
2406 }
2407
2408 sub GetCastingHelperForThisObject
2409 {
2410     my $interface = shift;
2411     my $interfaceName = $interface->name;
2412
2413     return "jsNodeCast" if $interfaceName eq "Node";
2414     return "jsElementCast" if $interfaceName eq "Element";
2415     return "jsDocumentCast" if $interfaceName eq "Document";
2416     return "jsEventTargetCast" if $interfaceName eq "EventTarget";
2417     return "jsDynamicCast<JS$interfaceName*>";
2418 }
2419
2420 sub GetIndexedGetterExpression
2421 {
2422     my $indexedGetterFunction = shift;
2423     return "jsStringOrUndefined(state, thisObject->wrapped().item(index))" if $indexedGetterFunction->signature->type eq "DOMString";
2424     return "toJS(state, thisObject->globalObject(), thisObject->wrapped().item(index))";
2425 }
2426
2427 # http://heycam.github.io/webidl/#Unscopable
2428 sub addUnscopableProperties
2429 {
2430     my $interface = shift;
2431
2432     my @unscopables;
2433     foreach my $functionOrAttribute (@{$interface->functions}, @{$interface->attributes}) {
2434         push(@unscopables, $functionOrAttribute->signature->name) if $functionOrAttribute->signature->extendedAttributes->{Unscopable};
2435     }
2436     return if scalar(@unscopables) == 0;
2437
2438     AddToImplIncludes("<runtime/ObjectConstructor.h>");
2439     push(@implContent, "    JSObject& unscopables = *constructEmptyObject(globalObject()->globalExec(), globalObject()->nullPrototypeObjectStructure());\n");
2440     foreach my $unscopable (@unscopables) {
2441         push(@implContent, "    unscopables.putDirect(vm, Identifier::fromString(&vm, \"$unscopable\"), jsBoolean(true));\n");
2442     }
2443     push(@implContent, "    putDirectWithoutTransition(vm, vm.propertyNames->unscopablesSymbol, &unscopables, DontEnum | ReadOnly);\n");
2444 }
2445
2446 sub GenerateImplementation
2447 {
2448     my ($object, $interface, $enumerations, $dictionaries) = @_;
2449
2450     my $interfaceName = $interface->name;
2451     my $className = "JS$interfaceName";
2452
2453     my $hasLegacyParent = $interface->extendedAttributes->{JSLegacyParent};
2454     my $hasRealParent = $interface->parent;
2455     my $hasParent = $hasLegacyParent || $hasRealParent;
2456     my $parentClassName = GetParentClassName($interface);
2457     my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
2458     my $eventTarget = $codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->name ne "EventTarget";
2459     my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
2460
2461     my $namedGetterFunction = GetNamedGetterFunction($interface);
2462     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
2463
2464     # - Add default header template
2465     push(@implContentHeader, GenerateImplementationContentHeader($interface));
2466
2467     $implIncludes{"JSDOMBinding.h"} = 1;
2468     $implIncludes{"<wtf/GetPtr.h>"} = 1;
2469     $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $indexedGetterFunction;
2470
2471     my $implType = GetImplClassName($interfaceName);
2472
2473     AddJSBuiltinIncludesIfNeeded($interface);
2474
2475     @implContent = ();
2476
2477     push(@implContent, "\nusing namespace JSC;\n\n");
2478     push(@implContent, "namespace WebCore {\n\n");
2479
2480     push(@implContent, GenerateEnumerationsImplementationContent($interface, $enumerations));
2481     push(@implContent, GenerateDictionariesImplementationContent($interface, $dictionaries));
2482
2483     my @functions = @{$interface->functions};
2484     push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
2485     push(@functions, @{$interface->serializable->functions}) if $interface->serializable;
2486
2487     my $numConstants = @{$interface->constants};
2488     my $numFunctions = @functions;
2489     my $numAttributes = @{$interface->attributes};
2490
2491     if ($numFunctions > 0) {
2492         my $inAppleCopyright = 0;
2493         push(@implContent,"// Functions\n\n");
2494         foreach my $function (@functions) {
2495             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2496             next if $function->signature->extendedAttributes->{ForwardDeclareInHeader};
2497             next if IsJSBuiltin($interface, $function);
2498
2499             if ($function->signature->extendedAttributes->{AppleCopyright}) {
2500                 if (!$inAppleCopyright) {
2501                     push(@implContent, $beginAppleCopyrightForHeaderFiles);
2502                     $inAppleCopyright = 1;
2503                 }
2504             } elsif ($inAppleCopyright) {
2505                 push(@implContent, $endAppleCopyright);
2506                 $inAppleCopyright = 0;
2507             }
2508
2509             my $conditionalAttribute = getConditionalForFunctionConsideringOverloads($function);
2510             my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
2511             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2512             my $functionName = GetFunctionName($interface, $className, $function);
2513             push(@implContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
2514             push(@implContent, "#endif\n") if $conditionalString;
2515         }
2516
2517         push(@implContent, $endAppleCopyright) if $inAppleCopyright;
2518         push(@implContent, "\n");
2519     }
2520
2521     if ($numAttributes > 0 || NeedsConstructorProperty($interface)) {
2522         push(@implContent, "// Attributes\n\n");
2523
2524         foreach my $attribute (@{$interface->attributes}) {
2525             next if $attribute->signature->extendedAttributes->{ForwardDeclareInHeader};
2526             next if IsJSBuiltin($interface, $attribute);
2527
2528             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2529             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2530             my $getter = GetAttributeGetterName($interface, $className, $attribute);
2531             push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
2532             if (!IsReadonly($attribute)) {
2533                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
2534                 push(@implContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
2535             }
2536             push(@implContent, "#endif\n") if $conditionalString;
2537         }
2538         
2539         if (NeedsConstructorProperty($interface)) {
2540             my $getter = "js" . $interfaceName . "Constructor";
2541             push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
2542         }
2543
2544         my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2545         push(@implContent, "bool ${constructorFunctionName}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
2546
2547         push(@implContent, "\n");
2548     }
2549
2550     GeneratePrototypeDeclaration(\@implContent, $className, $interface) if !HeaderNeedsPrototypeDeclaration($interface);
2551
2552     GenerateConstructorDeclaration(\@implContent, $className, $interface) if NeedsConstructorProperty($interface);
2553
2554     my @hashKeys = ();
2555     my @hashValue1 = ();
2556     my @hashValue2 = ();
2557     my @hashSpecials = ();
2558     my %conditionals = ();
2559     my $hashName = $className . "Table";
2560     my @runtimeEnabledFunctions = ();
2561     my @runtimeEnabledAttributes = ();
2562
2563     # Generate hash table for properties on the instance.
2564     my $numInstanceProperties = GeneratePropertiesHashTable($object, $interface, 1,
2565         \@hashKeys, \@hashSpecials,
2566         \@hashValue1, \@hashValue2,
2567         \%conditionals, \@runtimeEnabledFunctions, \@runtimeEnabledAttributes);
2568
2569     $object->GenerateHashTable($hashName, $numInstanceProperties,
2570         \@hashKeys, \@hashSpecials,
2571         \@hashValue1, \@hashValue2,
2572         \%conditionals, 0) if $numInstanceProperties > 0;
2573
2574     # - Add all interface object (aka constructor) properties (constants, static attributes, static operations).
2575     if (NeedsConstructorProperty($interface)) {
2576         my $hashSize = 0;
2577         my $hashName = $className . "ConstructorTable";
2578
2579         my @hashKeys = ();
2580         my @hashValue1 = ();
2581         my @hashValue2 = ();
2582         my @hashSpecials = ();
2583         my %conditionals = ();
2584
2585         my $needsConstructorTable = 0;
2586
2587         foreach my $constant (@{$interface->constants}) {
2588             my $name = $constant->name;
2589             push(@hashKeys, $name);
2590             push(@hashValue1, $constant->value);
2591             push(@hashValue2, "0");
2592             push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
2593
2594             my $implementedBy = $constant->extendedAttributes->{ImplementedBy};
2595             $implIncludes{"${implementedBy}.h"} = 1 if $implementedBy;
2596
2597             my $conditional = $constant->extendedAttributes->{Conditional};
2598             $conditionals{$name} = $conditional if $conditional;
2599
2600             $hashSize++;
2601         }
2602
2603         foreach my $attribute (@{$interface->attributes}) {
2604             next unless ($attribute->isStatic);
2605             my $name = $attribute->signature->name;
2606             push(@hashKeys, $name);
2607
2608             my @specials = ();
2609             push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{Deletable};
2610             push(@specials, "ReadOnly") if IsReadonly($attribute);
2611             push(@specials, "DOMJITAttribute") if $attribute->signature->extendedAttributes->{"DOMJIT"};
2612             my $special = (@specials > 0) ? join(" | ", @specials) : "0";
2613             push(@hashSpecials, $special);
2614
2615             if ($attribute->signature->extendedAttributes->{"DOMJIT"}) {
2616                 push(@hashValue1, "domJITGetterSetterFor" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name));
2617                 push(@hashValue2, "0");
2618             } else {
2619                 my $getter = GetAttributeGetterName($interface, $className, $attribute);
2620                 push(@hashValue1, $getter);
2621
2622                 if (IsReadonly($attribute)) {
2623                     push(@hashValue2, "0");
2624                 } else {
2625                     my $setter = GetAttributeSetterName($interface, $className, $attribute);
2626                     push(@hashValue2, $setter);
2627                 }
2628             }
2629
2630             my $conditional = $attribute->signature->extendedAttributes->{Conditional};
2631             $conditionals{$name} = $conditional if $conditional;
2632
2633             $hashSize++;
2634         }
2635
2636         foreach my $function (@{$interface->functions}) {
2637             next unless ($function->isStatic);
2638             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2639             my $name = $function->signature->name;
2640             push(@hashKeys, $name);
2641
2642             my $functionName = GetFunctionName($interface, $className, $function);
2643             push(@hashValue1, $functionName);
2644
2645             my $functionLength = GetFunctionLength($function);
2646             push(@hashValue2, $functionLength);
2647
2648             push(@hashSpecials, ComputeFunctionSpecial($interface, $function));
2649
2650             my $conditional = $function->signature->extendedAttributes->{Conditional};
2651             $conditionals{$name} = $conditional if $conditional;
2652
2653             $hashSize++;
2654         }
2655
2656         $object->GenerateHashTable($hashName, $hashSize,
2657                                    \@hashKeys, \@hashSpecials,
2658                                    \@hashValue1, \@hashValue2,
2659                                    \%conditionals, 1) if $hashSize > 0;
2660
2661         push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($interface));
2662
2663         my $protoClassName = "${className}Prototype";
2664         GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $visibleInterfaceName, $interface);
2665
2666         my $namedConstructor = $interface->extendedAttributes->{NamedConstructor};
2667         GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $namedConstructor, $interface, "GeneratingNamedConstructor") if $namedConstructor;
2668     }
2669
2670     # - Add functions and constants to a hashtable definition
2671
2672     $hashName = $className . "PrototypeTable";
2673
2674     @hashKeys = ();
2675     @hashValue1 = ();
2676     @hashValue2 = ();
2677     @hashSpecials = ();
2678     %conditionals = ();
2679     @runtimeEnabledFunctions = ();
2680     @runtimeEnabledAttributes = ();
2681
2682     # Generate hash table for properties on the prototype.
2683     my $numPrototypeProperties = GeneratePropertiesHashTable($object, $interface, 0,
2684         \@hashKeys, \@hashSpecials,
2685         \@hashValue1, \@hashValue2,
2686         \%conditionals, \@runtimeEnabledFunctions, \@runtimeEnabledAttributes);
2687     my $hashSize = $numPrototypeProperties;
2688
2689     foreach my $constant (@{$interface->constants}) {
2690         my $name = $constant->name;
2691
2692         push(@hashKeys, $name);
2693         push(@hashValue1, $constant->value);
2694         push(@hashValue2, "0");
2695         push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
2696
2697         my $conditional = $constant->extendedAttributes->{Conditional};
2698         $conditionals{$name} = $conditional if $conditional;
2699
2700         $hashSize++;
2701     }
2702
2703     my $justGenerateValueArray = !IsDOMGlobalObject($interface);
2704
2705     $object->GenerateHashTable($hashName, $hashSize,
2706                                \@hashKeys, \@hashSpecials,
2707                                \@hashValue1, \@hashValue2,
2708                                \%conditionals, $justGenerateValueArray);
2709
2710     if ($justGenerateValueArray) {
2711         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
2712     } else {
2713         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, &${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
2714     }
2715
2716     if (PrototypeHasStaticPropertyTable($interface) && !IsDOMGlobalObject($interface)) {
2717         push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
2718         push(@implContent, "{\n");
2719         push(@implContent, "    Base::finishCreation(vm);\n");
2720         push(@implContent, "    reifyStaticProperties(vm, ${className}PrototypeTableValues, *this);\n");
2721
2722         my @runtimeEnabledProperties = @runtimeEnabledFunctions;
2723         push(@runtimeEnabledProperties, @runtimeEnabledAttributes);
2724         foreach my $functionOrAttribute (@runtimeEnabledProperties) {
2725             my $signature = $functionOrAttribute->signature;
2726             my $conditionalString = $codeGenerator->GenerateConditionalString($signature);
2727             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2728             AddToImplIncludes("RuntimeEnabledFeatures.h");
2729             my $enable_function = GetRuntimeEnableFunctionName($signature);
2730             my $name = $signature->name;
2731             push(@implContent, "    if (!${enable_function}()) {\n");
2732             push(@implContent, "        Identifier propertyName = Identifier::fromString(&vm, reinterpret_cast<const LChar*>(\"$name\"), strlen(\"$name\"));\n");
2733             push(@implContent, "        VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);\n");
2734             push(@implContent, "        JSObject::deleteProperty(this, globalObject()->globalExec(), propertyName);\n");
2735             push(@implContent, "    }\n");
2736             push(@implContent, "#endif\n") if $conditionalString;
2737         }
2738
2739         my $firstPrivateFunction = 1;
2740         foreach my $function (@{$interface->functions}) {
2741             next unless ($function->signature->extendedAttributes->{PrivateIdentifier});
2742             AddToImplIncludes("WebCoreJSClientData.h");
2743             push(@implContent, "    JSVMClientData& clientData = *static_cast<JSVMClientData*>(vm.clientData);\n") if $firstPrivateFunction;
2744             $firstPrivateFunction = 0;
2745             push(@implContent, "    putDirect(vm, clientData.builtinNames()." . $function->signature->name . "PrivateName(), JSFunction::create(vm, globalObject(), 0, String(), " . GetFunctionName($interface, $className, $function) . "), ReadOnly | DontEnum);\n");
2746         }
2747
2748         if ($interface->iterable) {
2749             addIterableProperties($interface, $className);
2750         }
2751
2752         addUnscopableProperties($interface);
2753
2754         push(@implContent, "}\n\n");
2755     }
2756
2757     if ($interface->extendedAttributes->{JSCustomNamedGetterOnPrototype}) {
2758         push(@implContent, "bool ${className}Prototype::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
2759         push(@implContent, "{\n");
2760         push(@implContent, "    auto* thisObject = jsCast<${className}Prototype*>(cell);\n");
2761         push(@implContent, "    bool putResult = false;\n");
2762         push(@implContent, "    if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
2763         push(@implContent, "        return putResult;\n");
2764         push(@implContent, "    return Base::put(thisObject, state, propertyName, value, slot);\n");
2765         push(@implContent, "}\n\n");
2766     }
2767
2768     # - Initialize static ClassInfo object
2769     push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleInterfaceName}\", &Base::s_info, ");
2770
2771     if ($numInstanceProperties > 0) {
2772         push(@implContent, "&${className}Table");
2773     } else {
2774         push(@implContent, "0");
2775     }
2776     push(@implContent, ", CREATE_METHOD_TABLE($className) };\n\n");
2777
2778     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($interfaceName);
2779     my $svgPropertyOrListPropertyType;
2780     $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
2781     $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
2782
2783     # Constructor
2784     if ($interfaceName eq "DOMWindow") {
2785         AddIncludesForTypeInImpl("JSDOMWindowShell");
2786         push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* shell)\n");
2787         push(@implContent, "    : $parentClassName(vm, structure, WTFMove(impl), shell)\n");
2788         push(@implContent, "{\n");
2789         push(@implContent, "}\n\n");
2790     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
2791         AddIncludesForTypeInImpl($interfaceName);
2792         push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl)\n");
2793         push(@implContent, "    : $parentClassName(vm, structure, WTFMove(impl))\n");
2794         push(@implContent, "{\n");
2795         push(@implContent, "}\n\n");
2796     } elsif (!NeedsImplementationClass($interface)) {
2797         push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject& globalObject)\n");
2798         push(@implContent, "    : $parentClassName(structure, globalObject) { }\n\n");
2799     } else {
2800         push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject& globalObject, Ref<$implType>&& impl)\n");
2801         push(@implContent, "    : $parentClassName(structure, globalObject, WTFMove(impl))\n");
2802         push(@implContent, "{\n");
2803         push(@implContent, "}\n\n");
2804     }
2805
2806     if (IsDOMGlobalObject($interface)) {
2807         if ($interfaceName eq "DOMWindow") {
2808             push(@implContent, "void ${className}::finishCreation(VM& vm, JSDOMWindowShell* shell)\n");
2809             push(@implContent, "{\n");
2810             push(@implContent, "    Base::finishCreation(vm, shell);\n\n");
2811         } else {
2812             push(@implContent, "void ${className}::finishCreation(VM& vm, JSProxy* proxy)\n");
2813             push(@implContent, "{\n");
2814             push(@implContent, "    Base::finishCreation(vm, proxy);\n\n");
2815         }
2816         # Support for RuntimeEnabled attributes on global objects.
2817         foreach my $attribute (@{$interface->attributes}) {
2818             next unless $attribute->signature->extendedAttributes->{EnabledAtRuntime};
2819
2820             AddToImplIncludes("RuntimeEnabledFeatures.h");
2821             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2822             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2823             my $enable_function = GetRuntimeEnableFunctionName($attribute->signature);
2824             my $attributeName = $attribute->signature->name;
2825             push(@implContent, "    if (${enable_function}()) {\n");
2826             my $getter = GetAttributeGetterName($interface, $className, $attribute);
2827             my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interface, $className, $attribute);
2828             push(@implContent, "        auto* customGetterSetter = CustomGetterSetter::create(vm, $getter, $setter);\n");
2829             my $jscAttributes = GetJSCAttributesForAttribute($interface, $attribute);
2830             push(@implContent, "        putDirectCustomAccessor(vm, vm.propertyNames->$attributeName, customGetterSetter, attributesForStructure($jscAttributes));\n");
2831             push(@implContent, "    }\n");
2832             push(@implContent, "#endif\n") if $conditionalString;
2833         }
2834
2835         # Support PrivateIdentifier attributes on global objects
2836         foreach my $attribute (@{$interface->attributes}) {
2837             next unless $attribute->signature->extendedAttributes->{PrivateIdentifier};
2838
2839             AddToImplIncludes("WebCoreJSClientData.h");
2840             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2841             my $attributeName = $attribute->signature->name;
2842             my $getter = GetAttributeGetterName($interface, $className, $attribute);
2843
2844             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2845             push(@implContent, "    putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames()." . $attributeName . "PrivateName(), CustomGetterSetter::create(vm, $getter, nullptr), attributesForStructure(DontDelete | ReadOnly));\n");
2846             push(@implContent, "#endif\n") if $conditionalString;
2847         }
2848
2849         # Support for RuntimeEnabled operations on global objects.
2850         foreach my $function (@{$interface->functions}) {
2851             next unless $function->signature->extendedAttributes->{EnabledAtRuntime};
2852             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2853
2854             AddToImplIncludes("RuntimeEnabledFeatures.h");
2855             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2856             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2857             my $enable_function = GetRuntimeEnableFunctionName($function->signature);
2858             my $functionName = $function->signature->name;
2859             my $implementationFunction = GetFunctionName($interface, $className, $function);
2860             my $functionLength = GetFunctionLength($function);
2861             my $jsAttributes = ComputeFunctionSpecial($interface, $function);
2862             push(@implContent, "    if (${enable_function}())\n");
2863
2864             my $propertyName = "vm.propertyNames->$functionName";
2865             $propertyName = "static_cast<JSVMClientData*>(vm.clientData)->builtinNames()." . $functionName . "PrivateName()" if $function->signature->extendedAttributes->{PrivateIdentifier};
2866             if (IsJSBuiltin($interface, $function)) {
2867                 push(@implContent, "        putDirectBuiltinFunction(vm, this, $propertyName, $implementationFunction(vm), attributesForStructure($jsAttributes));\n");
2868             } else {
2869                 push(@implContent, "        putDirectNativeFunction(vm, this, $propertyName, $functionLength, $implementationFunction, NoIntrinsic, attributesForStructure($jsAttributes));\n");
2870             }
2871             push(@implContent, "#endif\n") if $conditionalString;
2872         }
2873         push(@implContent, "}\n\n");
2874     }
2875
2876     unless (ShouldUseGlobalObjectPrototype($interface)) {
2877         push(@implContent, "JSObject* ${className}::createPrototype(VM& vm, JSGlobalObject* globalObject)\n");
2878         push(@implContent, "{\n");
2879         if ($interface->parent) {
2880             my $parentClassNameForPrototype = "JS" . $interface->parent;
2881             push(@implContent, "    return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, ${parentClassNameForPrototype}::prototype(vm, globalObject)));\n");
2882         } else {
2883             my $prototype = $interface->isException ? "errorPrototype" : "objectPrototype";
2884             push(@implContent, "    return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, globalObject->${prototype}()));\n");
2885         }
2886         push(@implContent, "}\n\n");
2887
2888         push(@implContent, "JSObject* ${className}::prototype(VM& vm, JSGlobalObject* globalObject)\n");
2889         push(@implContent, "{\n");
2890         push(@implContent, "    return getDOMPrototype<${className}>(vm, globalObject);\n");
2891         push(@implContent, "}\n\n");
2892     }
2893
2894     if (!$hasParent) {
2895         push(@implContent, "void ${className}::destroy(JSC::JSCell* cell)\n");
2896         push(@implContent, "{\n");
2897         push(@implContent, "    ${className}* thisObject = static_cast<${className}*>(cell);\n");
2898         push(@implContent, "    thisObject->${className}::~${className}();\n");
2899         push(@implContent, "}\n\n");
2900     }
2901
2902     my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
2903
2904     # Attributes
2905     if ($hasGetter) {
2906         if (!$interface->extendedAttributes->{CustomGetOwnPropertySlot}) {
2907             push(@implContent, "bool ${className}::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)\n");
2908             push(@implContent, "{\n");
2909             push(@implContent, "    auto* thisObject = jsCast<${className}*>(object);\n");
2910             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2911             push(@implContent, GenerateGetOwnPropertySlotBody($interface, $className, 0));
2912             push(@implContent, "}\n\n");
2913         }
2914
2915         if ($indexedGetterFunction || $namedGetterFunction
2916                 || $interface->extendedAttributes->{CustomNamedGetter}
2917                 || $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}) {
2918             push(@implContent, "bool ${className}::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot)\n");
2919             push(@implContent, "{\n");
2920             push(@implContent, "    auto* thisObject = jsCast<${className}*>(object);\n");
2921             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2922
2923             # Sink the int-to-string conversion that happens when we create a PropertyName
2924             # to the point where we actually need it.
2925             my $generatedPropertyName = 0;
2926             my $propertyNameGeneration = sub {
2927                 if ($generatedPropertyName) {
2928                     return;
2929                 }
2930                 push(@implContent, "    Identifier propertyName = Identifier::from(state, index);\n");
2931                 $generatedPropertyName = 1;
2932             };
2933
2934             if ($indexedGetterFunction) {
2935                 if ($indexedGetterFunction->signature->type eq "DOMString") {
2936                     push(@implContent, "    if (LIKELY(index <= MAX_ARRAY_INDEX)) {\n");
2937                 } else {
2938                     push(@implContent, "    if (LIKELY(index < thisObject->wrapped().length())) {\n");
2939                 }
2940                 # Assume that if there's a setter, the index will be writable
2941                 if ($interface->extendedAttributes->{CustomIndexedSetter}) {
2942                     push(@implContent, "        unsigned attributes = DontDelete;\n");
2943                 } else {
2944                     push(@implContent, "        unsigned attributes = DontDelete | ReadOnly;\n");
2945                 }
2946                 push(@implContent, "        slot.setValue(thisObject, attributes, " . GetIndexedGetterExpression($indexedGetterFunction) . ");\n");
2947                 push(@implContent, "        return true;\n");
2948                 push(@implContent, "    }\n");
2949             }
2950
2951             # Indexing an object with an integer that is not a supported property index should not call the named property getter.
2952             # https://heycam.github.io/webidl/#idl-indexed-properties
2953             if (!$indexedGetterFunction && ($namedGetterFunction || $interface->extendedAttributes->{CustomNamedGetter})) {
2954                 &$propertyNameGeneration();
2955
2956                 # This condition is to make sure we use the subclass' named getter instead of the base class one when possible.
2957                 push(@implContent, "    if (thisObject->classInfo() == info()) {\n");
2958                 push(@implContent, "        JSValue value;\n");
2959                 push(@implContent, "        if (thisObject->nameGetter(state, propertyName, value)) {\n");
2960                 push(@implContent, "            slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, value);\n");
2961                 push(@implContent, "            return true;\n");
2962                 push(@implContent, "        }\n");
2963                 push(@implContent, "    }\n");
2964                 $implIncludes{"wtf/text/AtomicString.h"} = 1;
2965             }
2966
2967             if ($interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}) {
2968                 &$propertyNameGeneration();
2969                 push(@implContent, "    if (thisObject->getOwnPropertySlotDelegate(state, propertyName, slot))\n");
2970                 push(@implContent, "        return true;\n");
2971             }
2972
2973             push(@implContent, "    return Base::getOwnPropertySlotByIndex(thisObject, state, index, slot);\n");
2974             push(@implContent, "}\n\n");
2975         }
2976
2977     }
2978
2979     if ($numAttributes > 0) {
2980         my $castingFunction = $interface->extendedAttributes->{"CustomProxyToJSObject"} ? "to${className}" : GetCastingHelperForThisObject($interface);
2981         # FIXME: Remove ImplicitThis keyword as it is no longer defined by WebIDL spec and is only used in DOMWindow.
2982         if ($interface->extendedAttributes->{"ImplicitThis"}) {
2983             push(@implContent, "template<> inline ${className}* BindingCaller<${className}>::castForAttribute(ExecState& state, EncodedJSValue thisValue)\n");
2984             push(@implContent, "{\n");
2985             push(@implContent, "    auto decodedThisValue = JSValue::decode(thisValue);\n");
2986             push(@implContent, "    if (decodedThisValue.isUndefinedOrNull())\n");
2987             push(@implContent, "        decodedThisValue = state.thisValue().toThis(&state, NotStrictMode);\n");
2988             push(@implContent, "    return $castingFunction(decodedThisValue);");
2989             push(@implContent, "}\n\n");
2990         } else {
2991             push(@implContent, "template<> inline ${className}* BindingCaller<${className}>::castForAttribute(ExecState&, EncodedJSValue thisValue)\n");
2992             push(@implContent, "{\n");
2993             push(@implContent, "    return $castingFunction(JSValue::decode(thisValue));\n");
2994             push(@implContent, "}\n\n");
2995         }
2996     }
2997
2998     if ($numFunctions > 0 && $interfaceName ne "EventTarget") {
2999         # FIXME: Make consistent castForAttibute and castForOperation in case of CustomProxyToJSObject.
3000         my $castingFunction = $interface->extendedAttributes->{"CustomProxyToJSObject"} ? "to${className}" : GetCastingHelperForThisObject($interface);
3001         my $thisValue = $interface->extendedAttributes->{"CustomProxyToJSObject"} ? "state.thisValue().toThis(&state, NotStrictMode)" : "state.thisValue()";
3002         push(@implContent, "template<> inline ${className}* BindingCaller<${className}>::castForOperation(ExecState& state)\n");
3003         push(@implContent, "{\n");
3004         push(@implContent, "    return $castingFunction($thisValue);\n");
3005         push(@implContent, "}\n\n");
3006     }
3007
3008     $numAttributes = $numAttributes + 1 if NeedsConstructorProperty($interface);
3009     if ($numAttributes > 0) {
3010         foreach my $attribute (@{$interface->attributes}) {
3011             next if IsJSBuiltin($interface, $attribute);
3012
3013             my $name = $attribute->signature->name;
3014             my $type = $attribute->signature->type;
3015             my $getFunctionName = GetAttributeGetterName($interface, $className, $attribute);
3016             my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->extendedAttributes->{ImplementedAs} || $name);
3017             my $getterMayThrowLegacyException = $attribute->signature->extendedAttributes->{GetterMayThrowLegacyException};
3018
3019             $implIncludes{"ExceptionCode.h"} = 1 if $getterMayThrowLegacyException;
3020
3021             my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
3022             push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
3023
3024             if (!$attribute->isStatic || $attribute->signature->type =~ /Constructor$/) {
3025                 my $templateParameters = "${getFunctionName}Getter";
3026                 if ($attribute->signature->extendedAttributes->{LenientThis}) {
3027                     $templateParameters .= ", CastedThisErrorBehavior::ReturnEarly";
3028                 } elsif (IsReturningPromise($attribute)) {
3029                     $templateParameters .= ", CastedThisErrorBehavior::RejectPromise";
3030                 }
3031
3032                 push(@implContent, "static inline JSValue ${getFunctionName}Getter(ExecState&, ${className}&, ThrowScope& throwScope);\n\n");
3033
3034                 push(@implContent, "EncodedJSValue ${getFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
3035                 push(@implContent, "{\n");
3036                 push(@implContent, "    return BindingCaller<${className}>::attribute<${templateParameters}>(state, thisValue, \"$name\");\n");
3037                 push(@implContent, "}\n\n");
3038
3039                 push(@implContent, "static inline JSValue ${getFunctionName}Getter(ExecState& state, ${className}& thisObject, ThrowScope& throwScope)\n");
3040                 push(@implContent, "{\n");
3041                 push(@implContent, "    UNUSED_PARAM(throwScope);\n");
3042             } else {
3043                 push(@implContent, "static inline JSValue ${getFunctionName}Getter(ExecState&);\n\n");
3044
3045                 push(@implContent, "EncodedJSValue ${getFunctionName}(ExecState* state, EncodedJSValue, PropertyName)\n");
3046                 push(@implContent, "{\n");
3047                 push(@implContent, "    ASSERT(state);\n");
3048                 push(@implContent, "    return JSValue::encode(${getFunctionName}Getter(*state));\n");
3049                 push(@implContent, "}\n\n");
3050
3051                 push(@implContent, "static inline JSValue ${getFunctionName}Getter(ExecState& state)\n");
3052                 push(@implContent, "{\n");
3053             }
3054             push(@implContent, "    UNUSED_PARAM(state);\n");
3055
3056             my @arguments = ();
3057             if ($getterMayThrowLegacyException && !HasCustomGetter($attribute->signature->extendedAttributes)) {
3058                 push(@arguments, "ec");
3059                 push(@implContent, "    ExceptionCode ec = 0;\n");
3060             }
3061
3062             # Global constructors can be disabled at runtime.
3063             if ($attribute->signature->type =~ /Constructor$/) {
3064                 if ($attribute->signature->extendedAttributes->{EnabledBySetting}) {
3065                     AddToImplIncludes("Frame.h");
3066                     AddToImplIncludes("Settings.h");
3067                     my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{EnabledBySetting}) . "Enabled";
3068                     push(@implContent, "    if (UNLIKELY(!thisObject.wrapped().frame()))\n");
3069                     push(@implContent, "        return jsUndefined();\n");
3070                     push(@implContent, "    Settings& settings = thisObject.wrapped().frame()->settings();\n");
3071                     push(@implContent, "    if (!settings.$enable_function())\n");
3072                     push(@implContent, "        return jsUndefined();\n");
3073                 }
3074             }
3075
3076             $needsVisitChildren = 1 if ShouldCacheAttribute($attribute);
3077
3078             if ($interface->extendedAttributes->{CheckSecurity} &&
3079                 !$attribute->signature->extendedAttributes->{DoNotCheckSecurity} &&
3080                 !$attribute->signature->extendedAttributes->{DoNotCheckSecurityOnGetter}) {
3081                 if ($interfaceName eq "DOMWindow") {
3082                     push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(&state, thisObject.wrapped(), ThrowSecurityError))\n");
3083                 } else {
3084                     push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToFrame(&state, thisObject.wrapped().frame(), ThrowSecurityError))\n");
3085                 }
3086                 push(@implContent, "        return jsUndefined();\n");
3087             }
3088
3089             if ($attribute->signature->extendedAttributes->{Nondeterministic}) {
3090                 AddToImplIncludes("MemoizedDOMResult.h", "WEB_REPLAY");
3091                 AddToImplIncludes("<replay/InputCursor.h>", "WEB_REPLAY");
3092                 AddToImplIncludes("<wtf/NeverDestroyed.h>", "WEB_REPLAY");
3093
3094                 push(@implContent, "#if ENABLE(WEB_REPLAY)\n");
3095                 push(@implContent, "    JSGlobalObject* globalObject = state.lexicalGlobalObject();\n");
3096                 push(@implContent, "    InputCursor& cursor = globalObject->inputCursor();\n");
3097
3098                 my $nativeType = GetNativeType($interface, $type);
3099                 my $memoizedType = GetNativeTypeForMemoization($interface, $type);
3100                 my $exceptionCode = $getterMayThrowLegacyException ? "ec" : "0";
3101                 push(@implContent, "    static NeverDestroyed<const AtomicString> bindingName(\"$interfaceName.$name\", AtomicString::ConstructFromLiteral);\n");
3102                 push(@implContent, "    if (cursor.isCapturing()) {\n");
3103                 push(@implContent, "        $memoizedType memoizedResult = thisObject.wrapped().$implGetterFunctionName(" . join(", ", @arguments) . ");\n");
3104                 push(@implContent, "        cursor.appendInput<MemoizedDOMResult<$memoizedType>>(bindingName.get().string(), memoizedResult, $exceptionCode);\n");
3105                 push(@implContent, "        JSValue result = " . NativeToJSValueUsingReferences($attribute->signature, 0, $interface, "memoizedResult", "thisObject") . ";\n");
3106                 push(@implContent, "        setDOMException(&state, throwScope, ec);\n") if $getterMayThrowLegacyException;
3107                 push(@implContent, "        return result;\n");
3108                 push(@implContent, "    }\n");
3109                 push(@implContent, "\n");
3110                 push(@implContent, "    if (cursor.isReplaying()) {\n");
3111                 push(@implContent, "        $memoizedType memoizedResult;\n");
3112                 push(@implContent, "        MemoizedDOMResultBase* input = cursor.fetchInput<MemoizedDOMResultBase>();\n");
3113                 push(@implContent, "        if (input && input->convertTo<$memoizedType>(memoizedResult)) {\n");
3114                 # FIXME: the generated code should report an error if an input cannot be fetched or converted.
3115                 push(@implContent, "            JSValue result = " . NativeToJSValueUsingReferences($attribute->signature, 0, $interface, "memoizedResult", "thisObject") . ";\n");
3116                 push(@implContent, "            setDOMException(&state, throwScope, input->exceptionCode());\n") if $getterMayThrowLegacyException;
3117                 push(@implContent, "            return result;\n");
3118                 push(@implContent, "        }\n");
3119                 push(@implContent, "    }\n");
3120                 push(@implContent, "#endif\n");
3121             } # attribute Nondeterministic
3122
3123             if (HasCustomGetter($attribute->signature->extendedAttributes)) {
3124                 push(@implContent, "    return thisObject