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