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