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