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