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