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