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