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