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