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