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