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