[WebIDL] Overloaded functions unnecessarily duplicate argument checks
[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->globalObject()");
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->globalObject()", 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 = 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");
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 = 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");
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     if ($codeGenerator->IsEnumType($argument->type)) {
842         my $className = GetEnumerationClassName($argument->type, $interface);
843         return "throwArgumentMustBeEnumError(state, scope, ${argumentIndex}, \"${name}\", \"${visibleInterfaceName}\", ${quotedFunctionName}, expectedEnumerationValues<${className}>());";
844     }
845
846     return undef;
847 }
848
849 sub GetArgumentExceptionThrower
850 {
851     my ($interface, $argument, $argumentIndex, $quotedFunctionName) = @_;
852
853     my $functionCall = GetArgumentExceptionFunction($interface, $argument, $argumentIndex, $quotedFunctionName);
854     return "[](JSC::ExecState& state, JSC::ThrowScope& scope) { " . $functionCall . " }" if $functionCall;
855 }
856
857 sub GetAttributeExceptionFunction
858 {
859     my ($interface, $attribute) = @_;
860     
861     my $name = $attribute->name;
862     my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
863     my $typeName = $attribute->type->name;
864
865     if ($codeGenerator->IsWrapperType($attribute->type) || $codeGenerator->IsTypedArrayType($attribute->type)) {
866         return "throwAttributeTypeError(state, scope, \"${visibleInterfaceName}\", \"${name}\", \"${typeName}\");";
867     }
868 }
869
870 sub GetAttributeExceptionThrower
871 {
872     my ($interface, $attribute) = @_;
873
874     my $functionCall = GetAttributeExceptionFunction($interface, $attribute);
875     return "[](JSC::ExecState& state, JSC::ThrowScope& scope) { " . $functionCall . " }" if $functionCall;
876
877 }
878
879 sub PassArgumentExpression
880 {
881     my ($name, $context) = @_;
882
883     my $type = $context->type;
884
885     return "WTFMove(${name})" if $type->isNullable;
886     
887     if ($codeGenerator->IsTypedArrayType($type)) {
888         return "*${name}" if $type->name eq "ArrayBuffer";
889         return "${name}.releaseNonNull()";
890     }
891
892     return "${name}.releaseNonNull()" if $codeGenerator->IsCallbackInterface($type) || $codeGenerator->IsCallbackFunction($type);
893     return "*${name}" if $codeGenerator->IsWrapperType($type);
894     return "WTFMove(${name})";
895 }
896
897 sub GetAttributeGetterName
898 {
899     my ($interface, $className, $attribute) = @_;
900
901     return $codeGenerator->WK_lcfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->name) if $attribute->isStatic;
902     return GetJSBuiltinFunctionName($className, $attribute) if IsJSBuiltin($interface, $attribute);
903     return "js" . $interface->type->name . $codeGenerator->WK_ucfirst($attribute->name) . ($codeGenerator->IsConstructorType($attribute->type) ? "Constructor" : "");
904 }
905
906 sub GetAttributeSetterName
907 {
908     my ($interface, $className, $attribute) = @_;
909
910     return "set" . $codeGenerator->WK_ucfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->name) if $attribute->isStatic;
911     return "set" . $codeGenerator->WK_ucfirst(GetJSBuiltinFunctionName($className, $attribute)) if IsJSBuiltin($interface, $attribute);
912     return "setJS" . $interface->type->name . $codeGenerator->WK_ucfirst($attribute->name) . ($codeGenerator->IsConstructorType($attribute->type) ? "Constructor" : "");
913 }
914
915 sub GetFunctionName
916 {
917     my ($interface, $className, $function) = @_;
918
919     return GetJSBuiltinFunctionName($className, $function) if IsJSBuiltin($interface, $function);
920
921     my $functionName = $function->name;
922     $functionName = "SymbolIterator" if $functionName eq "[Symbol.Iterator]";
923
924     my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
925     return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($functionName);
926 }
927
928 sub GetSpecialAccessorFunctionForType
929 {
930     my $interface = shift;
931     my $special = shift;
932     my $firstParameterType = shift;
933     my $numberOfParameters = shift;
934
935     foreach my $function (@{$interface->functions}, @{$interface->anonymousFunctions}) {
936         my $specials = $function->specials;
937         my $specialExists = grep { $_ eq $special } @$specials;
938         my $arguments = $function->arguments;
939         if ($specialExists and scalar(@$arguments) == $numberOfParameters and $arguments->[0]->type->name eq $firstParameterType) {
940             return $function;
941         }
942     }
943
944     return 0;
945 }
946
947 sub HasComplexGetOwnProperty
948 {
949     my $interface = shift;
950     return $interface->extendedAttributes->{CheckSecurity}
951         || IsDOMGlobalObject($interface)
952         || InstanceOverridesGetOwnPropertySlot($interface);
953 }
954
955 sub IsGlobalOrPrimaryGlobalInterface
956 {
957     my $interface = shift;
958
959     return $interface->extendedAttributes->{Global} || $interface->extendedAttributes->{PrimaryGlobal};
960 }
961
962 sub InterfaceRequiresAttributesOnInstance
963 {
964     my $interface = shift;
965     my $interfaceName = $interface->type->name;
966
967     # FIXME: All these return 1 if ... should ideally be removed.
968     # Some of them are unavoidable due to DOM weirdness, in which case we should
969     # add an IDL attribute for them.
970
971     # FIXME: We should be able to drop this once <rdar://problem/24466097> is fixed.
972     return 1 if $interface->isException;
973
974     return 1 if IsGlobalOrPrimaryGlobalInterface($interface);
975
976     return 0;
977 }
978
979 sub AttributeShouldBeOnInstance
980 {
981     my $interface = shift;
982     my $attribute = shift;
983
984     return 1 if InterfaceRequiresAttributesOnInstance($interface);
985     return 1 if $codeGenerator->IsConstructorType($attribute->type);
986
987     # [Unforgeable] attributes should be on the instance.
988     # https://heycam.github.io/webidl/#Unforgeable
989     return 1 if IsUnforgeable($interface, $attribute);
990
991     if ($interface->extendedAttributes->{CheckSecurity}) {
992         return 0 if $attribute->extendedAttributes->{DoNotCheckSecurity};
993         return 0 if $attribute->extendedAttributes->{DoNotCheckSecurityOnGetter};
994         return 1;
995     }
996
997     return 0;
998 }
999
1000 sub NeedsRuntimeCheck
1001 {
1002     my $interface = shift;
1003     return $interface->extendedAttributes->{EnabledAtRuntime}
1004         || $interface->extendedAttributes->{EnabledForWorld};
1005 }
1006
1007 sub NeedsSettingsCheckForPrototypeProperty
1008 {
1009     my $interface = shift;
1010
1011     foreach my $function (@{$interface->functions}) {
1012         next if OperationShouldBeOnInstance($interface, $function);
1013
1014         return 1 if $function->extendedAttributes->{EnabledBySetting};
1015     }
1016
1017     foreach my $attribute (@{$interface->attributes}) {
1018         next if AttributeShouldBeOnInstance($interface, $attribute);
1019         return 1 if $attribute->extendedAttributes->{EnabledBySetting};
1020     }
1021
1022     return 0;
1023 }
1024
1025 # https://heycam.github.io/webidl/#es-operations
1026 sub OperationShouldBeOnInstance
1027 {
1028     my $interface = shift;
1029     my $function = shift;
1030
1031     return 1 if IsGlobalOrPrimaryGlobalInterface($interface);
1032
1033     # FIXME: The bindings generator does not support putting runtime-enabled operations on the instance yet (except for global objects).
1034     return 0 if NeedsRuntimeCheck($function);
1035
1036     # [Unforgeable] operations should be on the instance. https://heycam.github.io/webidl/#Unforgeable
1037     return 1 if IsUnforgeable($interface, $function);
1038
1039     return 0;
1040 }
1041
1042 sub GetJSCAttributesForAttribute
1043 {
1044     my $interface = shift;
1045     my $attribute = shift;
1046
1047     my @specials = ();
1048     push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute);
1049
1050     # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable.
1051     my $isGlobalConstructor = $codeGenerator->IsConstructorType($attribute->type);
1052     push(@specials, "DontEnum") if ($attribute->extendedAttributes->{NotEnumerable} || $isGlobalConstructor);
1053     push(@specials, "ReadOnly") if IsReadonly($attribute);
1054     push(@specials, "CustomAccessor") unless $isGlobalConstructor or IsJSBuiltin($interface, $attribute);
1055     push(@specials, "DOMJITAttribute") if $attribute->extendedAttributes->{"DOMJIT"};
1056     push(@specials, "Accessor | Builtin") if  IsJSBuiltin($interface, $attribute);
1057     return (@specials > 0) ? join(" | ", @specials) : "0";
1058 }
1059
1060 sub GetIndexedGetterFunction
1061 {
1062     my $interface = shift;
1063     return GetSpecialAccessorFunctionForType($interface, "getter", "unsigned long", 1);
1064 }
1065
1066 sub GetIndexedSetterFunction
1067 {
1068     my $interface = shift;
1069     return GetSpecialAccessorFunctionForType($interface, "setter", "unsigned long", 2);
1070 }
1071
1072 sub GetNamedGetterFunction
1073 {
1074     my $interface = shift;
1075     return GetSpecialAccessorFunctionForType($interface, "getter", "DOMString", 1);
1076 }
1077
1078 sub GetNamedSetterFunction
1079 {
1080     my $interface = shift;
1081     return GetSpecialAccessorFunctionForType($interface, "setter", "DOMString", 2);
1082 }
1083
1084 sub GetNamedDeleterFunction
1085 {
1086     my $interface = shift;
1087     return GetSpecialAccessorFunctionForType($interface, "deleter", "DOMString", 1);
1088 }
1089
1090 sub InstanceFunctionCount
1091 {
1092     my $interface = shift;
1093     my $count = 0;
1094
1095     foreach my $function (@{$interface->functions}) {
1096         $count++ if OperationShouldBeOnInstance($interface, $function);
1097     }
1098
1099     return $count;
1100 }
1101
1102 sub PrototypeFunctionCount
1103 {
1104     my $interface = shift;
1105     my $count = 0;
1106
1107     foreach my $function (@{$interface->functions}) {
1108         $count++ if !$function->isStatic && !OperationShouldBeOnInstance($interface, $function);
1109     }
1110
1111     $count += scalar @{$interface->iterable->functions} if $interface->iterable;
1112     $count += scalar @{$interface->mapLike->functions} if $interface->mapLike;
1113     $count += scalar @{$interface->serializable->functions} if $interface->serializable;
1114
1115     return $count;
1116 }
1117
1118 sub InstancePropertyCount
1119 {
1120     my $interface = shift;
1121     my $count = 0;
1122     foreach my $attribute (@{$interface->attributes}) {
1123         $count++ if AttributeShouldBeOnInstance($interface, $attribute);
1124     }
1125     $count += InstanceFunctionCount($interface);
1126     return $count;
1127 }
1128
1129 sub PrototypePropertyCount
1130 {
1131     my $interface = shift;
1132     my $count = 0;
1133     foreach my $attribute (@{$interface->attributes}) {
1134         $count++ if !AttributeShouldBeOnInstance($interface, $attribute);
1135     }
1136     $count += PrototypeFunctionCount($interface);
1137     $count++ if NeedsConstructorProperty($interface);
1138     return $count;
1139 }
1140
1141 sub InstanceOverridesGetOwnPropertySlot
1142 {
1143     my $interface = shift;
1144     return $interface->extendedAttributes->{CustomGetOwnPropertySlot}
1145         || $interface->extendedAttributes->{CustomNamedGetter}
1146         || $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}
1147         || GetIndexedGetterFunction($interface)
1148         || GetNamedGetterFunction($interface);
1149 }
1150
1151 sub InstanceOverridesPut
1152 {
1153     my $interface = shift;
1154     return $interface->extendedAttributes->{CustomNamedSetter}
1155         || $interface->extendedAttributes->{CustomIndexedSetter}
1156         || GetIndexedSetterFunction($interface)
1157         || GetNamedSetterFunction($interface);
1158 }
1159
1160 sub PrototypeHasStaticPropertyTable
1161 {
1162     my $interface = shift;
1163     my $numConstants = @{$interface->constants};
1164     return $numConstants > 0 || PrototypePropertyCount($interface) > 0;
1165 }
1166
1167 sub InstanceOverridesPutImplementation
1168 {
1169     my $interface = shift;
1170     return $interface->extendedAttributes->{CustomNamedSetter}
1171         || $interface->extendedAttributes->{CustomIndexedSetter};
1172 }
1173
1174 sub InstanceOverridesPutDeclaration
1175 {
1176     my $interface = shift;
1177     return $interface->extendedAttributes->{CustomPutFunction}
1178         || $interface->extendedAttributes->{CustomNamedSetter}
1179         || $interface->extendedAttributes->{CustomIndexedSetter};
1180 }
1181
1182 sub InstanceNeedsVisitChildren
1183 {
1184     my $interface = shift;
1185     return $interface->extendedAttributes->{JSCustomMarkFunction}
1186         || $codeGenerator->InheritsInterface($interface, "EventTarget")
1187         || $interface->type->name eq "EventTarget"
1188         || $interface->extendedAttributes->{ReportExtraMemoryCost}
1189         || IsJSBuiltinConstructor($interface)
1190 }
1191
1192 sub InstanceNeedsEstimatedSize
1193 {
1194     my $interface = shift;
1195     return $interface->extendedAttributes->{ReportExtraMemoryCost};
1196 }
1197
1198 sub GetImplClassName
1199 {
1200     my $interface = shift;
1201
1202     return $interface->type->name;
1203 }
1204
1205 sub IsClassNameWordBoundary
1206 {
1207     my ($name, $i) = @_;
1208
1209     # Interpret negative numbers as distance from end of string, just as the substr function does.
1210     $i += length($name) if $i < 0;
1211
1212     return 0 if $i < 0;
1213     return 1 if $i == 0;
1214     return 1 if $i == length($name);
1215     return 0 if $i > length($name);
1216
1217     my $checkString = substr($name, $i - 1);
1218     return $checkString =~ /^[^A-Z][A-Z]/ || $checkString =~ /^[A-Z][A-Z][^A-Z]/;
1219 }
1220
1221 sub IsPrefixRemovable
1222 {
1223     my ($class, $name, $i) = @_;
1224
1225     return IsClassNameWordBoundary($name, $i)
1226         && (IsClassNameWordBoundary($class, $i) && substr($class, 0, $i) eq substr($name, 0, $i)
1227             || IsClassNameWordBoundary($class, -$i) && substr($class, -$i) eq substr($name, 0, $i));
1228 }
1229
1230 sub GetNestedClassName
1231 {
1232     my ($interface, $name) = @_;
1233
1234     my $class = GetImplClassName($interface);
1235     my $member = $codeGenerator->WK_ucfirst($name);
1236
1237     # Since the enumeration name will be nested in the class name's namespace, remove any words
1238     # that happen to match the start or end of the class name. If an enumeration is named TrackType or
1239     # TextTrackType, and the class is named TextTrack, then we will get a name like TextTrack::Type.
1240     my $memberLength = length($member);
1241     my $longestPrefixLength = 0;
1242     if ($member =~ /^[A-Z]./) {
1243         for (my $i = 2; $i < $memberLength - 1; $i++) {
1244             $longestPrefixLength = $i if IsPrefixRemovable($class, $member, $i);
1245         }
1246     }
1247     $member = substr($member, $longestPrefixLength);
1248
1249     return "${class}::$member";
1250 }
1251
1252 sub GetEnumerationClassName
1253 {
1254     my ($type, $interface) = @_;
1255
1256     assert("Not a type") if ref($type) ne "IDLType";
1257
1258     if ($codeGenerator->HasEnumImplementationNameOverride($type)) {
1259         return $codeGenerator->GetEnumImplementationNameOverride($type);
1260     }
1261
1262     my $name = $type->name;
1263
1264     return $name if $codeGenerator->IsExternalEnumType($type);
1265     return $name unless defined($interface);
1266
1267     return GetNestedClassName($interface, $name);
1268 }
1269
1270 sub GetEnumerationValueName
1271 {
1272     my ($name) = @_;
1273
1274     return "EmptyString" if $name eq "";
1275     $name = join("", map { $codeGenerator->WK_ucfirst($_) } split("-", $name));
1276     $name = "_$name" if $name =~ /^\d/;
1277     return $name;
1278 }
1279
1280 sub GenerateEnumerationHeader
1281 {
1282     my ($object, $enumeration, $className) = @_;
1283  
1284     # - Add default header template and header protection.
1285     push(@headerContentHeader, GenerateHeaderContentHeader($enumeration));
1286  
1287     $headerIncludes{"$className.h"} = 1;
1288     $headerIncludes{"JSDOMConvert.h"} = 1;
1289  
1290     push(@headerContent, "\nnamespace WebCore {\n\n");
1291     push(@headerContent, GenerateEnumerationHeaderContent($enumeration, $className));
1292     push(@headerContent, "} // namespace WebCore\n");
1293      
1294     my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
1295     push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
1296 }
1297  
1298 sub GenerateEnumerationImplementation
1299 {
1300     my ($object, $enumeration, $className) = @_;
1301  
1302     # - Add default header template
1303     push(@implContentHeader, GenerateImplementationContentHeader($enumeration));
1304     
1305     # FIXME: A little ugly to have this be a side effect instead of a return value.
1306     AddToImplIncludes("<runtime/JSString.h>");
1307     AddToImplIncludes("JSDOMConvert.h");
1308  
1309     push(@implContent, "\nusing namespace JSC;\n\n");
1310     push(@implContent, "namespace WebCore {\n\n");
1311     push(@implContent, GenerateEnumerationImplementationContent($enumeration, $className));
1312     push(@implContent, "} // namespace WebCore\n");
1313      
1314     my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
1315     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
1316 }
1317
1318 sub GenerateEnumerationImplementationContent
1319 {
1320     my ($enumeration, $className, $interface, $conditionalString) = @_;
1321     
1322     my $result = "";
1323     $result .= "#if ${conditionalString}\n\n" if $conditionalString;
1324
1325     # FIXME: Change to take VM& instead of ExecState*.
1326     $result .= "template<> JSString* convertEnumerationToJS(ExecState& state, $className enumerationValue)\n";
1327     $result .= "{\n";
1328     # FIXME: Might be nice to make this global be "const", but NeverDestroyed does not currently support that.
1329     # FIXME: Might be nice to make the entire array be NeverDestroyed instead of each value, but not sure what the syntax for that is.
1330     AddToImplIncludes("<wtf/NeverDestroyed.h>");
1331     $result .= "    static NeverDestroyed<const String> values[] = {\n";
1332     foreach my $value (@{$enumeration->values}) {
1333         if ($value eq "") {
1334             $result .= "        emptyString(),\n";
1335         } else {
1336             $result .= "        ASCIILiteral(\"$value\"),\n";
1337         }
1338     }
1339     $result .= "    };\n";
1340     my $index = 0;
1341     foreach my $value (@{$enumeration->values}) {
1342         my $enumerationValueName = GetEnumerationValueName($value);
1343         $result .= "    static_assert(static_cast<size_t>(${className}::$enumerationValueName) == $index, \"${className}::$enumerationValueName is not $index as expected\");\n";
1344         $index++;
1345     }
1346     $result .= "    ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values));\n";
1347     $result .= "    return jsStringWithCache(&state, values[static_cast<size_t>(enumerationValue)]);\n";
1348     $result .= "}\n\n";
1349
1350     # FIXME: Change to take VM& instead of ExecState&.
1351     # FIXME: Consider using toStringOrNull to make exception checking faster.
1352     # FIXME: Consider finding a more efficient way to match against all the strings quickly.
1353     $result .= "template<> std::optional<$className> parseEnumeration<$className>(ExecState& state, JSValue value)\n";
1354     $result .= "{\n";
1355     $result .= "    auto stringValue = value.toWTFString(&state);\n";
1356     foreach my $value (@{$enumeration->values}) {
1357         my $enumerationValueName = GetEnumerationValueName($value);
1358         if ($value eq "") {
1359             $result .= "    if (stringValue.isEmpty())\n";
1360         } else {
1361             $result .= "    if (stringValue == \"$value\")\n";
1362         }
1363         $result .= "        return ${className}::${enumerationValueName};\n";
1364     }
1365     $result .= "    return std::nullopt;\n";
1366     $result .= "}\n\n";
1367
1368     $result .= "template<> const char* expectedEnumerationValues<$className>()\n";
1369     $result .= "{\n";
1370     $result .= "    return \"\\\"" . join ("\\\", \\\"", @{$enumeration->values}) . "\\\"\";\n";
1371     $result .= "}\n\n";
1372
1373     $result .= "#endif\n\n" if $conditionalString;
1374
1375     return $result;
1376 }
1377
1378 sub GenerateEnumerationsImplementationContent
1379 {
1380     my ($interface, $enumerations) = @_;
1381
1382     return "" unless @$enumerations;
1383     
1384     # FIXME: A little ugly to have this be a side effect instead of a return value.
1385     AddToImplIncludes("<runtime/JSString.h>");
1386     AddToImplIncludes("JSDOMConvert.h");
1387
1388     my $result = "";
1389     foreach my $enumeration (@$enumerations) {
1390         my $className = GetEnumerationClassName($enumeration->type, $interface);
1391         my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
1392         $result .= GenerateEnumerationImplementationContent($enumeration, $className, $interface, $conditionalString);
1393     }
1394     return $result;
1395 }
1396
1397 sub GenerateEnumerationHeaderContent
1398 {
1399     my ($enumeration, $className, $conditionalString) = @_;
1400
1401     my $result = "";
1402     $result .= "#if ${conditionalString}\n\n" if $conditionalString;
1403
1404     my $exportMacro = GetExportMacroForJSClass($enumeration);
1405
1406     $result .= "template<> ${exportMacro}JSC::JSString* convertEnumerationToJS(JSC::ExecState&, $className);\n\n";
1407     $result .= "template<> ${exportMacro}std::optional<$className> parseEnumeration<$className>(JSC::ExecState&, JSC::JSValue);\n";
1408     $result .= "template<> ${exportMacro}const char* expectedEnumerationValues<$className>();\n\n";
1409     $result .= "#endif\n\n" if $conditionalString;
1410     
1411     return $result;
1412 }
1413
1414 sub GenerateEnumerationsHeaderContent
1415 {
1416     my ($interface, $enumerations) = @_;
1417
1418     return "" unless @$enumerations;
1419
1420     # FIXME: Could optimize this to only generate the parts of each enumeration that are actually
1421     # used, which would require iterating over everything in the interface.
1422
1423     $headerIncludes{"JSDOMConvert.h"} = 1;
1424
1425     my $result = "";
1426     foreach my $enumeration (@$enumerations) {
1427         my $className = GetEnumerationClassName($enumeration->type, $interface);
1428         my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
1429         $result .= GenerateEnumerationHeaderContent($enumeration, $className, $conditionalString);
1430     }
1431     return $result;
1432 }
1433
1434 sub GetDictionaryClassName
1435 {
1436     my ($type, $interface) = @_;
1437
1438     if ($codeGenerator->HasDictionaryImplementationNameOverride($type)) {
1439         return $codeGenerator->GetDictionaryImplementationNameOverride($type);
1440     }
1441
1442     my $name = $type->name;
1443     return $name if $codeGenerator->IsExternalDictionaryType($type);
1444     return $name unless defined($interface);
1445     return GetNestedClassName($interface, $name);
1446 }
1447
1448 sub GenerateDefaultValue
1449 {
1450     my ($typeScope, $context, $type, $defaultValue) = @_;
1451
1452     if ($codeGenerator->IsStringType($type)) {
1453         my $useAtomicString = $type->extendedAttributes->{AtomicString};
1454         if ($defaultValue eq "null") {
1455             return $useAtomicString ? "nullAtom" : "String()";
1456         } elsif ($defaultValue eq "\"\"") {
1457             return $useAtomicString ? "emptyAtom" : "emptyString()";
1458         } else {
1459             return $useAtomicString ? "AtomicString(${defaultValue}, AtomicString::ConstructFromLiteral)" : "ASCIILiteral(${defaultValue})";
1460         }
1461     }
1462
1463     if ($codeGenerator->IsEnumType($type)) {
1464         # FIXME: Would be nice to report an error if the value does not have quote marks around it.
1465         # FIXME: Would be nice to report an error if the value is not one of the enumeration values.
1466         my $className = GetEnumerationClassName($type, $typeScope);
1467         my $enumerationValueName = GetEnumerationValueName(substr($defaultValue, 1, -1));
1468         return $className . "::" . $enumerationValueName;
1469     }
1470     if ($defaultValue eq "null") {
1471         if ($type->isUnion) {
1472             return "std::nullopt" if $type->isNullable;
1473
1474             my $IDLType = GetIDLType($typeScope, $type);
1475             return "convert<${IDLType}>(state, jsNull());";
1476         }
1477
1478         return "jsNull()" if $type->name eq "any";
1479         return "nullptr" if $codeGenerator->IsWrapperType($type) || $codeGenerator->IsTypedArrayType($type);
1480         return "String()" if $codeGenerator->IsStringType($type);
1481         return "std::nullopt";
1482     }
1483
1484     if ($defaultValue eq "[]") {
1485         my $IDLType = GetIDLType($typeScope, $type);
1486         return "Converter<${IDLType}>::ReturnType{ }";
1487     }
1488
1489     return "jsUndefined()" if $defaultValue eq "undefined";
1490     return "PNaN" if $defaultValue eq "NaN";
1491
1492     return $defaultValue;
1493 }
1494
1495 sub GenerateDictionaryHeaderContent
1496 {
1497     my ($dictionary, $className, $conditionalString) = @_;
1498
1499     my $result = "";
1500     $result .= "#if ${conditionalString}\n\n" if $conditionalString;
1501     $result .= "template<> ${className} convertDictionary<$className>(JSC::ExecState&, JSC::JSValue);\n\n";
1502
1503     if ($dictionary->extendedAttributes->{JSGenerateToJSObject}) {
1504         $result .= "JSC::JSObject* convertDictionaryToJS(JSC::ExecState&, JSDOMGlobalObject&, const ${className}&);\n\n";
1505     }
1506
1507     $result .= "#endif\n\n" if $conditionalString;
1508     return $result;
1509 }
1510
1511 sub GenerateDictionariesHeaderContent
1512 {
1513     my ($typeScope, $allDictionaries) = @_;
1514
1515     return "" unless @$allDictionaries;
1516
1517     $headerIncludes{"JSDOMConvert.h"} = 1;
1518
1519     my $result = "";
1520     foreach my $dictionary (@$allDictionaries) {
1521         $headerIncludes{$typeScope->type->name . ".h"} = 1 if $typeScope;
1522         my $className = GetDictionaryClassName($dictionary->type, $typeScope);
1523         my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
1524         $result .= GenerateDictionaryHeaderContent($dictionary, $className, $conditionalString);
1525     }
1526     return $result;
1527 }
1528
1529 sub GenerateDictionaryImplementationContent
1530 {
1531     my ($dictionary, $className, $interface, $conditionalString) = @_;
1532
1533     my $result = "";
1534
1535     my $name = $dictionary->type->name;
1536     my $typeScope = $interface || $dictionary;
1537
1538     $result .= "#if ${conditionalString}\n\n" if $conditionalString;
1539
1540     # FIXME: A little ugly to have this be a side effect instead of a return value.
1541     AddToImplIncludes("JSDOMConvert.h");
1542
1543     # https://heycam.github.io/webidl/#es-dictionary
1544     $result .= "template<> $className convertDictionary<$className>(ExecState& state, JSValue value)\n";
1545     $result .= "{\n";
1546     $result .= "    VM& vm = state.vm();\n";
1547     $result .= "    auto throwScope = DECLARE_THROW_SCOPE(vm);\n";
1548     $result .= "    bool isNullOrUndefined = value.isUndefinedOrNull();\n";
1549     $result .= "    auto* object = isNullOrUndefined ? nullptr : value.getObject();\n";
1550
1551     # 1. If Type(V) is not Undefined, Null or Object, then throw a TypeError.
1552     $result .= "    if (UNLIKELY(!isNullOrUndefined && !object)) {\n";
1553     $result .= "        throwTypeError(&state, throwScope);\n";
1554     $result .= "        return { };\n";
1555     $result .= "    }\n";
1556
1557     # 2. If V is a native RegExp object, then throw a TypeError.
1558     # FIXME: This RegExp special handling is likely to go away in the specification.
1559     $result .= "    if (UNLIKELY(object && object->type() == RegExpObjectType)) {\n";
1560     $result .= "        throwTypeError(&state, throwScope);\n";
1561     $result .= "        return { };\n";
1562     $result .= "    }\n";
1563
1564     # 3. Let dict be an empty dictionary value of type D; every dictionary member is initially considered to be not present.
1565
1566     # 4. Let dictionaries be a list consisting of D and all of D’s inherited dictionaries, in order from least to most derived.
1567     my @dictionaries;
1568     push(@dictionaries, $dictionary);
1569     my $parentType = $dictionary->parentType;
1570     while (defined($parentType)) {
1571         my $parentDictionary = $codeGenerator->GetDictionaryByType($parentType);
1572         assert("Unable to find definition for dictionary named '" . $parentType->name . "'!") unless defined($parentDictionary);
1573         unshift(@dictionaries, $parentDictionary);
1574         $parentType = $parentDictionary->parentType;
1575     }
1576
1577     my $arguments = "";
1578     my $comma = "";
1579
1580     $result .= "    $className result;\n";
1581
1582     # 5. For each dictionary dictionary in dictionaries, in order:
1583     foreach my $dictionary (@dictionaries) {
1584         # For each dictionary member member declared on dictionary, in lexicographical order:
1585         my @sortedMembers = sort { $a->name cmp $b->name } @{$dictionary->members};
1586         foreach my $member (@sortedMembers) {
1587             $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.
1588
1589             my $type = $member->type;
1590             AddToImplIncludesForIDLType($type);
1591
1592             # 5.1. Let key be the identifier of member.
1593             my $key = $member->name;
1594             my $implementedAsKey = $member->extendedAttributes->{"ImplementedAs"} ? $member->extendedAttributes->{"ImplementedAs"} : $key;
1595
1596             # 5.2. Let value be an ECMAScript value, depending on Type(V):
1597             $result .= "    JSValue ${key}Value = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, \"${key}\"));\n";
1598
1599             my $IDLType = GetIDLType($typeScope, $type);
1600
1601             # 5.3. If value is not undefined, then:
1602             $result .= "    if (!${key}Value.isUndefined()) {\n";
1603
1604             my $nativeValue = JSValueToNative($typeScope, $member, "${key}Value", $member->extendedAttributes->{Conditional}, "&state", "state");
1605             $result .= "        result.$implementedAsKey = $nativeValue;\n";
1606             $result .= "        RETURN_IF_EXCEPTION(throwScope, { });\n";
1607
1608             # Value is undefined.
1609             # 5.4. Otherwise, if value is undefined but the dictionary member has a default value, then:
1610             if (!$member->isRequired && defined $member->default) {
1611                 $result .= "    } else\n";
1612                 $result .= "        result.$implementedAsKey = " . GenerateDefaultValue($typeScope, $member, $member->type, $member->default) . ";\n";
1613             } elsif ($member->isRequired) {
1614                 # 5.5. Otherwise, if value is undefined and the dictionary member is a required dictionary member, then throw a TypeError.
1615                 $result .= "    } else {\n";
1616                 $result .= "        throwRequiredMemberTypeError(state, throwScope, \"". $member->name ."\", \"$name\", \"". $type->name ."\");\n";
1617                 $result .= "        return { };\n";
1618                 $result .= "    }\n";
1619             } else {
1620                 $result .= "    }\n";
1621             }
1622         }
1623     }
1624
1625     $result .= "    return result;\n";
1626     $result .= "}\n\n";
1627
1628     if ($dictionary->extendedAttributes->{JSGenerateToJSObject}) {
1629         $result .= "JSC::JSObject* convertDictionaryToJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const ${className}& dictionary)\n";
1630         $result .= "{\n";
1631         $result .= "    auto& vm = state.vm();\n\n";
1632
1633         # 1. Let O be ! ObjectCreate(%ObjectPrototype%).
1634         $result .= "    auto result = constructEmptyObject(&state);\n\n";
1635
1636         # 2. Let dictionaries be a list consisting of D and all of D’s inherited dictionaries,
1637         #    in order from least to most derived.
1638         #    NOTE: This was done above.
1639
1640         # 3. For each dictionary dictionary in dictionaries, in order:
1641         foreach my $dictionary (@dictionaries) {
1642             # 3.1. For each dictionary member member declared on dictionary, in lexicographical order:
1643             my @sortedMembers = sort { $a->name cmp $b->name } @{$dictionary->members};
1644             foreach my $member (@sortedMembers) {
1645                 my $key = $member->name;
1646                 my $implementedAsKey = $member->extendedAttributes->{"ImplementedAs"} ? $member->extendedAttributes->{"ImplementedAs"} : $key;
1647
1648                 # 1. Let key be the identifier of member.
1649                 # 2. If the dictionary member named key is present in V, then:
1650                     # 1. Let idlValue be the value of member on V.
1651                     # 2. Let value be the result of converting idlValue to an ECMAScript value.
1652                     # 3. Perform ! CreateDataProperty(O, key, value).
1653                 my $IDLType = GetIDLType($typeScope, $member->type);
1654                 if (!$member->isRequired && not defined $member->default) {
1655                     $result .= "    if (!${IDLType}::isNullValue(dictionary.${implementedAsKey})) {\n";
1656                     $result .= "        auto ${key}Value = toJS<$IDLType>(state, globalObject, ${IDLType}::extractValueFromNullable(dictionary.${implementedAsKey}));\n";
1657                     $result .= "        result->putDirect(vm, JSC::Identifier::fromString(&vm, \"${key}\"), ${key}Value);\n";
1658                     $result .= "    }\n";
1659                 } else {
1660                     $result .= "    auto ${key}Value = toJS<$IDLType>(state, globalObject, dictionary.${implementedAsKey});\n";
1661                     $result .= "    result->putDirect(vm, JSC::Identifier::fromString(&vm, \"${key}\"), ${key}Value);\n";
1662                 }
1663             }
1664         }
1665
1666         $result .= "    return result;\n";
1667         $result .= "}\n\n";
1668     }
1669
1670     $result .= "#endif\n\n" if $conditionalString;
1671
1672     return $result;
1673 }
1674
1675 sub GenerateDictionariesImplementationContent
1676 {
1677     my ($typeScope, $allDictionaries) = @_;
1678
1679     my $result = "";
1680     foreach my $dictionary (@$allDictionaries) {
1681         my $className = GetDictionaryClassName($dictionary->type, $typeScope);
1682         my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
1683         $result .= GenerateDictionaryImplementationContent($dictionary, $className, $typeScope, $conditionalString);
1684     }
1685     return $result;
1686 }
1687
1688 sub GetJSTypeForNode
1689 {
1690     my ($interface) = @_;
1691
1692     if ($codeGenerator->InheritsInterface($interface, "Document")) {
1693         return "JSDocumentWrapperType";
1694     }
1695     if ($codeGenerator->InheritsInterface($interface, "DocumentFragment")) {
1696         return "JSDocumentFragmentNodeType";
1697     }
1698     if ($codeGenerator->InheritsInterface($interface, "DocumentType")) {
1699         return "JSDocumentTypeNodeType";
1700     }
1701     if ($codeGenerator->InheritsInterface($interface, "ProcessingInstruction")) {
1702         return "JSProcessingInstructionNodeType";
1703     }
1704     if ($codeGenerator->InheritsInterface($interface, "CDATASection")) {
1705         return "JSCDATASectionNodeType";
1706     }
1707     if ($codeGenerator->InheritsInterface($interface, "Attr")) {
1708         return "JSAttrNodeType";
1709     }
1710     if ($codeGenerator->InheritsInterface($interface, "Comment")) {
1711         return "JSCommentNodeType";
1712     }
1713     if ($codeGenerator->InheritsInterface($interface, "Text")) {
1714         return "JSTextNodeType";
1715     }
1716     if ($codeGenerator->InheritsInterface($interface, "Element")) {
1717         return "JSElementType";
1718     }
1719     return "JSNodeType";
1720 }
1721
1722 sub GenerateHeader
1723 {
1724     my ($object, $interface, $enumerations, $dictionaries) = @_;
1725
1726     my $interfaceName = $interface->type->name;
1727     my $className = "JS$interfaceName";
1728     my %structureFlags = ();
1729
1730     my $hasLegacyParent = $interface->extendedAttributes->{JSLegacyParent};
1731     my $hasRealParent = $interface->parentType;
1732     my $hasParent = $hasLegacyParent || $hasRealParent;
1733     my $parentClassName = GetParentClassName($interface);
1734     my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
1735
1736     # - Add default header template and header protection
1737     push(@headerContentHeader, GenerateHeaderContentHeader($interface));
1738
1739     if ($hasParent) {
1740         $headerIncludes{"$parentClassName.h"} = 1;
1741     } else {
1742         $headerIncludes{"JSDOMWrapper.h"} = 1;
1743         if ($interface->isException) {
1744             $headerIncludes{"<runtime/ErrorPrototype.h>"} = 1;
1745         }
1746     }
1747
1748     $headerIncludes{"$interfaceName.h"} = 1 if $hasParent && $interface->extendedAttributes->{JSGenerateToNativeObject};
1749
1750     $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
1751
1752     my $implType = GetImplClassName($interface);
1753
1754     my $numConstants = @{$interface->constants};
1755     my $numAttributes = @{$interface->attributes};
1756     my $numFunctions = @{$interface->functions};
1757
1758     push(@headerContent, "\nnamespace WebCore {\n\n");
1759
1760     if ($codeGenerator->IsSVGAnimatedType($interface->type)) {
1761         $headerIncludes{"$interfaceName.h"} = 1;
1762     } else {
1763         # Implementation class forward declaration
1764         if (IsDOMGlobalObject($interface)) {
1765             AddClassForwardIfNeeded($interface->type);
1766         }
1767     }
1768
1769     push(@headerContent, "class JSDOMWindowShell;\n\n") if $interfaceName eq "DOMWindow";
1770
1771     my $exportMacro = GetExportMacroForJSClass($interface);
1772
1773     # Class declaration
1774     push(@headerContent, "class $exportMacro$className : public $parentClassName {\n");
1775
1776     # Static create methods
1777     push(@headerContent, "public:\n");
1778     push(@headerContent, "    using Base = $parentClassName;\n");
1779     push(@headerContent, "    using DOMWrapped = $implType;\n") if $hasRealParent;
1780
1781     if ($interfaceName eq "DOMWindow") {
1782         push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* windowShell)\n");
1783         push(@headerContent, "    {\n");
1784         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl), windowShell);\n");
1785         push(@headerContent, "        ptr->finishCreation(vm, windowShell);\n");
1786         push(@headerContent, "        return ptr;\n");
1787         push(@headerContent, "    }\n\n");
1788     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1789         push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSC::JSProxy* proxy)\n");
1790         push(@headerContent, "    {\n");
1791         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl));\n");
1792         push(@headerContent, "        ptr->finishCreation(vm, proxy);\n");
1793         push(@headerContent, "        return ptr;\n");
1794         push(@headerContent, "    }\n\n");
1795     } elsif ($interface->extendedAttributes->{MasqueradesAsUndefined}) {
1796         AddIncludesForImplementationTypeInHeader($implType);
1797         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
1798         push(@headerContent, "    {\n");
1799         push(@headerContent, "        globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(globalObject->vm(), \"Allocated masquerading object\");\n");
1800         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
1801         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1802         push(@headerContent, "        return ptr;\n");
1803         push(@headerContent, "    }\n\n");
1804     } elsif (!NeedsImplementationClass($interface)) {
1805         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject)\n");
1806         push(@headerContent, "    {\n");
1807         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject);\n");
1808         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1809         push(@headerContent, "        return ptr;\n");
1810         push(@headerContent, "    }\n\n");  
1811     } else {
1812         AddIncludesForImplementationTypeInHeader($implType);
1813         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
1814         push(@headerContent, "    {\n");
1815         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
1816         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1817         push(@headerContent, "        return ptr;\n");
1818         push(@headerContent, "    }\n\n");
1819     }
1820
1821     push(@headerContent, "    static const bool needsDestruction = false;\n\n") if IsDOMGlobalObject($interface);
1822
1823     $structureFlags{"JSC::HasStaticPropertyTable"} = 1 if InstancePropertyCount($interface) > 0;
1824
1825     # Prototype
1826     unless (ShouldUseGlobalObjectPrototype($interface)) {
1827         push(@headerContent, "    static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&);\n");
1828         push(@headerContent, "    static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&);\n");
1829     }
1830
1831     # JSValue to implementation type
1832     if (ShouldGenerateToWrapped($hasParent, $interface)) {
1833         # FIXME: Add extended attribute for this.
1834         my @toWrappedArguments = ();
1835         push(@toWrappedArguments, "JSC::VM&");
1836         push(@toWrappedArguments, "JSC::ExecState&") if $interface->type->name eq "XPathNSResolver";
1837         push(@toWrappedArguments, "JSC::JSValue");
1838
1839         my $toWrappedType = $interface->type->name eq "XPathNSResolver" ? "RefPtr<${implType}>" : "${implType}*";
1840
1841         my $export = "";
1842         $export = "WEBCORE_EXPORT " if $interface->extendedAttributes->{ExportToWrappedFunction};
1843         push(@headerContent, "    static ${export}${toWrappedType} toWrapped(" . join(", ", @toWrappedArguments) . ");\n");
1844     }
1845
1846     $headerTrailingIncludes{"${className}Custom.h"} = 1 if $interface->extendedAttributes->{JSCustomHeader};
1847
1848     my $namedGetterFunction = GetNamedGetterFunction($interface);
1849     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
1850
1851     my $hasNamedGetter = $namedGetterFunction
1852         || $interface->extendedAttributes->{CustomNamedGetter};
1853
1854     my $hasComplexGetter = $indexedGetterFunction
1855         || $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}
1856         || $interface->extendedAttributes->{CustomGetOwnPropertySlot}
1857         || $hasNamedGetter;
1858
1859     my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
1860
1861     if ($hasNamedGetter) {
1862         if ($interface->extendedAttributes->{OverrideBuiltins}) {
1863             $structureFlags{"JSC::GetOwnPropertySlotIsImpure"} = 1;
1864         } else {
1865             $structureFlags{"JSC::GetOwnPropertySlotIsImpureForPropertyAbsence"} = 1;
1866         }
1867     }
1868     $structureFlags{"JSC::NewImpurePropertyFiresWatchpoints"} = 1 if $interface->extendedAttributes->{NewImpurePropertyFiresWatchpoints};
1869     $structureFlags{"JSC::IsImmutablePrototypeExoticObject"} = 1 if $interface->extendedAttributes->{IsImmutablePrototypeExoticObject};
1870
1871     # Getters
1872     if ($hasGetter) {
1873         push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
1874         $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
1875
1876         if ($hasComplexGetter) {
1877             push(@headerContent, "    static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n");
1878             $structureFlags{"JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero"} = 1;
1879         }
1880     }
1881
1882     my $overridesPut = InstanceOverridesPutDeclaration($interface);
1883
1884     # Getters
1885     if ($overridesPut) {
1886         push(@headerContent, "    static bool put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1887         push(@headerContent, "    static bool putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n");
1888     }
1889
1890     if (!$hasParent) {
1891         push(@headerContent, "    static void destroy(JSC::JSCell*);\n");
1892     }
1893
1894     # Class info
1895     if ($interfaceName eq "Node") {
1896         push(@headerContent, "\n");
1897         push(@headerContent, "protected:\n");
1898         push(@headerContent, "    static const JSC::ClassInfo s_info;\n");
1899         push(@headerContent, "public:\n");
1900         push(@headerContent, "    static constexpr const JSC::ClassInfo* info() { return &s_info; }\n\n");
1901     } else {
1902         push(@headerContent, "\n");
1903         push(@headerContent, "    DECLARE_INFO;\n\n");
1904     }
1905
1906     # Structure ID
1907     $structureFlags{"JSC::ImplementsHasInstance | JSC::ImplementsDefaultHasInstance"} = 1 if $interfaceName eq "DOMWindow";
1908     push(@headerContent, "    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
1909     push(@headerContent, "    {\n");
1910     if (IsDOMGlobalObject($interface)) {
1911         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info());\n");
1912     } elsif ($codeGenerator->InheritsInterface($interface, "Node")) {
1913         my $type = GetJSTypeForNode($interface);
1914         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType($type), StructureFlags), info());\n");
1915     } elsif ($codeGenerator->InheritsInterface($interface, "Event")) {
1916         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSEventType), StructureFlags), info());\n");
1917     } else {
1918         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n");
1919     }
1920     push(@headerContent, "    }\n\n");
1921
1922     # Custom pushEventHandlerScope function
1923     push(@headerContent, "    JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{JSCustomPushEventHandlerScope};
1924
1925     # LegacyCaller and custom call functions
1926     if (IsCallable($interface)) {
1927         push(@headerContent, "    static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n");
1928         $headerIncludes{"<runtime/CallData.h>"} = 1;
1929         $structureFlags{"JSC::TypeOfShouldCallGetCallData"} = 1;
1930     }
1931
1932     # Custom deleteProperty function
1933     push(@headerContent, "    static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{CustomDeleteProperty};
1934     push(@headerContent, "    static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{CustomDeleteProperty};
1935
1936     # Custom getPropertyNames function exists on DOMWindow
1937     if ($interfaceName eq "DOMWindow") {
1938         push(@headerContent, "    static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1939         push(@headerContent, "    static void getGenericPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1940         push(@headerContent, "    static void getStructurePropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1941         push(@headerContent, "    static uint32_t getEnumerableLength(JSC::ExecState*, JSC::JSObject*);\n");
1942         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
1943     }
1944
1945     # Custom getOwnPropertyNames function
1946     if ($interface->extendedAttributes->{CustomEnumerateProperty} || $indexedGetterFunction || $namedGetterFunction) {
1947         push(@headerContent, "    static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1948         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;       
1949     }
1950
1951     # Custom defineOwnProperty function
1952     push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{JSCustomDefineOwnProperty};
1953
1954     # Custom getPrototype / setPrototype functions.
1955     push (@headerContent, "    static JSC::JSValue getPrototype(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{CustomGetPrototype};
1956
1957     # Custom toStringName function.
1958     push (@headerContent, "    static String toStringName(const JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{CustomToStringName};
1959
1960     # Custom preventExtensions function.
1961     push(@headerContent, "    static bool preventExtensions(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{CustomPreventExtensions};
1962     
1963     $structureFlags{"JSC::MasqueradesAsUndefined"} = 1 if $interface->extendedAttributes->{MasqueradesAsUndefined};
1964
1965     # Constructor object getter
1966     unless ($interface->extendedAttributes->{NoInterfaceObject}) {
1967         push(@headerContent, "    static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);\n");
1968         push(@headerContent, "    static JSC::JSValue getNamedConstructor(JSC::VM&, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{NamedConstructor};
1969     }
1970
1971     # Serializer function.
1972     push(@headerContent, "    static JSC::JSObject* serialize(JSC::ExecState*, JS${interfaceName}* thisObject, JSC::ThrowScope&);\n") if $interface->serializable;
1973
1974     my $numCustomFunctions = 0;
1975     my $numCustomAttributes = 0;
1976
1977     my $hasForwardDeclaringFunctions = 0;
1978     my $hasForwardDeclaringAttributes = 0;
1979
1980     my $hasDOMJITAttributes = 0;
1981
1982     # Attribute and function enums
1983     if ($numAttributes > 0) {
1984         foreach (@{$interface->attributes}) {
1985             my $attribute = $_;
1986             $numCustomAttributes++ if HasCustomGetter($attribute->extendedAttributes);
1987             $numCustomAttributes++ if HasCustomSetter($attribute->extendedAttributes);
1988             if ($attribute->extendedAttributes->{CachedAttribute}) {
1989                 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
1990                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1991                 push(@headerContent, "    mutable JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->name . ";\n");
1992                 $numCachedAttributes++;
1993                 $needsVisitChildren = 1;
1994                 push(@headerContent, "#endif\n") if $conditionalString;
1995             }
1996             $hasDOMJITAttributes = 1 if $attribute->extendedAttributes->{"DOMJIT"};
1997
1998             $hasForwardDeclaringAttributes = 1 if $attribute->extendedAttributes->{ForwardDeclareInHeader};
1999         }
2000     }
2001
2002     # visit function
2003     if ($needsVisitChildren) {
2004         push(@headerContent, "    static void visitChildren(JSCell*, JSC::SlotVisitor&);\n");
2005         push(@headerContent, "    void visitAdditionalChildren(JSC::SlotVisitor&);\n") if $interface->extendedAttributes->{JSCustomMarkFunction};
2006         push(@headerContent, "\n");
2007
2008         if ($interface->extendedAttributes->{JSCustomMarkFunction}) {
2009             # We assume that the logic in visitAdditionalChildren is highly volatile, and during a
2010             # concurrent GC or in between eden GCs something may happen that would lead to this
2011             # logic behaving differently. Since this could mark objects or add opaque roots, this
2012             # means that after any increment of mutator resumption in a concurrent GC and at least
2013             # once during any eden GC we need to re-execute visitAdditionalChildren on any objects
2014             # that we had executed it on before. We do this using the DOM's own MarkingConstraint,
2015             # which will call visitOutputConstraints on all objects in the DOM's own
2016             # outputConstraintSubspace. visitOutputConstraints is the name JSC uses for the method
2017             # that the GC calls to ask an object is it would like to mark anything else after the
2018             # program resumed since the last call to visitChildren or visitOutputConstraints. Since
2019             # this just calls visitAdditionalChildren, you usually don't have to worry about this.
2020             push(@headerContent, "    static void visitOutputConstraints(JSCell*, JSC::SlotVisitor&);\n");
2021             my $subspaceFunc = IsDOMGlobalObject($interface) ? "globalObjectOutputConstraintSubspaceFor" : "outputConstraintSubspaceFor";
2022             push(@headerContent, "    template<typename> static JSC::Subspace* subspaceFor(JSC::VM& vm) { return $subspaceFunc(vm); }\n");
2023         }
2024     }
2025
2026     if (InstanceNeedsEstimatedSize($interface)) {
2027         push(@headerContent, "    static size_t estimatedSize(JSCell*);\n");
2028     }
2029
2030     if ($numCustomAttributes > 0) {
2031         push(@headerContent, "\n    // Custom attributes\n");
2032
2033         foreach my $attribute (@{$interface->attributes}) {
2034             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
2035             if (HasCustomGetter($attribute->extendedAttributes)) {
2036                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
2037                 my $methodName = $codeGenerator->WK_lcfirst($attribute->name);
2038                 push(@headerContent, "    JSC::JSValue " . $methodName . "(JSC::ExecState&) const;\n");
2039                 push(@headerContent, "#endif\n") if $conditionalString;
2040             }
2041             if (HasCustomSetter($attribute->extendedAttributes) && !IsReadonly($attribute)) {
2042                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
2043                 push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->name) . "(JSC::ExecState&, JSC::JSValue);\n");
2044                 push(@headerContent, "#endif\n") if $conditionalString;
2045             }
2046         }
2047     }
2048
2049     foreach my $function (@{$interface->functions}) {
2050         $numCustomFunctions++ if HasCustomMethod($function->extendedAttributes);
2051         $hasForwardDeclaringFunctions = 1 if $function->extendedAttributes->{ForwardDeclareInHeader};
2052     }
2053
2054     if ($numCustomFunctions > 0) {
2055         my $inAppleCopyright = 0;
2056         push(@headerContent, "\n    // Custom functions\n");
2057         foreach my $function (@{$interface->functions}) {
2058             if ($function->extendedAttributes->{AppleCopyright}) {
2059                 if (!$inAppleCopyright) {
2060                     push(@headerContent, $beginAppleCopyrightForHeaderFiles);
2061                     $inAppleCopyright = 1;
2062                 }
2063             } elsif ($inAppleCopyright) {
2064                 push(@headerContent, $endAppleCopyright);
2065                 $inAppleCopyright = 0;
2066             }
2067             next unless HasCustomMethod($function->extendedAttributes);
2068             next if $function->{overloads} && $function->{overloadIndex} != 1;
2069             my $conditionalString = $codeGenerator->GenerateConditionalString($function);
2070             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
2071             my $functionImplementationName = $function->extendedAttributes->{ImplementedAs} || $codeGenerator->WK_lcfirst($function->name);
2072             push(@headerContent, "    " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState&);\n");
2073             push(@headerContent, "#endif\n") if $conditionalString;
2074         }
2075         push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
2076     }
2077
2078     if (NeedsImplementationClass($interface)) {
2079         if ($hasParent) {
2080             push(@headerContent, "    $interfaceName& wrapped() const\n");
2081             push(@headerContent, "    {\n");
2082             push(@headerContent, "        return static_cast<$interfaceName&>(Base::wrapped());\n");
2083             push(@headerContent, "    }\n");
2084         }
2085     }
2086
2087     # structure flags
2088     if (%structureFlags) {
2089         push(@headerContent, "public:\n");
2090         push(@headerContent, "    static const unsigned StructureFlags = ");
2091         foreach my $structureFlag (sort (keys %structureFlags)) {
2092             push(@headerContent, $structureFlag . " | ");
2093         }
2094         push(@headerContent, "Base::StructureFlags;\n");
2095     }
2096
2097     push(@headerContent, "protected:\n");
2098
2099     # Constructor
2100     if ($interfaceName eq "DOMWindow") {
2101         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&, JSDOMWindowShell*);\n");
2102     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
2103         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&);\n");
2104     } elsif (!NeedsImplementationClass($interface)) {
2105         push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject&);\n\n");
2106      } else {
2107         push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject&, Ref<$implType>&&);\n\n");
2108     }
2109
2110     if ($interfaceName eq "DOMWindow") {
2111         push(@headerContent, "    void finishCreation(JSC::VM&, JSDOMWindowShell*);\n");
2112     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
2113         push(@headerContent, "    void finishCreation(JSC::VM&, JSC::JSProxy*);\n");
2114     } else {
2115         push(@headerContent, "    void finishCreation(JSC::VM&);\n");
2116     }
2117
2118     if ($interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}) {
2119         push(@headerContent, "    bool getOwnPropertySlotDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
2120     }
2121
2122     if ($interface->extendedAttributes->{CustomNamedGetter}) {
2123         push(@headerContent, "    bool nameGetter(JSC::ExecState*, JSC::PropertyName, JSC::JSValue&);\n");
2124     }
2125
2126     if ($interface->extendedAttributes->{CustomNamedSetter}) {
2127         push(@headerContent, "    bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&, bool& putResult);\n");
2128     }
2129
2130     if ($interface->extendedAttributes->{CustomIndexedSetter}) {
2131         push(@headerContent, "    void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
2132     }
2133
2134     push(@headerContent, "};\n\n");
2135
2136     if (ShouldGenerateWrapperOwnerCode($hasParent, $interface)) {
2137         if ($interfaceName ne "Node" && $codeGenerator->InheritsInterface($interface, "Node")) {
2138             $headerIncludes{"JSNode.h"} = 1;
2139             push(@headerContent, "class JS${interfaceName}Owner : public JSNodeOwner {\n");
2140         } else {
2141             push(@headerContent, "class JS${interfaceName}Owner : public JSC::WeakHandleOwner {\n");
2142         }
2143         $headerIncludes{"<wtf/NeverDestroyed.h>"} = 1;
2144         push(@headerContent, "public:\n");
2145         push(@headerContent, "    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
2146         push(@headerContent, "    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
2147         push(@headerContent, "};\n");
2148         push(@headerContent, "\n");
2149         push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, $implType*)\n");
2150         push(@headerContent, "{\n");
2151         push(@headerContent, "    static NeverDestroyed<JS${interfaceName}Owner> owner;\n");
2152         push(@headerContent, "    return &owner.get();\n");
2153         push(@headerContent, "}\n");
2154         push(@headerContent, "\n");
2155         push(@headerContent, "inline void* wrapperKey($implType* wrappableObject)\n");
2156         push(@headerContent, "{\n");
2157         push(@headerContent, "    return wrappableObject;\n");
2158         push(@headerContent, "}\n");
2159         push(@headerContent, "\n");
2160     }
2161     if (ShouldGenerateToJSDeclaration($hasParent, $interface)) {
2162         # Node and NodeList have custom inline implementations which thus cannot be exported.
2163         # FIXME: The special case for Node and NodeList should probably be implemented via an IDL attribute.
2164         if ($implType eq "Node" or $implType eq "NodeList") {
2165             push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType&);\n");
2166         } else {
2167             push(@headerContent, $exportMacro."JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType&);\n");
2168         }
2169         push(@headerContent, "inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, $implType* impl) { return impl ? toJS(state, globalObject, *impl) : JSC::jsNull(); }\n");
2170
2171         push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, Ref<$implType>&&);\n");
2172         push(@headerContent, "inline JSC::JSValue toJSNewlyCreated(JSC::ExecState* state, JSDOMGlobalObject* globalObject, RefPtr<$implType>&& impl) { return impl ? toJSNewlyCreated(state, globalObject, impl.releaseNonNull()) : JSC::jsNull(); }\n");
2173    }
2174
2175     push(@headerContent, "\n");
2176
2177     GeneratePrototypeDeclaration(\@headerContent, $className, $interface) if HeaderNeedsPrototypeDeclaration($interface);
2178
2179     if ($hasForwardDeclaringFunctions) {
2180         my $inAppleCopyright = 0;
2181         push(@headerContent,"// Functions\n\n");
2182         foreach my $function (@{$interface->functions}) {
2183             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2184             next unless $function->extendedAttributes->{ForwardDeclareInHeader};
2185
2186             if ($function->extendedAttributes->{AppleCopyright}) {
2187                 if (!$inAppleCopyright) {
2188                     push(@headerContent, $beginAppleCopyrightForHeaderFiles);
2189                     $inAppleCopyright = 1;
2190                 }
2191             } elsif ($inAppleCopyright) {
2192                 push(@headerContent, $endAppleCopyright);
2193                 $inAppleCopyright = 0;
2194             }
2195
2196             my $conditionalAttribute = GetConditionalForFunctionConsideringOverloads($function);
2197             my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
2198             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
2199             my $functionName = GetFunctionName($interface, $className, $function);
2200             push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
2201             push(@headerContent, "#endif\n") if $conditionalString;
2202         }
2203
2204         push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
2205         push(@headerContent,"\n");
2206     }
2207
2208     if ($hasForwardDeclaringAttributes) {
2209         push(@headerContent,"// Attributes\n\n");
2210         foreach my $attribute (@{$interface->attributes}) {
2211             next unless $attribute->extendedAttributes->{ForwardDeclareInHeader};
2212
2213             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
2214             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
2215             my $getter = GetAttributeGetterName($interface, $className, $attribute);
2216             push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
2217             if (!IsReadonly($attribute)) {
2218                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
2219                 push(@headerContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
2220             }
2221             push(@headerContent, "#endif\n") if $conditionalString;
2222         }
2223     }
2224
2225     # CheckSubClass Patchpoint function.
2226     if ($interface->extendedAttributes->{DOMJIT}) {
2227         $headerIncludes{"<domjit/DOMJITPatchpoint.h>"} = 1;
2228         push(@headerContent, "#if ENABLE(JIT)\n");
2229         push(@headerContent, "RefPtr<JSC::DOMJIT::Patchpoint> checkSubClassPatchpointFor${className}();\n");
2230         push(@headerContent, "#endif\n");
2231     }
2232
2233     if ($hasDOMJITAttributes) {
2234         $headerIncludes{"<domjit/DOMJITGetterSetter.h>"} = 1;
2235         push(@headerContent,"// DOMJIT emitters for attributes\n\n");
2236         foreach my $attribute (@{$interface->attributes}) {
2237             next unless $attribute->extendedAttributes->{"DOMJIT"};
2238             assert("Only DOMJIT=Getter is supported for attributes") unless $codeGenerator->ExtendedAttributeContains($attribute->extendedAttributes->{DOMJIT}, "Getter");
2239
2240             my $interfaceName = $interface->type->name;
2241             my $className = $interfaceName . $codeGenerator->WK_ucfirst($attribute->name);
2242             my $domJITClassName = $className . "DOMJIT";
2243
2244             push(@headerContent, "JSC::DOMJIT::GetterSetter* domJITGetterSetterFor$className(void);\n");
2245
2246             push(@headerContent, "class ${domJITClassName} : public JSC::DOMJIT::GetterSetter {\n");
2247             push(@headerContent, "public:\n");
2248             push(@headerContent, "    ${domJITClassName}();\n");
2249             push(@headerContent, "#if ENABLE(JIT)\n");
2250             push(@headerContent, "    Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> callDOMGetter() override;\n");
2251             push(@headerContent, "#endif\n");
2252             push(@headerContent, "};\n\n");
2253         }
2254     }
2255
2256     if (HasCustomConstructor($interface)) {
2257         push(@headerContent, "// Custom constructor\n");
2258         push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState&);\n\n");
2259     }
2260
2261     if (NeedsImplementationClass($interface)) {
2262         my $toWrappedType = $interface->type->name eq "XPathNSResolver" ? "RefPtr<${implType}>" : "${implType}*";
2263     
2264         push(@headerContent, "template<> struct JSDOMWrapperConverterTraits<${implType}> {\n");
2265         push(@headerContent, "    using WrapperClass = ${className};\n");
2266         push(@headerContent, "    using ToWrappedReturnType = ${toWrappedType};\n");
2267         push(@headerContent, "};\n");
2268     }
2269
2270     push(@headerContent, GenerateEnumerationsHeaderContent($interface, $enumerations));
2271     push(@headerContent, GenerateDictionariesHeaderContent($interface, $dictionaries));
2272
2273     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
2274     push(@headerContent, "\n} // namespace WebCore\n");
2275     push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2276
2277     if ($interface->extendedAttributes->{AppleCopyright}) {
2278         push(@headerContent, "\n");
2279         push(@headerContent, split("\r", $endAppleCopyright));
2280     }
2281
2282     # - Generate dependencies.
2283     if ($writeDependencies) {
2284         my @ancestors;
2285         $codeGenerator->ForAllParents($interface, sub {
2286             my $currentInterface = shift;
2287             push(@ancestors, $currentInterface->type->name);
2288         }, 0);
2289         for my $dictionary (@$dictionaries) {
2290             my $parentType = $dictionary->parentType;
2291             while (defined($parentType)) {
2292                 push(@ancestors, $parentType->name) if $codeGenerator->IsExternalDictionaryType($parentType);
2293                 my $parentDictionary = $codeGenerator->GetDictionaryByType($parentType);
2294                 assert("Unable to find definition for dictionary named '" . $parentType->name . "'!") unless defined($parentDictionary);
2295                 $parentType = $parentDictionary->parentType;
2296             }
2297         }
2298         push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestors), "\n");
2299         push(@depsContent, map { "$_.idl :\n" } @ancestors);
2300     }
2301 }
2302
2303 sub GeneratePropertiesHashTable
2304 {
2305     my ($object, $interface, $isInstance, $hashKeys, $hashSpecials, $hashValue1, $hashValue2, $conditionals, $runtimeEnabledFunctions, $runtimeEnabledAttributes, $settingsEnabledFunctions, $settingsEnabledAttributes) = @_;
2306
2307     # FIXME: These should be functions on $interface.
2308     my $interfaceName = $interface->type->name;
2309     my $className = "JS$interfaceName";
2310     
2311     # - Add all properties in a hashtable definition
2312     my $propertyCount = $isInstance ? InstancePropertyCount($interface) : PrototypePropertyCount($interface);
2313
2314     if (!$isInstance && NeedsConstructorProperty($interface)) {
2315         die if !$propertyCount;
2316         push(@$hashKeys, "constructor");
2317         my $getter = "js" . $interfaceName . "Constructor";
2318         push(@$hashValue1, $getter);
2319
2320         my $setter = "setJS" . $interfaceName . "Constructor";
2321         push(@$hashValue2, $setter);
2322         push(@$hashSpecials, "DontEnum");
2323     }
2324
2325     return 0 if !$propertyCount;
2326
2327     my @attributes = @{$interface->attributes};
2328     push(@attributes, @{$interface->mapLike->attributes}) if $interface->mapLike;
2329
2330     foreach my $attribute (@attributes) {
2331         next if ($attribute->isStatic);
2332         next if AttributeShouldBeOnInstance($interface, $attribute) != $isInstance;
2333
2334         # Global objects add RuntimeEnabled attributes after creation so do not add them to the static table.
2335         if ($isInstance && NeedsRuntimeCheck($attribute)) {
2336             $propertyCount -= 1;
2337             next;
2338         }
2339
2340         my $name = $attribute->name;
2341         push(@$hashKeys, $name);
2342
2343         my $special = GetJSCAttributesForAttribute($interface, $attribute);
2344         push(@$hashSpecials, $special);
2345
2346         if ($attribute->extendedAttributes->{"DOMJIT"}) {
2347             push(@$hashValue1, "domJITGetterSetterFor" . $interface->type->name . $codeGenerator->WK_ucfirst($attribute->name));
2348             push(@$hashValue2, "0");
2349         } else {
2350             my $getter = GetAttributeGetterName($interface, $className, $attribute);
2351             push(@$hashValue1, $getter);
2352
2353             if (IsReadonly($attribute)) {
2354                 push(@$hashValue2, "0");
2355             } else {
2356                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
2357                 push(@$hashValue2, $setter);
2358             }
2359         }
2360
2361         my $conditional = $attribute->extendedAttributes->{Conditional};
2362         $conditionals->{$name} = $conditional if $conditional;
2363
2364         if (NeedsRuntimeCheck($attribute)) {
2365             push(@$runtimeEnabledAttributes, $attribute);
2366         }
2367
2368         if ($attribute->extendedAttributes->{EnabledBySetting}) {
2369             push(@$settingsEnabledAttributes, $attribute);
2370         }
2371     }
2372
2373     my @functions = @{$interface->functions};
2374     push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
2375     push(@functions, @{$interface->mapLike->functions}) if $interface->mapLike;
2376     push(@functions, @{$interface->serializable->functions}) if $interface->serializable;
2377     foreach my $function (@functions) {
2378         next if ($function->extendedAttributes->{PrivateIdentifier} and not $function->extendedAttributes->{PublicIdentifier});
2379         next if ($function->isStatic);
2380         next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2381         next if OperationShouldBeOnInstance($interface, $function) != $isInstance;
2382         next if $function->name eq "[Symbol.Iterator]";
2383
2384         # Global objects add RuntimeEnabled operations after creation so do not add them to the static table.
2385         if ($isInstance && NeedsRuntimeCheck($function)) {
2386             $propertyCount -= 1;
2387             next;
2388         }
2389
2390         my $name = $function->name;
2391         push(@$hashKeys, $name);
2392
2393         my $functionName = GetFunctionName($interface, $className, $function);
2394         push(@$hashValue1, $functionName);
2395
2396         my $functionLength = GetFunctionLength($function);
2397
2398         if ($function->extendedAttributes->{DOMJIT}) {
2399             push(@$hashValue2, "&DOMJITSignatureFor" . $interface->type->name . $codeGenerator->WK_ucfirst($function->name));
2400         } else {
2401             push(@$hashValue2, $functionLength);
2402         }
2403
2404         push(@$hashSpecials, ComputeFunctionSpecial($interface, $function));
2405
2406         my $conditional = GetConditionalForFunctionConsideringOverloads($function);
2407         $conditionals->{$name} = $conditional if $conditional;
2408
2409         if (NeedsRuntimeCheck($function)) {
2410             push(@$runtimeEnabledFunctions, $function);
2411         }
2412
2413         if ($function->extendedAttributes->{EnabledBySetting}) {
2414             push(@$settingsEnabledFunctions, $function);
2415         }
2416     }
2417
2418     return $propertyCount;
2419 }
2420
2421 # This computes an effective overload set for a given operation / constructor,
2422 # which represents the allowable invocations.This set is used as input for
2423 # the Web IDL overload resolution algorithm.
2424 # http://heycam.github.io/webidl/#dfn-effective-overload-set
2425 sub ComputeEffectiveOverloadSet
2426 {
2427     my ($overloads) = @_;
2428
2429     my %allSets;
2430     my $addTuple = sub {
2431         my $tuple = shift;
2432         # The Web IDL specification uses a flat set of tuples but we use a hash where the key is the
2433         # number of parameters and the value is the set of tuples for the given number of parameters.
2434         my $length = scalar(@{@$tuple[1]});
2435         if (!exists($allSets{$length})) {
2436             $allSets{$length} = [ $tuple ];
2437         } else {
2438             push(@{$allSets{$length}}, $tuple);
2439         }
2440     };
2441
2442     my $m = LengthOfLongestFunctionParameterList($overloads);
2443     foreach my $overload (@{$overloads}) {
2444         my $n = @{$overload->arguments};
2445         my @t;
2446         my @o;
2447         my $isVariadic = 0;
2448         foreach my $argument (@{$overload->arguments}) {
2449             push(@t, $argument->type);
2450             if ($argument->isOptional) {
2451                 push(@o, "optional");
2452             } elsif ($argument->isVariadic) {
2453                 push(@o, "variadic");
2454                 $isVariadic = 1;
2455             } else {
2456                 push(@o, "required");
2457             }
2458         }
2459         &$addTuple([$overload, [@t], [@o]]);
2460         if ($isVariadic) {
2461             my @newT = @t;
2462             my @newO = @o;
2463             for (my $i = $n; $i < $m; $i++) {
2464                 push(@newT, $t[-1]);
2465                 push(@newO, "variadic");
2466                 &$addTuple([$overload, [@newT], [@newO]]);
2467             }
2468         }
2469         for (my $i = $n - 1; $i >= 0; $i--) {
2470             my $argument = @{$overload->arguments}[$i];
2471             last unless ($argument->isOptional || $argument->isVariadic);
2472             pop(@t);
2473             pop(@o);
2474             &$addTuple([$overload, [@t], [@o]]);
2475         }
2476     }
2477     return %allSets;
2478 }
2479
2480 sub IsIDLTypeDistinguishableWithUnionForOverloadResolution
2481 {
2482     my ($type, $unionSubtypes) = @_;
2483
2484     assert("First type should not be a union") if $type->isUnion;
2485     for my $unionSubType (@$unionSubtypes) {
2486         return 0 unless AreTypesDistinguishableForOverloadResolution($type, $unionSubType);
2487     }
2488     return 1;
2489 }
2490
2491 # Determines if two types are distinguishable in the context of overload resolution,
2492 # according to the Web IDL specification:
2493 # http://heycam.github.io/webidl/#dfn-distinguishable
2494 sub AreTypesDistinguishableForOverloadResolution
2495 {
2496     my ($typeA, $typeB) = @_;
2497
2498     my $isCallbackFunctionOrDictionary = sub {
2499         my $type = shift;
2500         return $codeGenerator->IsCallbackFunction($type) || $codeGenerator->IsDictionaryType($type);
2501     };
2502
2503     # Two types are distinguishable for overload resolution if at most one of the two includes a nullable type.
2504     return 0 if $typeA->isNullable && $typeB->isNullable;
2505
2506     # Union types: typeA and typeB  are distinguishable if:
2507     # - Both types are either a union type or nullable union type, and each member type of the one is
2508     #   distinguishable with each member type of the other.
2509     # - One type is a union type or nullable union type, the other is neither a union type nor a nullable
2510     #   union type, and each member type of the first is distinguishable with the second.
2511     if ($typeA->isUnion && $typeB->isUnion) {
2512         for my $unionASubType (@{$typeA->subtypes}) {
2513             return 0 unless IsIDLTypeDistinguishableWithUnionForOverloadResolution($unionASubType, $typeB->subtypes);
2514         }
2515         return 1;
2516     } elsif ($typeA->isUnion) {
2517         return IsIDLTypeDistinguishableWithUnionForOverloadResolution($typeB, $typeA->subtypes);
2518     } elsif ($typeB->isUnion) {
2519         return IsIDLTypeDistinguishableWithUnionForOverloadResolution($typeA, $typeB->subtypes);
2520     }
2521
2522     return 0 if $typeA->name eq $typeB->name;
2523     return 0 if $typeA->name eq "object" or $typeB->name eq "object";
2524     return 0 if $codeGenerator->IsNumericType($typeA) && $codeGenerator->IsNumericType($typeB);
2525     return 0 if $codeGenerator->IsStringOrEnumType($typeA) && $codeGenerator->IsStringOrEnumType($typeB);
2526     return 0 if $codeGenerator->IsDictionaryType($typeA) && $codeGenerator->IsDictionaryType($typeB);
2527     return 0 if $codeGenerator->IsCallbackInterface($typeA) && $codeGenerator->IsCallbackInterface($typeB);
2528     return 0 if &$isCallbackFunctionOrDictionary($typeA) && &$isCallbackFunctionOrDictionary($typeB);
2529     return 0 if $codeGenerator->IsSequenceOrFrozenArrayType($typeA) && $codeGenerator->IsSequenceOrFrozenArrayType($typeB);
2530     # FIXME: return 0 if $typeA and $typeB are both exception types.
2531     return 1;
2532 }
2533
2534 # If there is more than one entry in an effective overload set that has a given type list length,
2535 # then for those entries there must be an index i such that for each pair of entries the types
2536 # at index i are distinguishable. The lowest such index is termed the distinguishing argument index.
2537 # http://heycam.github.io/webidl/#dfn-distinguishing-argument-index
2538 sub GetDistinguishingArgumentIndex
2539 {
2540     my ($function, $S) = @_;
2541
2542     # FIXME: Consider all the tuples, not just the 2 first ones?
2543     my $firstTupleTypes = @{@{$S}[0]}[1];
2544     my $secondTupleTypes = @{@{$S}[1]}[1];
2545     for (my $index = 0; $index < scalar(@$firstTupleTypes); $index++) {
2546         return $index if AreTypesDistinguishableForOverloadResolution(@{$firstTupleTypes}[$index], @{$secondTupleTypes}[$index]);
2547     }
2548     die "Undistinguishable overloads for operation " . $function->name . " with length: " . scalar(@$firstTupleTypes);
2549 }
2550
2551 sub GetOverloadThatMatches
2552 {
2553     my ($S, $parameterIndex, $matches) = @_;
2554
2555     for my $tuple (@{$S}) {
2556         my $type = @{@{$tuple}[1]}[$parameterIndex];
2557         my $optionality = @{@{$tuple}[2]}[$parameterIndex];
2558         if ($type->isUnion) {
2559             for my $subtype (GetFlattenedMemberTypes($type)) {
2560                 return @{$tuple}[0] if $matches->($subtype, $optionality);
2561             }
2562         } else {
2563             return @{$tuple}[0] if $matches->($type, $optionality);
2564         }
2565     }
2566 }
2567
2568 sub GetOverloadThatMatchesIgnoringUnionSubtypes
2569 {
2570     my ($S, $parameterIndex, $matches) = @_;
2571
2572     for my $tuple (@{$S}) {
2573         my $type = @{@{$tuple}[1]}[$parameterIndex];
2574         my $optionality = @{@{$tuple}[2]}[$parameterIndex];
2575         return @{$tuple}[0] if $matches->($type, $optionality);
2576     }
2577 }
2578
2579 sub GetConditionalForFunctionConsideringOverloads
2580 {
2581     my $function = shift;
2582
2583     return $function->extendedAttributes->{Conditional} unless $function->{overloads};
2584
2585     my %conditions;
2586     foreach my $overload (@{$function->{overloads}}) {
2587         my $conditional = $overload->extendedAttributes->{Conditional};
2588         return unless $conditional;
2589         $conditions{$conditional} = 1;
2590     }
2591     return join("|", keys %conditions);
2592 }
2593
2594 # Implements the overload resolution algorithm, as defined in the Web IDL specification:
2595 # http://heycam.github.io/webidl/#es-overloads
2596 sub GenerateOverloadDispatcher
2597 {
2598     my ($function, $interface, $overloadFunctionPrefix, $functionSignature) = @_;
2599     
2600     my %allSets = ComputeEffectiveOverloadSet($function->{overloads});
2601
2602     my $generateOverloadCallIfNecessary = sub {
2603         my ($overload, $condition, $include) = @_;
2604         return unless $overload;
2605         my $conditionalString = $codeGenerator->GenerateConditionalString($overload);
2606         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2607         push(@implContent, "        if ($condition)\n    ") if $condition;
2608         push(@implContent, "        return ${overloadFunctionPrefix}" . $overload->{overloadIndex} . "(state);\n");
2609         push(@implContent, "#endif\n") if $conditionalString;
2610         AddToImplIncludes($include, $overload->extendedAttributes->{"Conditional"}) if $include;
2611     };
2612     my $isOptionalParameter = sub {
2613         my ($type, $optionality) = @_;
2614         return $optionality eq "optional";
2615     };
2616     my $isDictionaryOrRecordParameter = sub {
2617         my ($type, $optionality) = @_;
2618         return $codeGenerator->IsDictionaryType($type) || $codeGenerator->IsRecordType($type);
2619     };
2620     my $isNullableOrDictionaryOrRecordOrUnionContainingOne = sub {
2621         my ($type, $optionality) = @_;
2622         return 1 if $type->isNullable;
2623         if ($type->isUnion) {
2624             for my $subtype (GetFlattenedMemberTypes($type)) {
2625                 return 1 if $type->isNullable || &$isDictionaryOrRecordParameter($subtype, $optionality);
2626             }
2627             return 0;
2628         } else {
2629             return &$isDictionaryOrRecordParameter($type, $optionality);
2630         }
2631     };
2632     my $isRegExpOrObjectParameter = sub {
2633         my ($type, $optionality) = @_;
2634         return $type->name eq "RegExp" || $type->name eq "object";
2635     };
2636     my $isObjectOrErrorParameter = sub {
2637         my ($type, $optionality) = @_;
2638         return $type->name eq "object" || $type->name eq "Error";
2639     };
2640     my $isObjectOrErrorOrDOMExceptionParameter = sub {
2641         my ($type, $optionality) = @_;
2642         return 1 if &$isObjectOrErrorParameter($type, $optionality);
2643         return $type->name eq "DOMException";
2644     };
2645     my $isObjectOrCallbackFunctionParameter = sub {
2646         my ($type, $optionality) = @_;
2647         return $type->name eq "object" || $codeGenerator->IsCallbackFunction($type);
2648     };
2649     my $isSequenceOrFrozenArrayParameter = sub {
2650         my ($type, $optionality) = @_;
2651         return $codeGenerator->IsSequenceOrFrozenArrayType($type);
2652     };
2653     my $isDictionaryOrRecordOrObjectOrCallbackInterfaceParameter = sub {
2654         my ($type, $optionality) = @_;
2655         return 1 if &$isDictionaryOrRecordParameter($type, $optionality);
2656         return 1 if $type->name eq "object";
2657         return 1 if $codeGenerator->IsCallbackInterface($type) && !$codeGenerator->IsCallbackFunction($type);
2658         return 0;
2659     };
2660     my $isBooleanParameter = sub {
2661         my ($type, $optionality) = @_;
2662         return $type->name eq "boolean";
2663     };
2664     my $isNumericParameter = sub {
2665         my ($type, $optionality) = @_;
2666         return $codeGenerator->IsNumericType($type);
2667     };
2668     my $isStringOrEnumParameter = sub {
2669         my ($type, $optionality) = @_;
2670         return $codeGenerator->IsStringOrEnumType($type);
2671     };
2672     my $isAnyParameter = sub {
2673         my ($type, $optionality) = @_;
2674         return $type->name eq "any";
2675     };
2676
2677     my $maxArgCount = LengthOfLongestFunctionParameterList($function->{overloads});
2678
2679     my $conditionalAttribute = GetConditionalForFunctionConsideringOverloads($function);
2680     my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
2681     push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2682     push(@implContent, "$functionSignature\n");
2683     push(@implContent, <<END);    
2684 {
2685     VM& vm = state->vm();
2686     auto throwScope = DECLARE_THROW_SCOPE(vm);
2687     UNUSED_PARAM(throwScope);
2688     size_t argsCount = std::min<size_t>($maxArgCount, state->argumentCount());
2689 END
2690
2691     for my $length ( sort keys %allSets ) {
2692         push(@implContent, <<END);
2693     if (argsCount == $length) {
2694 END
2695         my $S = $allSets{$length};
2696         if (scalar(@$S) > 1) {
2697             my $d = GetDistinguishingArgumentIndex($function, $S);
2698             push(@implContent, "        JSValue distinguishingArg = state->uncheckedArgument($d);\n");
2699
2700             my $overload = GetOverloadThatMatchesIgnoringUnionSubtypes($S, $d, \&$isOptionalParameter);
2701             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isUndefined()");
2702
2703             $overload = GetOverloadThatMatchesIgnoringUnionSubtypes($S, $d, \&$isNullableOrDictionaryOrRecordOrUnionContainingOne);
2704             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isUndefinedOrNull()");
2705
2706             for my $tuple (@{$S}) {
2707                 my $overload = @{$tuple}[0];
2708                 my $type = @{@{$tuple}[1]}[$d];
2709
2710                 my @subtypes = $type->isUnion ? GetFlattenedMemberTypes($type) : ( $type );
2711                 for my $subtype (@subtypes) {
2712                     if ($codeGenerator->IsWrapperType($subtype) || $codeGenerator->IsTypedArrayType($subtype)) {
2713                         if ($subtype->name eq "DOMWindow") {
2714                             AddToImplIncludes("JSDOMWindowShell.h");
2715                             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && (asObject(distinguishingArg)->inherits(vm, JSDOMWindowShell::info()) || asObject(distinguishingArg)->inherits(vm, JSDOMWindow::info()))");
2716                         } else {
2717                             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->inherits(vm, JS" . $subtype->name . "::info())");
2718                         }
2719                     }
2720                 }
2721             }
2722
2723             $overload = GetOverloadThatMatches($S, $d, \&$isRegExpOrObjectParameter);
2724             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() == RegExpObjectType");
2725
2726             $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrErrorOrDOMExceptionParameter);
2727             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->inherits(vm, JSDOMCoreException::info())");
2728
2729             $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrErrorParameter);
2730             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() == ErrorInstanceType");
2731
2732             $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrCallbackFunctionParameter);
2733             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isFunction()");
2734
2735             # FIXME: Avoid invoking GetMethod(object, Symbol.iterator) again in convert<IDLSequence<T>>(...).
2736             $overload = GetOverloadThatMatches($S, $d, \&$isSequenceOrFrozenArrayParameter);
2737             &$generateOverloadCallIfNecessary($overload, "hasIteratorMethod(*state, distinguishingArg)", "<runtime/IteratorOperations.h>");
2738
2739             $overload = GetOverloadThatMatches($S, $d, \&$isDictionaryOrRecordOrObjectOrCallbackInterfaceParameter);
2740             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() != RegExpObjectType");
2741
2742             my $booleanOverload = GetOverloadThatMatches($S, $d, \&$isBooleanParameter);
2743             &$generateOverloadCallIfNecessary($booleanOverload, "distinguishingArg.isBoolean()");
2744
2745             my $numericOverload = GetOverloadThatMatches($S, $d, \&$isNumericParameter);
2746             &$generateOverloadCallIfNecessary($numericOverload, "distinguishingArg.isNumber()");
2747
2748             # Fallbacks.
2749             $overload = GetOverloadThatMatches($S, $d, \&$isStringOrEnumParameter);
2750             if ($overload) {
2751                 &$generateOverloadCallIfNecessary($overload);
2752             } elsif ($numericOverload) {
2753                 &$generateOverloadCallIfNecessary($numericOverload);
2754             } elsif ($booleanOverload) {
2755                 &$generateOverloadCallIfNecessary($booleanOverload);
2756             } else {
2757                 $overload = GetOverloadThatMatches($S, $d, \&$isAnyParameter);
2758                 &$generateOverloadCallIfNecessary($overload);
2759             }
2760         } else {
2761             # Only 1 overload with this number of parameters.
2762             my $overload = @{@{$S}[0]}[0];
2763             &$generateOverloadCallIfNecessary($overload);
2764         }
2765         push(@implContent, <<END);
2766     }
2767 END
2768     }
2769     my $minArgCount = GetFunctionLength($function);
2770     if ($minArgCount > 0) {
2771         push(@implContent, "    return argsCount < $minArgCount ? throwVMError(state, throwScope, createNotEnoughArgumentsError(state)) : throwVMTypeError(state, throwScope);\n")
2772     } else {
2773         push(@implContent, "    return throwVMTypeError(state, throwScope);\n")
2774     }
2775     push(@implContent, "}\n");
2776     push(@implContent, "#endif\n") if $conditionalString;
2777     push(@implContent, "\n");
2778 }
2779
2780 # As per Web IDL specification, the length of a function Object is its number of mandatory parameters.
2781 sub GetFunctionLength
2782 {
2783     my $function = shift;
2784
2785     my $getOverloadLength = sub {
2786         my $function = shift;
2787
2788         my $length = 0;
2789         foreach my $argument (@{$function->arguments}) {
2790             last if $argument->isOptional || $argument->isVariadic;
2791             $length++;
2792         }
2793         return $length;
2794     };
2795
2796     my $length = &$getOverloadLength($function);
2797     foreach my $overload (@{$function->{overloads}}) {
2798         my $newLength = &$getOverloadLength($overload);
2799         $length = $newLength if $newLength < $length;
2800     }
2801     return $length;
2802 }
2803
2804 sub LengthOfLongestFunctionParameterList
2805 {
2806     my ($overloads) = @_;
2807     my $result = 0;
2808     foreach my $overload (@{$overloads}) {
2809         my @arguments = @{$overload->arguments};
2810         $result = @arguments if $result < @arguments;
2811     }
2812     return $result;
2813 }
2814
2815 # See http://refspecs.linux-foundation.org/cxxabi-1.83.html.
2816 sub GetGnuVTableRefForInterface
2817 {
2818     my $interface = shift;
2819     my $vtableName = GetGnuVTableNameForInterface($interface);
2820     if (!$vtableName) {
2821         return "0";
2822     }
2823     my $typename = $interface->type->name;
2824     my $offset = GetGnuVTableOffsetForType($typename);
2825     return "&" . $vtableName . "[" . $offset . "]";
2826 }
2827
2828 sub GetGnuVTableNameForInterface
2829 {
2830     my $interface = shift;
2831     my $typename = $interface->type->name;
2832     my $templatePosition = index($typename, "<");
2833     return "" if $templatePosition != -1;
2834     return "" if GetImplementationLacksVTableForInterface($interface);
2835     return "" if GetSkipVTableValidationForInterface($interface);
2836     return "_ZTV" . GetGnuMangledNameForInterface($interface);
2837 }
2838
2839 sub GetGnuMangledNameForInterface
2840 {
2841     my $interface = shift;
2842     my $typename = $interface->type->name;
2843     my $templatePosition = index($typename, "<");
2844     if ($templatePosition != -1) {
2845         return "";
2846     }
2847     my $mangledType = length($typename) . $typename;
2848     my $namespace = "WebCore";
2849     my $mangledNamespace =  "N" . length($namespace) . $namespace;
2850     return $mangledNamespace . $mangledType . "E";
2851 }
2852
2853 sub GetGnuVTableOffsetForType
2854 {
2855     my $typename = shift;
2856     if ($typename eq "SVGAElement"
2857         || $typename eq "SVGCircleElement"
2858         || $typename eq "SVGClipPathElement"
2859         || $typename eq "SVGDefsElement"
2860         || $typename eq "SVGEllipseElement"
2861         || $typename eq "SVGForeignObjectElement"
2862         || $typename eq "SVGGElement"
2863         || $typename eq "SVGImageElement"
2864         || $typename eq "SVGLineElement"
2865         || $typename eq "SVGPathElement"
2866         || $typename eq "SVGPolyElement"
2867         || $typename eq "SVGPolygonElement"
2868         || $typename eq "SVGPolylineElement"
2869         || $typename eq "SVGRectElement"
2870         || $typename eq "SVGSVGElement"
2871         || $typename eq "SVGGraphicsElement"
2872         || $typename eq "SVGSwitchElement"
2873         || $typename eq "SVGTextElement"
2874         || $typename eq "SVGUseElement") {
2875         return "3";
2876     }
2877     return "2";
2878 }
2879
2880 # See http://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B_Name_Mangling.
2881 sub GetWinVTableRefForInterface
2882 {
2883     my $interface = shift;
2884     my $vtableName = GetWinVTableNameForInterface($interface);
2885     return 0 if !$vtableName;
2886     return "__identifier(\"" . $vtableName . "\")";
2887 }
2888
2889 sub GetWinVTableNameForInterface
2890 {
2891     my $interface = shift;
2892     my $typename = $interface->type->name;
2893     my $templatePosition = index($typename, "<");
2894     return "" if $templatePosition != -1;
2895     return "" if GetImplementationLacksVTableForInterface($interface);
2896     return "" if GetSkipVTableValidationForInterface($interface);
2897     return "??_7" . GetWinMangledNameForInterface($interface) . "6B@";
2898 }
2899
2900 sub GetWinMangledNameForInterface
2901 {
2902     my $interface = shift;
2903     my $typename = $interface->type->name;
2904     my $namespace = "WebCore";
2905     return $typename . "@" . $namespace . "@@";
2906 }
2907
2908 sub GetImplementationLacksVTableForInterface
2909 {
2910     my $interface = shift;
2911     return $interface->extendedAttributes->{ImplementationLacksVTable};
2912 }
2913
2914 sub GetSkipVTableValidationForInterface
2915 {
2916     my $interface = shift;
2917     return $interface->extendedAttributes->{SkipVTableValidation};
2918 }
2919
2920 # URL becomes url, but SetURL becomes setURL.
2921 sub ToMethodName
2922 {
2923     my $param = shift;
2924     my $ret = lcfirst($param);
2925     $ret =~ s/cSS/css/ if $ret =~ /^cSS/;
2926     $ret =~ s/dOM/dom/ if $ret =~ /^dOM/;
2927     $ret =~ s/hTML/html/ if $ret =~ /^hTML/;
2928     $ret =~ s/jS/js/ if $ret =~ /^jS/;
2929     $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
2930     $ret =~ s/xML/xml/ if $ret =~ /^xML/;
2931     $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
2932
2933     # For HTML5 FileSystem API Flags attributes.
2934     # (create is widely used to instantiate an object and must be avoided.)
2935     $ret =~ s/^create/isCreate/ if $ret =~ /^create$/;
2936     $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/;
2937
2938     return $ret;
2939 }
2940
2941 # Returns the conditional string that determines whether a method/attribute is enabled at runtime.
2942 # A method/attribute is enabled at runtime if either its RuntimeEnabledFeatures function returns
2943 # true or its EnabledForWorld function returns true (or both).
2944 # NOTE: Parameter passed in must have an 'extendedAttributes' property.
2945 # (e.g. DOMInterface, DOMAttribute, DOMOperation, DOMIterable, etc.)
2946 sub GenerateRuntimeEnableConditionalString
2947 {
2948     my $context = shift;
2949
2950     AddToImplIncludes("RuntimeEnabledFeatures.h");
2951
2952     my @conjuncts;
2953     if ($context->extendedAttributes->{EnabledForWorld}) {
2954         assert("Must specify value for EnabledForWorld.") if $context->extendedAttributes->{EnabledForWorld} eq "VALUE_IS_MISSING";
2955         push @conjuncts, "worldForDOMObject(this)." . ToMethodName($context->extendedAttributes->{EnabledForWorld}) . "()";
2956     }
2957
2958     if ($context->extendedAttributes->{EnabledAtRuntime}) {
2959         assert("Must specify value for EnabledAtRuntime.") if $context->extendedAttributes->{EnabledAtRuntime} eq "VALUE_IS_MISSING";
2960         my @flags = split /&/, $context->extendedAttributes->{EnabledAtRuntime};
2961         foreach my $flag (@flags) {
2962             push @conjuncts, "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($flag) . "Enabled()";
2963         }
2964     }
2965
2966     my $result = join(" && ", @conjuncts);
2967     $result = "($result)" if @conjuncts > 1;
2968     return $result;
2969 }
2970
2971 sub GetCastingHelperForThisObject
2972 {
2973     my $interface = shift;
2974     my $interfaceName = $interface->type->name;
2975     return "jsDynamicDowncast<JS$interfaceName*>";
2976 }
2977
2978 # http://heycam.github.io/webidl/#Unscopable
2979 sub addUnscopableProperties
2980 {
2981     my $interface = shift;
2982
2983     my @unscopables;
2984     foreach my $functionOrAttribute (@{$interface->functions}, @{$interface->attributes}) {
2985         push(@unscopables, $functionOrAttribute->name) if $functionOrAttribute->extendedAttributes->{Unscopable};
2986     }
2987     return if scalar(@unscopables) == 0;
2988
2989     AddToImplIncludes("<runtime/ObjectConstructor.h>");
2990     push(@implContent, "    JSObject& unscopables = *constructEmptyObject(globalObject()->globalExec(), globalObject()->nullPrototypeObjectStructure());\n");
2991     foreach my $unscopable (@unscopables) {
2992         push(@implContent, "    unscopables.putDirect(vm, Identifier::fromString(&vm, \"$unscopable\"), jsBoolean(true));\n");
2993     }
2994     push(@implContent, "    putDirectWithoutTransition(vm, vm.propertyNames->unscopablesSymbol, &unscopables, DontEnum | ReadOnly);\n");
2995 }
2996
2997 sub GetUnsafeArgumentType
2998 {
2999     my ($interface, $type) = @_;
3000
3001     my $IDLType = GetIDLType($interface, $type);
3002     return "DOMJIT::IDLJSArgumentType<${IDLType}>";
3003 }
3004
3005 sub GetArgumentTypeFilter
3006 {
3007     my ($interface, $type) = @_;
3008
3009     my $IDLType = GetIDLType($interface, $type);
3010     return "DOMJIT::IDLArgumentTypeFilter<${IDLType}>::value";
3011 }
3012
3013 sub GetResultTypeFilter
3014 {
3015     my ($interface, $type) = @_;
3016
3017     my $IDLType = GetIDLType($interface, $type);
3018     return "DOMJIT::IDLResultTypeFilter<${IDLType}>::value";
3019 }
3020
3021 sub GetAttributeWithName
3022 {
3023     my ($interface, $attributeName) = @_;
3024     
3025     foreach my $attribute (@{$interface->attributes}) {
3026         return $attribute if $attribute->name eq $attributeName;
3027     }
3028 }
3029
3030 # https://heycam.github.io/webidl/#es-iterator
3031 sub InterfaceNeedsIterator
3032 {
3033     my ($interface) = @_;
3034
3035     # FIXME: This should return 1 for setlike once we support it.
3036     return 1 if $interface->mapLike;
3037     return 1 if $interface->iterable;
3038
3039     if (GetIndexedGetterFunction($interface)) {
3040         my $lengthAttribute = GetAttributeWithName($interface, "length");
3041         return 1 if $lengthAttribute and $codeGenerator->IsIntegerType($lengthAttribute->type);
3042     }
3043     return 0;
3044 }
3045
3046 sub GenerateImplementation
3047 {
3048     my ($object, $interface, $enumerations, $dictionaries) = @_;
3049
3050     my $interfaceName = $interface->type->name;
3051     my $className = "JS$interfaceName";
3052
3053     my $hasLegacyParent = $interface->extendedAttributes->{JSLegacyParent};
3054     my $hasRealParent = $interface->parentType;
3055     my $hasParent = $hasLegacyParent || $hasRealParent;
3056     my $parentClassName = GetParentClassName($interface);
3057     my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
3058     my $eventTarget = $codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->type->name ne "EventTarget";
3059     my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
3060
3061     my $namedGetterFunction = GetNamedGetterFunction($interface);
3062     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
3063
3064     # - Add default header template
3065     push(@implContentHeader, GenerateImplementationContentHeader($interface));
3066
3067     $implIncludes{"JSDOMBinding.h"} = 1;
3068     $implIncludes{"JSDOMBindingCaller.h"} = 1;
3069     $implIncludes{"JSDOMExceptionHandling.h"} = 1;
3070     $implIncludes{"JSDOMWrapperCache.h"} = 1;
3071     $implIncludes{"<wtf/GetPtr.h>"} = 1;
3072     $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $indexedGetterFunction;
3073
3074     my $implType = GetImplClassName($interface);
3075
3076     AddJSBuiltinIncludesIfNeeded($interface);
3077
3078     @implContent = ();
3079
3080     push(@implContent, "\nusing namespace JSC;\n\n");
3081     push(@implContent, "namespace WebCore {\n\n");
3082
3083     push(@implContent, GenerateEnumerationsImplementationContent($interface, $enumerations));
3084     push(@implContent, GenerateDictionariesImplementationContent($interface, $dictionaries));
3085
3086     my @functions = @{$interface->functions};
3087     push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
3088     push(@functions, @{$interface->mapLike->functions}) if $interface->mapLike;
3089     push(@functions, @{$interface->serializable->functions}) if $interface->serializable;
3090
3091     my @attributes = @{$interface->attributes};
3092     push(@attributes, @{$interface->mapLike->attributes}) if $interface->mapLike;
3093
3094     my $numConstants = @{$interface->constants};
3095     my $numFunctions = @functions;
3096     my $numAttributes = @attributes;
3097
3098     if ($numFunctions > 0) {
3099         my $inAppleCopyright = 0;
3100         push(@implContent,"// Functions\n\n");
3101         foreach my $function (@functions) {
3102             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
3103             next if $function->extendedAttributes->{ForwardDeclareInHeader};
3104             next if IsJSBuiltin($interface, $function);
3105
3106             if ($function->extendedAttributes->{AppleCopyright}) {
3107                 if (!$inAppleCopyright) {
3108                     push(@implContent, $beginAppleCopyrightForHeaderFiles);
3109                     $inAppleCopyright = 1;
3110                 }
3111             } elsif ($inAppleCopyright) {
3112                 push(@implContent, $endAppleCopyright);
3113                 $inAppleCopyright = 0;
3114             }
3115
3116             my $conditionalAttribute = GetConditionalForFunctionConsideringOverloads($function);
3117             my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
3118             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
3119             my $functionName = GetFunctionName($interface, $className, $function);
3120             push(@implContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
3121             if ($function->extendedAttributes->{DOMJIT}) {
3122                 $implIncludes{"DOMJITIDLType.h"} = 1;
3123                 my $unsafeFunctionName = "unsafe" . $codeGenerator->WK_ucfirst($functionName);
3124                 my $functionSignature = "JSC::EncodedJSValue JIT_OPERATION ${unsafeFunctionName}(JSC::ExecState*, $className*";
3125                 foreach my $argument (@{$function->arguments}) {
3126                     my $type = $argument->type;
3127                     my $argumentType = GetUnsafeArgumentType($interface, $type);
3128                     $functionSignature .= ", ${argumentType}";
3129                 }
3130                 push(@implContent, $functionSignature . ");\n");
3131             }
3132             push(@implContent, "#endif\n") if $conditionalString;
3133         }
3134
3135         push(@implContent, $endAppleCopyright) if $inAppleCopyright;
3136         push(@implContent, "\n");
3137     }
3138
3139     if ($numAttributes > 0 || NeedsConstructorProperty($interface)) {
3140         push(@implContent, "// Attributes\n\n");
3141
3142         foreach my $attribute (@attributes) {
3143             next if $attribute->extendedAttributes->{ForwardDeclareInHeader};
3144             next if IsJSBuiltin($interface, $attribute);
3145
3146             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
3147             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
3148             my $getter = GetAttributeGetterName($interface, $className, $attribute);
3149             push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
3150             if (!IsReadonly($attribute)) {
3151                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
3152                 push(@implContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
3153             }
3154             push(@implContent, "#endif\n") if $conditionalString;
3155         }
3156
3157         if (NeedsConstructorProperty($interface)) {
3158             my $getter = "js" . $interfaceName . "Constructor";
3159             push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
3160         }
3161
3162         my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
3163         push(@implContent, "bool ${constructorFunctionName}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
3164
3165         push(@implContent, "\n");
3166     }
3167
3168     if ($numFunctions > 0) {
3169         foreach my $function (@functions) {
3170             next unless $function->extendedAttributes->{DOMJIT};
3171             $implIncludes{"DOMJITIDLTypeFilter.h"} = 1;
3172             $implIncludes{"DOMJITAbstractHeapRepository.h"} = 1;
3173
3174             my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
3175             die "Overloads is not supported in DOMJIT" if $isOverloaded;
3176             die "Currently ReadDOM value is only allowed" unless $codeGenerator->ExtendedAttributeContains($function->extendedAttributes->{DOMJIT}, "ReadDOM");
3177
3178             my $interfaceName = $interface->type->name;
3179             my $functionName = GetFunctionName($interface, $className, $function);
3180             my $unsafeFunctionName = "unsafe" . $codeGenerator->WK_ucfirst($functionName);
3181             my $domJITSignatureName = "DOMJITSignatureFor" . $interface->type->name . $codeGenerator->WK_ucfirst($function->name);
3182             my $classInfo = "JS" . $interface->type->name . "::info()";
3183             my $resultType = GetResultTypeFilter($interface, $function->type);
3184             my $domJITSignatureHeader = "static const JSC::DOMJIT::Signature ${domJITSignatureName}((uintptr_t)${unsafeFunctionName},";
3185             my $domJITSignatureFooter = "$classInfo, JSC::DOMJIT::Effect::forRead(DOMJIT::AbstractHeapRepository::DOM), ${resultType}";
3186             foreach my $argument (@{$function->arguments}) {
3187                 my $type = $argument->type;
3188                 my $argumentType = GetArgumentTypeFilter($interface, $type);
3189                 $domJITSignatureFooter .= ", ${argumentType}";
3190             }
3191             $domJITSignatureFooter .= ");";
3192             my $conditionalString = $codeGenerator->GenerateConditionalString($function);
3193             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
3194             push(@implContent, "$domJITSignatureHeader $domJITSignatureFooter\n");
3195             push(@implContent, "#endif\n") if $conditionalString;
3196             push(@implContent, "\n");
3197         }
3198     }
3199
3200     GeneratePrototypeDeclaration(\@implContent, $className, $interface) if !HeaderNeedsPrototypeDeclaration($interface);
3201
3202     GenerateConstructorDeclaration(\@implContent, $className, $interface) if NeedsConstructorProperty($interface);
3203
3204     my @hashKeys = ();
3205     my @hashValue1 = ();
3206     my @hashValue2 = ();
3207     my @hashSpecials = ();
3208     my %conditionals = ();
3209     my $hashName = $className . "Table";
3210     my @runtimeEnabledFunctions = ();
3211     my @runtimeEnabledAttributes = ();
3212     my @settingsEnabledFunctions = ();
3213     my @settingsEnabledAttributes = ();
3214
3215     # Generate hash table for properties on the instance.
3216     my $numInstanceProperties = GeneratePropertiesHashTable($object, $interface, 1,
3217         \@hashKeys, \@hashSpecials,
3218         \@hashValue1, \@hashValue2,
3219         \%conditionals,
3220         \@runtimeEnabledFunctions, \@runtimeEnabledAttributes,
3221         \@settingsEnabledFunctions, \@settingsEnabledAttributes);
3222
3223     $object->GenerateHashTable($hashName, $numInstanceProperties,
3224         \@hashKeys, \@hashSpecials,
3225         \@hashValue1, \@hashValue2,
3226         \%conditionals, 0) if $numInstanceProperties > 0;
3227
3228     # - Add all interface object (aka constructor) properties (constants, static attributes, static operations).
3229     if (NeedsConstructorProperty($interface)) {
3230         my $hashSize = 0;
3231         my $hashName = $className . "ConstructorTable";
3232
3233         my @hashKeys = ();
3234         my @hashValue1 = ();
3235         my @hashValue2 = ();
3236         my @hashSpecials = ();
3237         my %conditionals = ();
3238
3239         my $needsConstructorTable = 0;
3240
3241         foreach my $constant (@{$interface->constants}) {
3242             my $name = $constant->name;
3243             push(@hashKeys, $name);
3244             push(@hashValue1, $constant->value);
3245             push(@hashValue2, "0");
3246             push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
3247
3248             my $implementedBy = $constant->extendedAttributes->{ImplementedBy};
3249             $implIncludes{"${implementedBy}.h"} = 1 if $implementedBy;
3250
3251             my $conditional = $constant->extendedAttributes->{Conditional};
3252             $conditionals{$name} = $conditional if $conditional;
3253
3254             $hashSize++;
3255         }
3256
3257         foreach my $attribute (@{$interface->attributes}) {
3258             next unless ($attribute->isStatic);
3259             my $name = $attribute->name;
3260             push(@hashKeys, $name);
3261