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