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