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