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