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