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