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