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