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