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