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