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