Binding generator should support interfaces with CustomConstructor and NoInterfaceObject
[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 (NeedsConstructorProperty($interface)) {
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 || NeedsConstructorProperty($interface)) {
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 (NeedsConstructorProperty($interface)) {
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 (NeedsConstructorProperty($interface)) {
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 (NeedsConstructorProperty($interface)) {
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 NeedsConstructorProperty($interface);
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 (NeedsConstructorProperty($interface)) {
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             if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
2444                 push(@implContent, "    return JSValue::encode(${className}::getConstructor(exec->vm(), domObject->globalObject()));\n");
2445             } else {
2446                 push(@implContent, "    JSValue constructor = ${className}Constructor::create(exec->vm(), ${className}Constructor::createStructure(exec->vm(), domObject->globalObject(), domObject->globalObject()->objectPrototype()), jsCast<JSDOMGlobalObject*>(domObject->globalObject()));\n");
2447                 push(@implContent, "    // Shadowing constructor property to ensure reusing the same constructor object\n");
2448                 push(@implContent, "    domObject->putDirect(exec->vm(), exec->propertyNames().constructor, constructor, DontEnum | ReadOnly);\n");
2449                 push(@implContent, "    return JSValue::encode(constructor);\n");
2450             }
2451             push(@implContent, "}\n\n");
2452         }
2453
2454         if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
2455             my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2456
2457             push(@implContent, "void ${constructorFunctionName}(ExecState* exec, JSObject*, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
2458             push(@implContent, "{\n");
2459             push(@implContent, "    JSValue value = JSValue::decode(encodedValue);");
2460             if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
2461                 push(@implContent, "    ${className}* castedThis = to${className}(JSValue::decode(thisValue));\n");
2462             } else {
2463                 push(@implContent, "    ${className}* castedThis = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
2464             }
2465             push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2466             push(@implContent, "        throwVMTypeError(exec);\n");
2467             push(@implContent, "        return;\n");
2468             push(@implContent, "    }\n");
2469             if ($interface->extendedAttributes->{"CheckSecurity"}) {
2470                 if ($interfaceName eq "DOMWindow") {
2471                     push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2472                 } else {
2473                     push(@implContent, "    if (!shouldAllowAccessToFrame(exec, castedThis->impl().frame()))\n");
2474                 }
2475                 push(@implContent, "        return;\n");
2476             }
2477
2478             push(@implContent, "    // Shadowing a built-in constructor\n");
2479
2480             if ($interfaceName eq "DOMWindow") {
2481                 push(@implContent, "    castedThis->putDirect(exec->vm(), exec->propertyNames().constructor, value);\n");
2482             } else {
2483                 die "No way to handle interface with ReplaceableConstructor extended attribute: $interfaceName";
2484             }
2485             push(@implContent, "}\n\n");
2486         }
2487     }
2488     my $hasCustomSetter = $interface->extendedAttributes->{"CustomNamedSetter"}
2489                           || $interface->extendedAttributes->{"CustomIndexedSetter"};
2490
2491     if ($hasCustomSetter) {
2492         if (!$interface->extendedAttributes->{"CustomPutFunction"}) {
2493             push(@implContent, "void ${className}::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
2494             push(@implContent, "{\n");
2495             push(@implContent, "    auto* thisObject = jsCast<${className}*>(cell);\n");
2496             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2497             if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2498                 push(@implContent, "    if (Optional<uint32_t> index = parseIndex(propertyName)) {\n");
2499                 push(@implContent, "        thisObject->indexSetter(exec, index.value(), value);\n");
2500                 push(@implContent, "        return;\n");
2501                 push(@implContent, "    }\n");
2502             }
2503             if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2504                 push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
2505                 push(@implContent, "        return;\n");
2506             }
2507
2508             push(@implContent, "    Base::put(thisObject, exec, propertyName, value, slot);\n");
2509             push(@implContent, "}\n\n");
2510
2511             if ($interface->extendedAttributes->{"CustomIndexedSetter"} || $interface->extendedAttributes->{"CustomNamedSetter"}) {
2512                 push(@implContent, "void ${className}::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)\n");
2513                 push(@implContent, "{\n");
2514                 push(@implContent, "    auto* thisObject = jsCast<${className}*>(cell);\n");
2515                 push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2516
2517                 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2518                     push(@implContent, "    if (index <= MAX_ARRAY_INDEX) {\n");
2519                     push(@implContent, "        thisObject->indexSetter(exec, index, value);\n");
2520                     push(@implContent, "        return;\n");
2521                     push(@implContent, "    }\n");
2522                 }
2523
2524                 if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2525                     push(@implContent, "    Identifier propertyName = Identifier::from(exec, index);\n");
2526                     push(@implContent, "    PutPropertySlot slot(thisObject, shouldThrow);\n");
2527                     push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
2528                     push(@implContent, "        return;\n");
2529                 }
2530
2531                 push(@implContent, "    Base::putByIndex(cell, exec, index, value, shouldThrow);\n");
2532                 push(@implContent, "}\n\n");
2533             }
2534         }
2535     }
2536
2537     foreach my $attribute (@{$interface->attributes}) {
2538         if (!IsReadonly($attribute)) {
2539             my $name = $attribute->signature->name;
2540             my $type = $attribute->signature->type;
2541             my $putFunctionName = GetAttributeSetterName($interfaceName, $className, $attribute);
2542             my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
2543             my $setterRaisesException = $attribute->signature->extendedAttributes->{"SetterRaisesException"};
2544
2545             my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2546             push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2547
2548             push(@implContent, "void ${putFunctionName}(ExecState* exec, JSObject* baseObject, EncodedJSValue");
2549             push(@implContent, " thisValue") if !$attribute->isStatic;
2550             push(@implContent, ", EncodedJSValue encodedValue)\n");
2551             push(@implContent, "{\n");
2552             push(@implContent, "    JSValue value = JSValue::decode(encodedValue);\n");
2553             push(@implContent, "    UNUSED_PARAM(baseObject);\n");
2554             if (!$attribute->isStatic) {
2555                 if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
2556                     push(@implContent, "    ${className}* castedThis = to${className}(JSValue::decode(thisValue));\n");
2557                 } elsif (AttributeShouldBeOnInstance($interface, $attribute)) {
2558                     push(@implContent, "    UNUSED_PARAM(thisValue);\n");
2559                     push(@implContent, "    auto* castedThis = jsCast<JS${interfaceName}*>(baseObject);\n");
2560                     if (InterfaceRequiresAttributesOnInstanceForCompatibility($interface)) {
2561                         push(@implContent, "    ${className}* castedThisObject = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
2562                         push(@implContent, "    if (UNLIKELY(!castedThisObject))\n");
2563                         push(@implContent, "        reportDeprecatedSetterError(*exec, \"$interfaceName\", \"$name\");\n");
2564                     } else {
2565                         push(@implContent, "    UNUSED_PARAM(thisValue);\n");
2566                         push(@implContent, "    UNUSED_PARAM(exec);\n");
2567                     }
2568                 } else {
2569                     push(@implContent, "    ${className}* castedThis = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
2570                     push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2571                     push(@implContent, "        if (jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue)))\n");
2572                     push(@implContent, "            reportDeprecatedSetterError(*exec, \"$interfaceName\", \"$name\");\n");
2573                     push(@implContent, "        else\n");
2574                     push(@implContent, "            throwSetterTypeError(*exec, \"$interfaceName\", \"$name\");\n");
2575                     push(@implContent, "        return;\n");
2576                     push(@implContent, "    }\n");
2577                 }
2578             }
2579             if ($interface->extendedAttributes->{"CheckSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2580                 if ($interfaceName eq "DOMWindow") {
2581                     push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2582                 } else {
2583                     push(@implContent, "    if (!shouldAllowAccessToFrame(exec, castedThis->impl().frame()))\n");
2584                 }
2585                 push(@implContent, "        return;\n");
2586             }
2587
2588             if (HasCustomSetter($attribute->signature->extendedAttributes)) {
2589                 push(@implContent, "    castedThis->set$implSetterFunctionName(exec, value);\n");
2590             } elsif ($type eq "EventHandler") {
2591                 $implIncludes{"JSEventListener.h"} = 1;
2592                 my $eventName = EventHandlerAttributeEventName($attribute);
2593                 # FIXME: Find a way to do this special case without hardcoding the class and attribute names here.
2594                 if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerGlobalScope")) and $name eq "onerror") {
2595                     $implIncludes{"JSErrorHandler.h"} = 1;
2596                     push(@implContent, "    castedThis->impl().setAttributeEventListener($eventName, createJSErrorHandler(exec, value, castedThis));\n");
2597                 } else {
2598                     $implIncludes{"JSEventListener.h"} = 1;
2599                     my $setter = $attribute->signature->extendedAttributes->{"WindowEventHandler"} ? "setWindowEventHandlerAttribute"
2600                         : $attribute->signature->extendedAttributes->{"DocumentEventHandler"} ? "setDocumentEventHandlerAttribute"
2601                         : "setEventHandlerAttribute";
2602                     push(@implContent, "    $setter(*exec, *castedThis, castedThis->impl(), $eventName, value);\n");
2603                 }
2604             } elsif ($attribute->signature->type =~ /Constructor$/) {
2605                 my $constructorType = $attribute->signature->type;
2606                 $constructorType =~ s/Constructor$//;
2607                 # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
2608                 # We do not generate the header file for NamedConstructor of class XXXX,
2609                 # since we generate the NamedConstructor declaration into the header file of class XXXX.
2610                 if ($constructorType ne "any" and $constructorType !~ /Named$/) {
2611                     AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2612                 }
2613                 push(@implContent, "    // Shadowing a built-in constructor.\n");
2614                 push(@implContent, "    castedThis->putDirect(exec->vm(), Identifier::fromString(exec, \"$name\"), value);\n");
2615             } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
2616                 push(@implContent, "    // Shadowing a built-in object.\n");
2617                 push(@implContent, "    castedThis->putDirect(exec->vm(), Identifier::fromString(exec, \"$name\"), value);\n");
2618             } else {
2619                 if (!$attribute->isStatic) {
2620                     push(@implContent, "    auto& impl = castedThis->impl();\n");
2621                 }
2622                 push(@implContent, "    ExceptionCode ec = 0;\n") if $setterRaisesException;
2623
2624                 # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
2625                 # interface type, then if the incoming value does not implement that interface, a TypeError
2626                 # is thrown rather than silently passing NULL to the C++ code.
2627                 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to
2628                 # both strings and numbers, so do not throw TypeError if the attribute is of these types.
2629                 if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
2630                     $implIncludes{"<runtime/Error.h>"} = 1;
2631
2632                     my $argType = $attribute->signature->type;
2633                     if ($codeGenerator->IsWrapperType($argType)) {
2634                         push(@implContent, "    if (!value.isUndefinedOrNull() && !value.inherits(JS${argType}::info())) {\n");
2635                         push(@implContent, "        throwAttributeTypeError(*exec, \"$interfaceName\", \"$name\", \"$argType\");\n");
2636                         push(@implContent, "        return;\n");
2637                         push(@implContent, "    };\n");
2638                     }
2639                 }
2640
2641                 push(@implContent, "    " . GetNativeTypeFromSignature($attribute->signature) . " nativeValue(" . JSValueToNative($attribute->signature, "value", $attribute->signature->extendedAttributes->{"Conditional"}) . ");\n");
2642                 push(@implContent, "    if (UNLIKELY(exec->hadException()))\n");
2643                 push(@implContent, "        return;\n");
2644
2645                 if ($codeGenerator->IsEnumType($type)) {
2646                     my @enumValues = $codeGenerator->ValidEnumValues($type);
2647                     my @enumChecks = ();
2648                     foreach my $enumValue (@enumValues) {
2649                         push(@enumChecks, "nativeValue != \"$enumValue\"");
2650                     }
2651                     push (@implContent, "    if (" . join(" && ", @enumChecks) . ")\n");
2652                     push (@implContent, "        return;\n");
2653                 }
2654
2655                 if ($attribute->signature->type eq "double" or $attribute->signature->type eq "float") {
2656                     push(@implContent, "    if (!std::isfinite(nativeValue)) {\n");
2657                     push(@implContent, "        setDOMException(exec, TypeError);\n");
2658                     push(@implContent, "        return;\n");
2659                     push(@implContent, "    }\n");
2660                 }
2661
2662                 if ($svgPropertyOrListPropertyType) {
2663                     if ($svgPropertyType) {
2664                         push(@implContent, "    if (impl.isReadOnly()) {\n");
2665                         push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
2666                         push(@implContent, "        return;\n");
2667                         push(@implContent, "    }\n");
2668                         $implIncludes{"ExceptionCode.h"} = 1;
2669                     }
2670                     push(@implContent, "    $svgPropertyOrListPropertyType& podImpl = impl.propertyReference();\n");
2671                     if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
2672                         push(@implContent, "    podImpl = nativeValue;\n");
2673                     } else {
2674                         push(@implContent, "    podImpl.set$implSetterFunctionName(nativeValue");
2675                         push(@implContent, ", ec") if $setterRaisesException;
2676                         push(@implContent, ");\n");
2677                         push(@implContent, "    setDOMException(exec, ec);\n") if $setterRaisesException;
2678                     }
2679                     if ($svgPropertyType) {
2680                         if ($setterRaisesException) {
2681                             push(@implContent, "    if (!ec)\n");
2682                             push(@implContent, "        impl.commitChange();\n");
2683                         } else {
2684                             push(@implContent, "    impl.commitChange();\n");
2685                         }
2686                     }
2687                 } else {
2688                     my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
2689                     if ($codeGenerator->IsTypedArrayType($attribute->signature->type) and not $attribute->signature->type eq "ArrayBuffer") {
2690                         push(@arguments, "nativeValue.get()");
2691                     } else {
2692                         push(@arguments, "nativeValue");
2693                     }
2694                     if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
2695                         my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
2696                         AddToImplIncludes("${implementedBy}.h", $attribute->signature->extendedAttributes->{"Conditional"});
2697                         unshift(@arguments, "&impl") if !$attribute->isStatic;
2698                         $functionName = "${implementedBy}::${functionName}";
2699                     } elsif ($attribute->isStatic) {
2700                         $functionName = "${interfaceName}::${functionName}";
2701                     } else {
2702                         $functionName = "impl.${functionName}";
2703                     }
2704
2705                     unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, ""));
2706
2707                     push(@arguments, "ec") if $setterRaisesException;
2708                     push(@implContent, "    ${functionName}(" . join(", ", @arguments) . ");\n");
2709                     push(@implContent, "    setDOMException(exec, ec);\n") if $setterRaisesException;
2710                 }
2711             }
2712
2713             push(@implContent, "}\n\n");
2714             push(@implContent, "#endif\n") if $attributeConditionalString;
2715             push(@implContent, "\n");
2716         }
2717     }
2718
2719     if ($indexedGetterFunction && !$interface->extendedAttributes->{"CustomEnumerateProperty"}) {
2720         push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
2721         push(@implContent, "{\n");
2722         push(@implContent, "    auto* thisObject = jsCast<${className}*>(object);\n");
2723         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2724         push(@implContent, "    for (unsigned i = 0, count = thisObject->impl().length(); i < count; ++i)\n");
2725         push(@implContent, "        propertyNames.add(Identifier::from(exec, i));\n");
2726         push(@implContent, "    Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);\n");
2727         push(@implContent, "}\n\n");
2728     }
2729
2730     if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
2731         push(@implContent, "JSValue ${className}::getConstructor(VM& vm, JSGlobalObject* globalObject)\n{\n");
2732         push(@implContent, "    return getDOMConstructor<${className}Constructor>(vm, jsCast<JSDOMGlobalObject*>(globalObject));\n");
2733         push(@implContent, "}\n\n");
2734         if ($interface->extendedAttributes->{"NamedConstructor"}) {
2735             push(@implContent, "JSValue ${className}::getNamedConstructor(VM& vm, JSGlobalObject* globalObject)\n{\n");
2736             push(@implContent, "    return getDOMConstructor<${className}NamedConstructor>(vm, jsCast<JSDOMGlobalObject*>(globalObject));\n");
2737             push(@implContent, "}\n\n");
2738         }
2739     }
2740
2741     # Functions
2742     if ($numFunctions > 0) {
2743         my $inAppleCopyright = 0;
2744         foreach my $function (@{$interface->functions}) {
2745             my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
2746             if ($needsAppleCopyright) {
2747                 if (!$inAppleCopyright) {
2748                     push(@implContent, $beginAppleCopyrightForSourceFiles);
2749                     $inAppleCopyright = 1;
2750                 }
2751             } elsif ($inAppleCopyright) {
2752                 push(@implContent, $endAppleCopyright);
2753                 $inAppleCopyright = 0;
2754             }
2755
2756             my $isCustom = HasCustomMethod($function->signature->extendedAttributes);
2757             my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
2758             my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
2759
2760             next if $isCustom && $isOverloaded && $function->{overloadIndex} > 1;
2761
2762             AddIncludesForTypeInImpl($function->signature->type) unless $isCustom;
2763
2764             my $functionName = GetFunctionName($className, $function);
2765
2766             my $conditional = $function->signature->extendedAttributes->{"Conditional"};
2767             if ($conditional) {
2768                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2769                 push(@implContent, "#if ${conditionalString}\n");
2770             }
2771
2772
2773             if (!$isCustom && $isOverloaded) {
2774                 # Append a number to an overloaded method's name to make it unique:
2775                 $functionName = $functionName . $function->{overloadIndex};
2776                 # Make this function static to avoid compiler warnings, since we
2777                 # don't generate a prototype for it in the header.
2778                 push(@implContent, "static ");
2779             }
2780
2781             my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
2782
2783             push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
2784             push(@implContent, "{\n");
2785
2786             $implIncludes{"<runtime/Error.h>"} = 1;
2787
2788             if ($function->isStatic) {
2789                 if ($isCustom) {
2790                     GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2791                     push(@implContent, "    return JSValue::encode(${className}::" . $functionImplementationName . "(exec));\n");
2792                 } else {
2793                     GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2794
2795                     push(@implContent, "    ExceptionCode ec = 0;\n") if $raisesException;
2796
2797                     my $numParameters = @{$function->parameters};
2798                     my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
2799                     GenerateImplementationFunctionCall($function, $functionString, "    ", $svgPropertyType, $interfaceName);
2800                 }
2801             } else {
2802                 if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
2803                     push(@implContent, "    $className* castedThis = to${className}(exec->thisValue().toThis(exec, NotStrictMode));\n");
2804                     push(@implContent, "    if (UNLIKELY(!castedThis))\n");
2805                     push(@implContent, "        return throwVMTypeError(exec);\n");
2806                 } elsif ($interface->extendedAttributes->{"WorkerGlobalScope"}) {
2807                     push(@implContent, "    $className* castedThis = to${className}(exec->thisValue().toThis(exec, NotStrictMode));\n");
2808                     push(@implContent, "    if (UNLIKELY(!castedThis))\n");
2809                     push(@implContent, "        return throwVMTypeError(exec);\n");
2810                 } else {
2811                     push(@implContent, "    JSValue thisValue = exec->thisValue();\n");
2812                     push(@implContent, "    $className* castedThis = " . GetCastingHelperForThisObject($interface) . "(thisValue);\n");
2813                     my $domFunctionName = $function->signature->name;
2814                     push(@implContent, "    if (UNLIKELY(!castedThis))\n");
2815                     push(@implContent, "        return throwThisTypeError(*exec, \"$interfaceName\", \"$domFunctionName\");\n");
2816                 }
2817
2818                 push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(castedThis, ${className}::info());\n");
2819
2820                 if ($interface->extendedAttributes->{"CheckSecurity"} and
2821                     !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2822                     push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2823                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2824                 }
2825
2826                 if ($isCustom) {
2827                     push(@implContent, "    return JSValue::encode(castedThis->" . $functionImplementationName . "(exec));\n");
2828                 } else {
2829                     push(@implContent, "    auto& impl = castedThis->impl();\n");
2830                     if ($svgPropertyType) {
2831                         push(@implContent, "    if (impl.isReadOnly()) {\n");
2832                         push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
2833                         push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2834                         push(@implContent, "    }\n");
2835                         push(@implContent, "    $svgPropertyType& podImpl = impl.propertyReference();\n");
2836                         $implIncludes{"ExceptionCode.h"} = 1;
2837                     }
2838
2839                     # For compatibility with legacy content, the EventListener calls are generated without GenerateArgumentsCountCheck.
2840                     if ($function->signature->name eq "addEventListener") {
2841                         push(@implContent, GenerateEventListenerCall("add"));
2842                     } elsif ($function->signature->name eq "removeEventListener") {
2843                         push(@implContent, GenerateEventListenerCall("remove"));
2844                     } else {
2845                         GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2846
2847                         push(@implContent, "    ExceptionCode ec = 0;\n") if $raisesException;
2848
2849                         if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) {
2850                             push(@implContent, "    if (!shouldAllowAccessToNode(exec, impl." . $function->signature->name . "(" . ($raisesException ? "ec" : "") .")))\n");
2851                             push(@implContent, "        return JSValue::encode(jsNull());\n");
2852                             $implIncludes{"JSDOMBinding.h"} = 1;
2853                         }
2854
2855                         my $numParameters = @{$function->parameters};
2856                         my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
2857                         GenerateImplementationFunctionCall($function, $functionString, "    ", $svgPropertyType, $interfaceName);
2858                     }
2859                 }
2860             }
2861
2862             push(@implContent, "}\n\n");
2863             push(@implContent, "#endif\n\n") if $conditional;
2864
2865             if (!$isCustom && $isOverloaded && $function->{overloadIndex} == @{$function->{overloads}}) {
2866                 # Generate a function dispatching call to the rest of the overloads.
2867                 GenerateOverloadedFunction($function, $interface, $interfaceName);
2868             }
2869
2870         }
2871
2872         push(@implContent, $endAppleCopyright) if $inAppleCopyright;
2873
2874     }
2875
2876     if ($needsVisitChildren) {
2877         push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n");
2878         push(@implContent, "{\n");
2879         push(@implContent, "    auto* thisObject = jsCast<${className}*>(cell);\n");
2880         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2881         push(@implContent, "    Base::visitChildren(thisObject, visitor);\n");
2882         if ($interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget") {
2883             push(@implContent, "    thisObject->impl().visitJSEventListeners(visitor);\n");
2884         }
2885         push(@implContent, "    thisObject->visitAdditionalChildren(visitor);\n") if $interface->extendedAttributes->{"JSCustomMarkFunction"};
2886         if ($interface->extendedAttributes->{"ReportExtraMemoryCost"}) {
2887             push(@implContent, "    visitor.reportExtraMemoryVisited(cell, thisObject->impl().memoryCost());\n");
2888         }
2889         if ($numCachedAttributes > 0) {
2890             foreach (@{$interface->attributes}) {
2891                 my $attribute = $_;
2892                 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2893                     push(@implContent, "    visitor.append(&thisObject->m_" . $attribute->signature->name . ");\n");
2894                 }
2895             }
2896         }
2897         push(@implContent, "}\n\n");
2898     }
2899
2900     # Cached attributes are indeed allowed when there is a custom mark/visitChildren function.
2901     # The custom function must make sure to account for the cached attribute.
2902     # Uncomment the below line to temporarily enforce generated mark functions when cached attributes are present.
2903     # die "Can't generate binding for class with cached attribute and custom mark." if (($numCachedAttributes > 0) and ($interface->extendedAttributes->{"JSCustomMarkFunction"}));
2904
2905     if ($indexedGetterFunction) {
2906         if ($indexedGetterFunction->signature->type eq "DOMString") {
2907             $implIncludes{"URL.h"} = 1;
2908         }
2909         if ($interfaceName =~ /^HTML\w*Collection$/ or $interfaceName eq "RadioNodeList") {
2910             $implIncludes{"JSNode.h"} = 1;
2911             $implIncludes{"Node.h"} = 1;
2912         }
2913     }
2914
2915     if ($interfaceName eq "DOMNamedFlowCollection") {
2916         if ($namedGetterFunction) {
2917             push(@implContent, "bool ${className}::canGetItemsForName(ExecState*, $interfaceName* collection, PropertyName propertyName)\n");
2918             push(@implContent, "{\n");
2919             push(@implContent, "    return collection->hasNamedItem(propertyNameToAtomicString(propertyName));\n");
2920             push(@implContent, "}\n\n");
2921             push(@implContent, "EncodedJSValue ${className}::nameGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName propertyName)\n");
2922             push(@implContent, "{\n");
2923             push(@implContent, "    auto* thisObject = jsCast<$className*>(slotBase);\n");
2924             push(@implContent, "    return JSValue::encode(toJS(exec, thisObject->globalObject(), thisObject->impl().namedItem(propertyNameToAtomicString(propertyName))));\n");
2925             push(@implContent, "}\n\n");
2926         }
2927     }
2928
2929     if ((!$hasParent && !GetCustomIsReachable($interface)) || GetGenerateIsReachable($interface) || $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
2930         if (GetGenerateIsReachable($interface)) {
2931             push(@implContent, "static inline bool isObservable(JS${interfaceName}* js${interfaceName})\n");
2932             push(@implContent, "{\n");
2933             push(@implContent, "    if (js${interfaceName}->hasCustomProperties())\n");
2934             push(@implContent, "        return true;\n");
2935             if ($eventTarget) {
2936                 push(@implContent, "    if (js${interfaceName}->impl().hasEventListeners())\n");
2937                 push(@implContent, "        return true;\n");
2938             }
2939             push(@implContent, "    return false;\n");
2940             push(@implContent, "}\n\n");
2941         }
2942
2943         push(@implContent, "bool JS${interfaceName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)\n");
2944         push(@implContent, "{\n");
2945         # All ActiveDOMObjects implement hasPendingActivity(), but not all of them
2946         # increment their C++ reference counts when hasPendingActivity() becomes
2947         # true. As a result, ActiveDOMObjects can be prematurely destroyed before
2948         # their pending activities complete. To wallpaper over this bug, JavaScript
2949         # wrappers unconditionally keep ActiveDOMObjects with pending activity alive.
2950         # FIXME: Fix this lifetime issue in the DOM, and move this hasPendingActivity
2951         # check below the isObservable check.
2952         my $emittedJSCast = 0;
2953         if ($codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
2954             push(@implContent, "    auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
2955             $emittedJSCast = 1;
2956             push(@implContent, "    if (js${interfaceName}->impl().hasPendingActivity())\n");
2957             push(@implContent, "        return true;\n");
2958         }
2959         if ($codeGenerator->InheritsExtendedAttribute($interface, "EventTarget")) {
2960             if (!$emittedJSCast) {
2961                 push(@implContent, "    auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
2962                 $emittedJSCast = 1;
2963             }
2964             push(@implContent, "    if (js${interfaceName}->impl().isFiringEventListeners())\n");
2965             push(@implContent, "        return true;\n");
2966         }
2967         if ($codeGenerator->InheritsInterface($interface, "Node")) {
2968             if (!$emittedJSCast) {
2969                 push(@implContent, "    auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
2970                 $emittedJSCast = 1;
2971             }
2972             push(@implContent, "    if (JSNodeOwner::isReachableFromOpaqueRoots(handle, 0, visitor))\n");
2973             push(@implContent, "        return true;\n");
2974         }
2975         if (GetGenerateIsReachable($interface)) {
2976             if (!$emittedJSCast) {
2977                 push(@implContent, "    auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
2978                 $emittedJSCast = 1;
2979             }
2980             push(@implContent, "    if (!isObservable(js${interfaceName}))\n");
2981             push(@implContent, "        return false;\n");
2982