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