Next step on dictionary bindings, along with other bindings refinements
[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, 2007-2010, 2013-2016 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 Hasher;
37
38 my $codeGenerator;
39
40 my @headerContentHeader = ();
41 my @headerContent = ();
42 my %headerIncludes = ();
43 my %headerTrailingIncludes = ();
44
45 my @implContentHeader = ();
46 my @implContent = ();
47 my %implIncludes = ();
48 my @depsContent = ();
49 my $numCachedAttributes = 0;
50 my $currentCachedAttribute = 0;
51
52 my $beginAppleCopyrightForHeaderFiles = <<END;
53 // ------- Begin Apple Copyright -------
54 /*
55  * Copyright (C) 2008, Apple Inc. All rights reserved.
56  *
57  * Permission is granted by Apple to use this file to the extent
58  * necessary to relink with LGPL WebKit files.
59  *
60  * No license or rights are granted by Apple expressly or by
61  * implication, estoppel, or otherwise, to Apple patents and
62  * trademarks. For the sake of clarity, no license or rights are
63  * granted by Apple expressly or by implication, estoppel, or otherwise,
64  * under any Apple patents, copyrights and trademarks to underlying
65  * implementations of any application programming interfaces (APIs)
66  * or to any functionality that is invoked by calling any API.
67  */
68
69 END
70 my $beginAppleCopyrightForSourceFiles = <<END;
71 // ------- Begin Apple Copyright -------
72 /*
73  * Copyright (C) 2008, Apple Inc. All rights reserved.
74  *
75  * No license or rights are granted by Apple expressly or by implication,
76  * estoppel, or otherwise, to Apple copyrights, patents, trademarks, trade
77  * secrets or other rights.
78  */
79
80 END
81 my $endAppleCopyright   = <<END;
82 // ------- End Apple Copyright   -------
83
84 END
85
86 # Default .h template
87 my $headerTemplate = << "EOF";
88 /*
89     This file is part of the WebKit open source project.
90     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
91
92     This library is free software; you can redistribute it and/or
93     modify it under the terms of the GNU Library General Public
94     License as published by the Free Software Foundation; either
95     version 2 of the License, or (at your option) any later version.
96
97     This library is distributed in the hope that it will be useful,
98     but WITHOUT ANY WARRANTY; without even the implied warranty of
99     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
100     Library General Public License for more details.
101
102     You should have received a copy of the GNU Library General Public License
103     along with this library; see the file COPYING.LIB.  If not, write to
104     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
105     Boston, MA 02110-1301, USA.
106 */
107 EOF
108
109 # Default constructor
110 sub new
111 {
112     my $object = shift;
113     my $reference = { };
114
115     $codeGenerator = shift;
116
117     bless($reference, $object);
118     return $reference;
119 }
120
121 sub GenerateInterface
122 {
123     my ($object, $interface, $defines, $enumerations, $dictionaries) = @_;
124
125     $codeGenerator->LinkOverloadedFunctions($interface);
126     if ($interface->isCallback) {
127         $object->GenerateCallbackHeader($interface);
128         $object->GenerateCallbackImplementation($interface, $enumerations, $dictionaries);
129     } else {
130         $object->GenerateHeader($interface);
131         $object->GenerateImplementation($interface, $enumerations, $dictionaries);
132     }
133 }
134
135 sub EventHandlerAttributeEventName
136 {
137     my $attribute = shift;
138     my $eventType = $attribute->signature->extendedAttributes->{"ImplementedAs"} || $attribute->signature->name;
139
140     # Remove the "on" prefix.
141     $eventType = substr($eventType, 2);
142
143     return "eventNames().${eventType}Event";
144 }
145
146 sub GenerateEventListenerCall
147 {
148     my $functionName = shift;
149     my $suffix = ucfirst $functionName;
150     my $passRefPtrHandling = ($functionName eq "add") ? "" : ".ptr()";
151
152     $implIncludes{"JSEventListener.h"} = 1;
153
154     my @GenerateEventListenerImpl = ();
155
156     push(@GenerateEventListenerImpl, <<END);
157     JSValue listener = state->argument(1);
158     if (UNLIKELY(!listener.isObject()))
159         return JSValue::encode(jsUndefined());
160     impl.${functionName}EventListener(state->argument(0).toString(state)->toAtomicString(state), createJSEventListenerFor$suffix(*state, *asObject(listener), *castedThis)$passRefPtrHandling, state->argument(2).toBoolean(state));
161     return JSValue::encode(jsUndefined());
162 END
163     return @GenerateEventListenerImpl;
164 }
165
166 sub GetParentClassName
167 {
168     my $interface = shift;
169
170     return $interface->extendedAttributes->{"JSLegacyParent"} if $interface->extendedAttributes->{"JSLegacyParent"};
171     return "JSDOMObject" unless NeedsImplementationClass($interface);
172     return "JSDOMWrapper<" . GetImplClassName($interface->name) . ">" unless $interface->parent;
173     return "JS" . $interface->parent;
174 }
175
176 sub GetCallbackClassName
177 {
178     my $className = shift;
179
180     return "JS$className";
181 }
182
183 sub GetJSCallbackDataType
184 {
185     my $callbackInterface = shift;
186
187     return $callbackInterface->extendedAttributes->{"IsWeakCallback"} ? "JSCallbackDataWeak" : "JSCallbackDataStrong";
188 }
189
190 sub AddIncludesForTypeInImpl
191 {
192     my $type = shift;
193     my $isCallback = @_ ? shift : 0;
194     
195     AddIncludesForType($type, $isCallback, \%implIncludes);
196 }
197
198 sub AddIncludesForTypeInHeader
199 {
200     my $type = shift;
201     my $isCallback = @_ ? shift : 0;
202     
203     AddIncludesForType($type, $isCallback, \%headerIncludes);
204 }
205
206 sub GetExportMacroForJSClass
207 {
208     my $interface = shift;
209
210     return $interface->extendedAttributes->{"ExportMacro"} . " " if $interface->extendedAttributes->{"ExportMacro"};
211     return "";
212 }
213
214 sub AddIncludesForType
215 {
216     my $type = shift;
217     my $isCallback = shift;
218     my $includesRef = shift;
219
220     return if $codeGenerator->SkipIncludeHeader($type);
221     
222     # When we're finished with the one-file-per-class reorganization, we won't need these special cases.
223     if ($type eq "XPathNSResolver") {
224         $includesRef->{"JSXPathNSResolver.h"} = 1;
225         $includesRef->{"JSCustomXPathNSResolver.h"} = 1;
226     } elsif ($isCallback && $codeGenerator->IsWrapperType($type)) {
227         $includesRef->{"JS${type}.h"} = 1;
228     } elsif ($codeGenerator->GetArrayOrSequenceType($type)) {
229         my $arrayType = $codeGenerator->GetArrayType($type);
230         my $arrayOrSequenceType = $arrayType || $codeGenerator->GetSequenceType($type);
231         if ($arrayType eq "DOMString") {
232             $includesRef->{"JSDOMStringList.h"} = 1;
233             $includesRef->{"DOMStringList.h"} = 1;
234         } elsif ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) {
235             $includesRef->{"JS${arrayOrSequenceType}.h"} = 1;
236             $includesRef->{"${arrayOrSequenceType}.h"} = 1;
237         }
238         $includesRef->{"<runtime/JSArray.h>"} = 1;
239     } else {
240         # default, include the same named file
241         $includesRef->{"${type}.h"} = 1;
242     }
243 }
244
245 sub AddToImplIncludes
246 {
247     my $header = shift;
248     my $conditional = shift;
249
250     if (not $conditional) {
251         $implIncludes{$header} = 1;
252     } elsif (not exists($implIncludes{$header})) {
253         $implIncludes{$header} = $conditional;
254     } else {
255         my $oldValue = $implIncludes{$header};
256         $implIncludes{$header} = "$oldValue|$conditional" if $oldValue ne 1;
257     }
258 }
259
260 sub IsReadonly
261 {
262     my $attribute = shift;
263     return $attribute->isReadOnly && !$attribute->signature->extendedAttributes->{"Replaceable"} && !$attribute->signature->extendedAttributes->{"PutForwards"};
264 }
265
266 sub AddClassForwardIfNeeded
267 {
268     my $interfaceName = shift;
269
270     if ($interfaceName eq "ScriptProfileNode") {
271         $headerIncludes{"<profiler/ProfileNode.h>"} = 1;
272         push(@headerContent, "typedef JSC::ProfileNode ScriptProfileNode;\n\n");
273         return;
274     }
275
276     # SVGAnimatedLength/Number/etc. are typedefs and should not be forward-declared as classes.
277     return if $codeGenerator->IsSVGAnimatedType($interfaceName);
278
279     return if $codeGenerator->IsTypedArrayType($interfaceName);
280
281     push(@headerContent, "class $interfaceName;\n\n");
282 }
283
284 sub GetGenerateIsReachable
285 {
286     my $interface = shift;
287     return $interface->extendedAttributes->{"GenerateIsReachable"};
288 }
289
290 sub GetCustomIsReachable
291 {
292     my $interface = shift;
293     return $interface->extendedAttributes->{"CustomIsReachable"};
294 }
295
296 sub IsDOMGlobalObject
297 {
298     my $interface = shift;
299     return $interface->name eq "DOMWindow" || $codeGenerator->InheritsInterface($interface, "WorkerGlobalScope") || $interface->name eq "TestGlobalObject";
300 }
301
302 sub GenerateGetOwnPropertySlotBody
303 {
304     my ($interface, $className, $hasInstanceProperties, $inlined) = @_;
305
306     my $namespaceMaybe = ($inlined ? "JSC::" : "");
307     my $namedGetterFunction = GetNamedGetterFunction($interface);
308     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
309
310     my @getOwnPropertySlotImpl = ();
311
312     my $ownPropertyCheck = sub {
313         if ($hasInstanceProperties) {
314             my $instanceFunctionCount = InstanceFunctionCount($interface);
315             # If there are functions on the instance, then call getStaticPropertySlot() instead of getStaticValueSlot().
316             my $staticPropertyGetFunction = $namespaceMaybe . ($instanceFunctionCount eq 0 ? "getStaticValueSlot" : "getStaticPropertySlot");
317             my $staticPropertyTable = $inlined ? "*info()->staticPropHashTable" : "${className}Table";
318             push(@getOwnPropertySlotImpl, "    if ($staticPropertyGetFunction<$className, Base>(state, ${staticPropertyTable}, thisObject, propertyName, slot))\n");
319         } else {
320             push(@getOwnPropertySlotImpl, "    if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot))\n");
321         }
322         push(@getOwnPropertySlotImpl, "        return true;\n");
323     };
324
325     # FIXME: As per the Web IDL specification, the prototype check is supposed to skip "named properties objects":
326     # https://heycam.github.io/webidl/#dfn-named-property-visibility
327     # https://heycam.github.io/webidl/#dfn-named-properties-object
328     my $prototypeCheck = sub {
329         push(@getOwnPropertySlotImpl, "    ${namespaceMaybe}JSValue proto = thisObject->getPrototypeDirect();\n");
330         push(@getOwnPropertySlotImpl, "    if (proto.isObject() && jsCast<${namespaceMaybe}JSObject*>(proto)->hasProperty(state, propertyName))\n");
331         push(@getOwnPropertySlotImpl, "        return false;\n\n");
332     };
333
334     if ($indexedGetterFunction) {
335         push(@getOwnPropertySlotImpl, "    Optional<uint32_t> optionalIndex = parseIndex(propertyName);\n");
336
337         # If the item function returns a string then we let the TreatReturnedNullStringAs handle the cases
338         # where the index is out of range.
339         if ($indexedGetterFunction->signature->type eq "DOMString") {
340             push(@getOwnPropertySlotImpl, "    if (optionalIndex) {\n");
341         } else {
342             push(@getOwnPropertySlotImpl, "    if (optionalIndex && optionalIndex.value() < thisObject->wrapped().length()) {\n");
343         }
344         push(@getOwnPropertySlotImpl, "        unsigned index = optionalIndex.value();\n");
345         # Assume that if there's a setter, the index will be writable
346         if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
347             push(@getOwnPropertySlotImpl, "        unsigned attributes = ${namespaceMaybe}DontDelete;\n");
348         } else {
349             push(@getOwnPropertySlotImpl, "        unsigned attributes = ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly;\n");
350         }
351         push(@getOwnPropertySlotImpl, "        slot.setValue(thisObject, attributes, " . GetIndexedGetterExpression($indexedGetterFunction) . ");\n");
352         push(@getOwnPropertySlotImpl, "        return true;\n");
353         push(@getOwnPropertySlotImpl, "    }\n");
354     }
355
356     my $hasNamedGetter = $namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"};
357     if ($hasNamedGetter) {
358         if (!$interface->extendedAttributes->{"OverrideBuiltins"}) {
359             &$ownPropertyCheck();
360             &$prototypeCheck();
361         }
362
363         # The "thisObject->classInfo() == info()" check is to make sure we use the subclass' named getter
364         # instead of the base class one when possible.
365         if ($indexedGetterFunction) {
366             # Indexing an object with an integer that is not a supported property index should not call the named property getter.
367             # https://heycam.github.io/webidl/#idl-indexed-properties
368             push(@getOwnPropertySlotImpl, "    if (!optionalIndex && thisObject->classInfo() == info()) {\n");
369         } else {
370             push(@getOwnPropertySlotImpl, "    if (thisObject->classInfo() == info()) {\n");
371         }
372         push(@getOwnPropertySlotImpl, "        JSValue value;\n");
373         push(@getOwnPropertySlotImpl, "        if (thisObject->nameGetter(state, propertyName, value)) {\n");
374         push(@getOwnPropertySlotImpl, "            slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, value);\n");
375         push(@getOwnPropertySlotImpl, "            return true;\n");
376         push(@getOwnPropertySlotImpl, "        }\n");
377         push(@getOwnPropertySlotImpl, "    }\n");
378         if ($inlined) {
379             $headerIncludes{"wtf/text/AtomicString.h"} = 1;
380         } else {
381             $implIncludes{"wtf/text/AtomicString.h"} = 1;
382         }
383     }
384
385     if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
386         push(@getOwnPropertySlotImpl, "    if (thisObject->getOwnPropertySlotDelegate(state, propertyName, slot))\n");
387         push(@getOwnPropertySlotImpl, "        return true;\n");
388     }
389
390     if (!$hasNamedGetter || $interface->extendedAttributes->{"OverrideBuiltins"}) {
391         &$ownPropertyCheck();
392     }
393
394     push(@getOwnPropertySlotImpl, "    return false;\n");
395
396     return @getOwnPropertySlotImpl;
397 }
398
399 sub GenerateHeaderContentHeader
400 {
401     my $interface = shift;
402     my $className = "JS" . $interface->name;
403
404     my @headerContentHeader;
405     if ($interface->extendedAttributes->{"AppleCopyright"}) {
406         @headerContentHeader = split("\r", $beginAppleCopyrightForHeaderFiles);
407     } else {
408         @headerContentHeader = split("\r", $headerTemplate);
409     }
410
411     push(@headerContentHeader, "\n#pragma once\n\n");
412
413     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
414     push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
415     return @headerContentHeader;
416 }
417
418 sub GenerateImplementationContentHeader
419 {
420     my $interface = shift;
421     my $className = "JS" . $interface->name;
422
423     my @implContentHeader;
424     if ($interface->extendedAttributes->{"AppleCopyright"}) {
425         @implContentHeader = split("\r", $beginAppleCopyrightForSourceFiles);
426     } else {
427         @implContentHeader = split("\r", $headerTemplate);
428     }
429
430     push(@implContentHeader, "\n#include \"config.h\"\n");
431     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
432     push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;
433     push(@implContentHeader, "#include \"$className.h\"\n\n");
434     return @implContentHeader;
435 }
436
437 sub NeedsImplementationClass
438 {
439     my ($interface) = @_;
440
441     return 0 if $interface->extendedAttributes->{"JSBuiltin"};
442     return 1;
443 }
444
445 sub ShouldGenerateToWrapped
446 {
447     my ($hasParent, $interface) = @_;
448
449     return 0 if not NeedsImplementationClass($interface);
450     return 1 if !$hasParent or $interface->extendedAttributes->{"JSGenerateToNativeObject"};
451     return 1 if $interface->parent && $interface->parent eq "EventTarget";
452     return 0;
453 }
454
455 sub ShouldGenerateWrapperOwnerCode
456 {
457     my ($hasParent, $interface) = @_;
458
459     return 0 if not NeedsImplementationClass($interface);
460     if (!$hasParent ||
461         GetGenerateIsReachable($interface) ||
462         GetCustomIsReachable($interface) ||
463         $interface->extendedAttributes->{"JSCustomFinalize"} ||
464         $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
465         return 1;
466     }
467     return 0;
468 }
469
470 sub ShouldGenerateToJSDeclaration
471 {
472     my ($hasParent, $interface) = @_;
473
474     return 0 if ($interface->extendedAttributes->{"SuppressToJSObject"});
475     return 0 if not NeedsImplementationClass($interface);
476     return 0 if $interface->name eq "AbstractView";
477     return 0 if $interface->extendedAttributes->{"CustomProxyToJSObject"};
478     return 1 if (!$hasParent or $interface->extendedAttributes->{"JSGenerateToJSObject"} or $interface->extendedAttributes->{"CustomToJSObject"});
479     return 1 if $interface->parent && $interface->parent eq "EventTarget";
480     return 0;
481 }
482
483 sub ShouldGenerateToJSImplementation
484 {
485     my ($hasParent, $interface) = @_;
486
487     return 0 if not ShouldGenerateToJSDeclaration($hasParent, $interface);
488     return 1 if not $interface->extendedAttributes->{"CustomToJSObject"};
489     return 0;
490 }
491
492 sub GetAttributeGetterName
493 {
494     my ($interface, $className, $attribute) = @_;
495
496     return $codeGenerator->WK_lcfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name) if $attribute->isStatic;
497     return GetJSBuiltinFunctionName($className, $attribute) if IsJSBuiltin($interface, $attribute);
498     return "js" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
499 }
500
501 sub GetAttributeSetterName
502 {
503     my ($interface, $className, $attribute) = @_;
504
505     return "set" . $codeGenerator->WK_ucfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name) if $attribute->isStatic;
506     return "set" . $codeGenerator->WK_ucfirst(GetJSBuiltinFunctionName($className, $attribute)) if IsJSBuiltin($interface, $attribute);
507     return "setJS" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
508 }
509
510 sub GetFunctionName
511 {
512     my ($interface, $className, $function) = @_;
513
514     return GetJSBuiltinFunctionName($className, $function) if IsJSBuiltin($interface, $function);
515
516     my $functionName = $function->signature->name;
517     $functionName = "SymbolIterator" if $functionName eq "[Symbol.Iterator]";
518
519     my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
520     return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($functionName);
521 }
522
523 sub GetSpecialAccessorFunctionForType
524 {
525     my $interface = shift;
526     my $special = shift;
527     my $firstParameterType = shift;
528     my $numberOfParameters = shift;
529
530     foreach my $function (@{$interface->functions}, @{$interface->anonymousFunctions}) {
531         my $specials = $function->signature->specials;
532         my $specialExists = grep { $_ eq $special } @$specials;
533         my $parameters = $function->parameters;
534         if ($specialExists and scalar(@$parameters) == $numberOfParameters and $parameters->[0]->type eq $firstParameterType) {
535             return $function;
536         }
537     }
538
539     return 0;
540 }
541
542 sub HasComplexGetOwnProperty
543 {
544     my $interface = shift;
545
546     my $namedGetterFunction = GetNamedGetterFunction($interface);
547     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
548
549     my $hasNamedGetter = $namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"};
550
551     my $hasComplexGetter = $indexedGetterFunction
552         || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
553         || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
554         || $hasNamedGetter;
555
556     return 1 if $interface->extendedAttributes->{"CheckSecurity"};
557     return 1 if IsDOMGlobalObject($interface);
558     return 1 if $hasComplexGetter;
559     return 0;
560 }
561
562
563 sub InterfaceRequiresAttributesOnInstanceForCompatibility
564 {
565     my $interface = shift;
566     my $interfaceName = $interface->name;
567
568     # Needed for compatibility with existing content
569     return 1 if $interfaceName =~ "Touch";
570     return 1 if $interfaceName =~ "ClientRect";
571
572     return 0;
573 }
574
575 sub InterfaceRequiresAttributesOnInstance
576 {
577     my $interface = shift;
578     my $interfaceName = $interface->name;
579
580     # FIXME: All these return 1 if ... should ideally be removed.
581     # Some of them are unavoidable due to DOM weirdness, in which case we should
582     # add an IDL attribute for them
583
584     # FIXME: We should be able to drop this once <rdar://problem/24466097> is fixed.
585     return 1 if $interface->isException;
586
587     return 1 if IsDOMGlobalObject($interface);
588
589     return 1 if InterfaceRequiresAttributesOnInstanceForCompatibility($interface);
590
591     return 0;
592 }
593
594 sub AttributeShouldBeOnInstance
595 {
596     my $interface = shift;
597     my $attribute = shift;
598
599     # FIXME: The bindings generator does not support putting runtime-enabled attributes on the instance yet (except for global objects).
600     return 0 if $attribute->signature->extendedAttributes->{"EnabledAtRuntime"} && !IsDOMGlobalObject($interface);
601
602     return 1 if InterfaceRequiresAttributesOnInstance($interface);
603     return 1 if $attribute->signature->type =~ /Constructor$/;
604
605     # [Unforgeable] attributes should be on the instance.
606     # https://heycam.github.io/webidl/#Unforgeable
607     return 1 if IsUnforgeable($interface, $attribute);
608
609     if ($interface->extendedAttributes->{"CheckSecurity"}) {
610         if ($attribute->signature->extendedAttributes->{"DoNotCheckSecurity"} or
611             $attribute->signature->extendedAttributes->{"DoNotCheckSecurityOnGetter"}) {
612             return 0;
613         }
614         return 1;
615     }
616     return 0;
617 }
618
619 # https://heycam.github.io/webidl/#es-operations
620 sub OperationShouldBeOnInstance
621 {
622     my $interface = shift;
623     my $function = shift;
624
625     return 1 if IsDOMGlobalObject($interface);
626
627     # FIXME: The bindings generator does not support putting runtime-enabled operations on the instance yet (except for global objects).
628     return 0 if $function->signature->extendedAttributes->{"EnabledAtRuntime"};
629
630     # [Unforgeable] operations should be on the instance. https://heycam.github.io/webidl/#Unforgeable
631     return 1 if IsUnforgeable($interface, $function);
632
633     return 0;
634 }
635
636 sub GetJSCAttributesForAttribute
637 {
638     my $interface = shift;
639     my $attribute = shift;
640
641     my @specials = ();
642     push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute);
643
644     # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable.
645     my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
646     push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor);
647     push(@specials, "ReadOnly") if IsReadonly($attribute);
648     push(@specials, "CustomAccessor") unless $is_global_constructor or IsJSBuiltin($interface, $attribute);
649     push(@specials, "Accessor | Builtin") if  IsJSBuiltin($interface, $attribute);
650     return (@specials > 0) ? join(" | ", @specials) : "0";
651 }
652
653 sub GetIndexedGetterFunction
654 {
655     my $interface = shift;
656     return GetSpecialAccessorFunctionForType($interface, "getter", "unsigned long", 1);
657 }
658
659 sub GetNamedGetterFunction
660 {
661     my $interface = shift;
662     return GetSpecialAccessorFunctionForType($interface, "getter", "DOMString", 1);
663 }
664
665 sub InstanceFunctionCount
666 {
667     my $interface = shift;
668     my $count = 0;
669
670     foreach my $function (@{$interface->functions}) {
671         $count++ if OperationShouldBeOnInstance($interface, $function);
672     }
673
674     return $count;
675 }
676
677 sub PrototypeFunctionCount
678 {
679     my $interface = shift;
680     my $count = 0;
681
682     foreach my $function (@{$interface->functions}) {
683         $count++ if !$function->isStatic && !OperationShouldBeOnInstance($interface, $function);
684     }
685
686     $count += scalar @{$interface->iterable->functions} if $interface->iterable;
687
688     return $count;
689 }
690
691 sub InstancePropertyCount
692 {
693     my $interface = shift;
694     my $count = 0;
695     foreach my $attribute (@{$interface->attributes}) {
696         $count++ if AttributeShouldBeOnInstance($interface, $attribute);
697     }
698     $count += InstanceFunctionCount($interface);
699     return $count;
700 }
701
702 sub PrototypePropertyCount
703 {
704     my $interface = shift;
705     my $count = 0;
706     foreach my $attribute (@{$interface->attributes}) {
707         $count++ if !AttributeShouldBeOnInstance($interface, $attribute);
708     }
709     $count += PrototypeFunctionCount($interface);
710     $count++ if NeedsConstructorProperty($interface);
711     return $count;
712 }
713
714 sub InstanceOverridesGetOwnPropertySlot
715 {
716     my $interface = shift;
717     my $numInstanceProperties = InstancePropertyCount($interface);
718
719     my $namedGetterFunction = GetNamedGetterFunction($interface);
720     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
721
722     my $hasNamedGetter = $namedGetterFunction
723         || $interface->extendedAttributes->{"CustomNamedGetter"};
724
725     my $hasComplexGetter = $indexedGetterFunction
726         || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
727         || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
728         || $hasNamedGetter;
729
730     return $numInstanceProperties > 0 || $hasComplexGetter;
731 }
732
733 sub PrototypeOverridesGetOwnPropertySlot
734 {
735     my $interface = shift;
736     my $numPrototypeProperties = PrototypePropertyCount($interface);
737     my $numConstants = @{$interface->constants};
738     return $numConstants > 0 || $numPrototypeProperties > 0;
739 }
740
741 sub InstanceOverridesPutImplementation
742 {
743     my $interface = shift;
744     return $interface->extendedAttributes->{"CustomNamedSetter"}
745         || $interface->extendedAttributes->{"CustomIndexedSetter"};
746 }
747
748 sub InstanceOverridesPutDeclaration
749 {
750     my $interface = shift;
751     return $interface->extendedAttributes->{"CustomPutFunction"}
752         || $interface->extendedAttributes->{"CustomNamedSetter"}
753         || $interface->extendedAttributes->{"CustomIndexedSetter"};
754 }
755
756 sub InstanceNeedsVisitChildren
757 {
758     my $interface = shift;
759     return $interface->extendedAttributes->{"JSCustomMarkFunction"}
760         || $codeGenerator->InheritsInterface($interface, "EventTarget")
761         || $interface->name eq "EventTarget"
762         || $interface->extendedAttributes->{"ReportExtraMemoryCost"}
763         || IsJSBuiltinConstructor($interface)
764 }
765
766 sub GetImplClassName
767 {
768     my $name = shift;
769
770     return "DOMWindow" if $name eq "AbstractView";
771
772     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($name);
773     return $svgNativeType if $svgNativeType;
774
775     return $name;
776 }
777
778 sub IsClassNameWordBoundary
779 {
780     my ($name, $i) = @_;
781
782     # Interpret negative numbers as distance from end of string, just as the substr function does.
783     $i += length($name) if $i < 0;
784
785     return 0 if $i < 0;
786     return 1 if $i == 0;
787     return 1 if $i == length($name);
788     return 0 if $i > length($name);
789
790     my $checkString = substr($name, $i - 1);
791     return $checkString =~ /^[^A-Z][A-Z]/ || $checkString =~ /^[A-Z][A-Z][^A-Z]/;
792 }
793
794 sub IsPrefixRemovable
795 {
796     my ($class, $name, $i) = @_;
797
798     return IsClassNameWordBoundary($name, $i)
799         && (IsClassNameWordBoundary($class, $i) && substr($class, 0, $i) eq substr($name, 0, $i)
800             || IsClassNameWordBoundary($class, -$i) && substr($class, -$i) eq substr($name, 0, $i));
801 }
802
803 sub GetNestedClassName
804 {
805     my ($interface, $name) = @_;
806
807     my $class = GetImplClassName($interface->name);
808     my $member = $codeGenerator->WK_ucfirst($name);
809
810     # Since the enumeration name will be nested in the class name's namespace, remove any words
811     # that happen to match the start or end of the class name. If an enumeration is named TrackType or
812     # TextTrackType, and the class is named TextTrack, then we will get a name like TextTrack::Type.
813     my $memberLength = length($member);
814     my $longestPrefixLength = 0;
815     if ($member =~ /^[A-Z]./) {
816         for (my $i = 2; $i < $memberLength - 1; $i++) {
817             $longestPrefixLength = $i if IsPrefixRemovable($class, $member, $i);
818         }
819     }
820     $member = substr($member, $longestPrefixLength);
821
822     return "${class}::$member";
823 }
824
825 sub GetEnumerationClassName
826 {
827     my ($interface, $name) = @_;
828
829     return GetNestedClassName($interface, $name);
830 }
831
832 sub GetEnumerationValueName
833 {
834     my ($name) = @_;
835
836     return "EmptyString" if $name eq "";
837     $name = join("", map { $codeGenerator->WK_ucfirst($_) } split("-", $name));
838     $name = "_$name" if $name =~ /^\d/;
839     return $name;
840 }
841
842 sub GenerateEnumerationImplementationContent
843 {
844     my ($interface, $enumerations) = @_;
845
846     return "" unless @$enumerations;
847
848     # FIXME: Could optimize this to only generate the parts of each enumeration that are actually
849     # used, which would require iterating over everything in the interface.
850
851     my $result = "";
852
853     $result .= "template<typename T> Optional<T> parse(ExecState&, JSValue);\n";
854     $result .= "template<typename T> const char* expectedEnumerationValues();\n\n";
855
856     foreach my $enumeration (@$enumerations) {
857         my $name = $enumeration->name;
858
859         my $className = GetEnumerationClassName($interface, $name);
860
861         # FIXME: A little ugly to have this be a side effect instead of a return value.
862         AddToImplIncludes("<runtime/JSString.h>");
863
864         my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
865         $result .= "#if ${conditionalString}\n\n" if $conditionalString;
866
867         # Declare this instead of using "static" because it may be unused and we don't
868         # want to get warnings about it.
869         $result .= "JSString* jsStringWithCache(ExecState*, $className);\n";
870
871         # Take an ExecState* instead of an ExecState& to match the jsStringWithCache from JSString.h.
872         # FIXME: Change to take VM& instead of ExecState*.
873         $result .= "JSString* jsStringWithCache(ExecState* state, $className enumerationValue)\n";
874         $result .= "{\n";
875         # FIXME: Might be nice to make this global be "const", but NeverDestroyed does not currently support that.
876         # FIXME: Might be nice to make the entire array be NeverDestroyed instead of each value, but not sure the syntax for that.
877         $result .= "    static NeverDestroyed<const String> values[] = {\n";
878         foreach my $value (@{$enumeration->values}) {
879             if ($value eq "") {
880                 $result .= "        emptyString(),\n";
881             } else {
882                 $result .= "        ASCIILiteral(\"$value\"),\n";
883             }
884         }
885         $result .= "    };\n";
886         my $index = 0;
887         foreach my $value (@{$enumeration->values}) {
888             my $enumerationValueName = GetEnumerationValueName($value);
889             $result .= "    static_assert(static_cast<size_t>(${className}::$enumerationValueName) == $index, \"${className}::$enumerationValueName is not $index as expected\");\n";
890             $index++;
891         }
892         $result .= "    ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values));\n";
893         $result .= "    return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);\n";
894         $result .= "}\n\n";
895
896         $result .= "template<> struct JSValueTraits<$className> {\n";
897         $result .= "    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, $className value) { return jsStringWithCache(state, value); }\n";
898         $result .= "};\n\n";
899
900         # FIXME: Change to take VM& instead of ExecState&.
901         # FIXME: Consider using toStringOrNull to make exception checking faster.
902         # FIXME: Consider finding a more efficient way to match against all the strings quickly.
903         $result .= "template<> Optional<$className> parse<$className>(ExecState& state, JSValue value)\n";
904         $result .= "{\n";
905         $result .= "    auto stringValue = value.toWTFString(&state);\n";
906         foreach my $value (@{$enumeration->values}) {
907             my $enumerationValueName = GetEnumerationValueName($value);
908             if ($value eq "") {
909                 $result .= "    if (stringValue.isEmpty())\n";
910             } else {
911                 $result .= "    if (stringValue == \"$value\")\n";
912             }
913             $result .= "        return ${className}::${enumerationValueName};\n";
914         }
915         $result .= "    return Nullopt;\n";
916         $result .= "}\n\n";
917
918         # FIXME: A little ugly to have this be a side effect instead of a return value.
919         AddToImplIncludes("JSDOMConvert.h");
920
921         $result .= "template<> $className convert<$className>(ExecState& state, JSValue value)\n";
922         $result .= "{\n";
923         $result .= "    auto result = parse<$className>(state, value);\n";
924         $result .= "    if (UNLIKELY(!result)) {\n";
925         $result .= "        throwTypeError(&state);\n";
926         $result .= "        return { };\n";
927         $result .= "    }\n";
928         $result .= "    return result.value();\n";
929         $result .= "}\n\n";
930
931         $result .= "template<> inline const char* expectedEnumerationValues<$className>()\n";
932         $result .= "{\n";
933         $result .= "    return \"\\\"" . join ("\\\", \\\"", @{$enumeration->values}) . "\\\"\";\n";
934         $result .= "}\n\n";
935
936         $result .= "#endif\n\n" if $conditionalString;
937     }
938     return $result;
939 }
940
941 sub GetDictionaryClassName
942 {
943     my ($interface, $name) = @_;
944
945     return GetNestedClassName($interface, $name);
946 }
947
948 sub GenerateDictionaryImplementationContent
949 {
950     my ($interface, $dictionaries) = @_;
951
952     my $result = "";
953     foreach my $dictionary (@$dictionaries) {
954         my $name = $dictionary->name;
955
956         my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
957         $result .= "#if ${conditionalString}\n\n" if $conditionalString;
958
959         my $className = GetDictionaryClassName($interface, $name);
960
961         # FIXME: A little ugly to have this be a side effect instead of a return value.
962         AddToImplIncludes("JSDOMConvert.h");
963
964         $result .= "template<> $className convert<$className>(ExecState& state, JSValue value)\n";
965         $result .= "{\n";
966         my $needExceptionCheck = 0;
967         foreach my $member (@{$dictionary->members}) {
968             if ($needExceptionCheck) {
969                 $result .= "    if (UNLIKELY(state.hadException()))\n";
970                 $result .= "        return { };\n";
971             }
972             # FIXME: Eventually we will want this to call JSValueToNative.
973             my $function = $member->isOptional ? "convertOptional" : "convert";
974             my $defaultValueWithLeadingComma = $member->isOptional ? ", " . $member->default : "";
975             $result .= "    auto " . $member->name . " = " . $function . "<" . GetNativeTypeFromSignature($interface, $member) . ">"
976                 . "(state, propertyValue(state, value, \"" . $member->name . "\")" . $defaultValueWithLeadingComma . ");\n";
977             $needExceptionCheck = 1;
978         }
979         $result .= "    return { ";
980         my $comma = "";
981         foreach my $member (@{$dictionary->members}) {
982             $result .= $comma . "WTFMove(" . $member->name . ")";
983             $comma = ", ";
984         }
985         $result .= " };\n";
986         $result .= "}\n\n";
987
988         $result .= "#endif\n\n" if $conditionalString;
989     }
990     return $result;
991 }
992
993 sub GenerateHeader
994 {
995     my ($object, $interface) = @_;
996
997     my $interfaceName = $interface->name;
998     my $className = "JS$interfaceName";
999     my %structureFlags = ();
1000
1001     my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
1002     my $hasRealParent = $interface->parent;
1003     my $hasParent = $hasLegacyParent || $hasRealParent;
1004     my $parentClassName = GetParentClassName($interface);
1005     my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
1006
1007     # - Add default header template and header protection
1008     push(@headerContentHeader, GenerateHeaderContentHeader($interface));
1009
1010     if ($hasParent) {
1011         $headerIncludes{"$parentClassName.h"} = 1;
1012     } else {
1013         $headerIncludes{"JSDOMWrapper.h"} = 1;
1014         if ($interface->isException) {
1015             $headerIncludes{"<runtime/ErrorPrototype.h>"} = 1;
1016         }
1017     }
1018
1019     if ($interface->extendedAttributes->{"CustomCall"}) {
1020         $headerIncludes{"<runtime/CallData.h>"} = 1;
1021     }
1022
1023     if ($hasParent && $interface->extendedAttributes->{"JSGenerateToNativeObject"}) {
1024         $headerIncludes{"$interfaceName.h"} = 1;
1025     }
1026     
1027     $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
1028
1029     my $implType = GetImplClassName($interfaceName);
1030     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($interfaceName);
1031     my $svgPropertyOrListPropertyType;
1032     $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
1033     $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
1034
1035     my $numConstants = @{$interface->constants};
1036     my $numAttributes = @{$interface->attributes};
1037     my $numFunctions = @{$interface->functions};
1038
1039     push(@headerContent, "\nnamespace WebCore {\n\n");
1040
1041     if ($codeGenerator->IsSVGAnimatedType($interfaceName)) {
1042         $headerIncludes{"$interfaceName.h"} = 1;
1043     } else {
1044         # Implementation class forward declaration
1045         if (IsDOMGlobalObject($interface)) {
1046             AddClassForwardIfNeeded($interfaceName) unless $svgPropertyOrListPropertyType;
1047         }
1048     }
1049
1050     AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow";
1051     AddClassForwardIfNeeded("JSDictionary") if $codeGenerator->IsConstructorTemplate($interface, "Event");
1052
1053     my $exportMacro = GetExportMacroForJSClass($interface);
1054
1055     # Class declaration
1056     push(@headerContent, "class $exportMacro$className : public $parentClassName {\n");
1057
1058     # Static create methods
1059     push(@headerContent, "public:\n");
1060     push(@headerContent, "    typedef $parentClassName Base;\n");
1061     if ($interfaceName eq "DOMWindow") {
1062         push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* windowShell)\n");
1063         push(@headerContent, "    {\n");
1064         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl), windowShell);\n");
1065         push(@headerContent, "        ptr->finishCreation(vm, windowShell);\n");
1066         push(@headerContent, "        vm.heap.addFinalizer(ptr, destroy);\n");
1067         push(@headerContent, "        return ptr;\n");
1068         push(@headerContent, "    }\n\n");
1069     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1070         push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl)\n");
1071         push(@headerContent, "    {\n");
1072         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl));\n");
1073         push(@headerContent, "        ptr->finishCreation(vm);\n");
1074         push(@headerContent, "        vm.heap.addFinalizer(ptr, destroy);\n");
1075         push(@headerContent, "        return ptr;\n");
1076         push(@headerContent, "    }\n\n");
1077     } elsif ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
1078         AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
1079         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
1080         push(@headerContent, "    {\n");
1081         push(@headerContent, "        globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(\"Allocated masquerading object\");\n");
1082         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
1083         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1084         push(@headerContent, "        return ptr;\n");
1085         push(@headerContent, "    }\n\n");
1086     } elsif (!NeedsImplementationClass($interface)) {
1087         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject)\n");
1088         push(@headerContent, "    {\n");
1089         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject);\n");
1090         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1091         push(@headerContent, "        return ptr;\n");
1092         push(@headerContent, "    }\n\n");  
1093     } else {
1094         AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
1095         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
1096         push(@headerContent, "    {\n");
1097         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
1098         push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
1099         push(@headerContent, "        return ptr;\n");
1100         push(@headerContent, "    }\n\n");
1101     }
1102
1103     if (IsDOMGlobalObject($interface)) {
1104         push(@headerContent, "    static const bool needsDestruction = false;\n\n");
1105     }
1106
1107     my $hasStaticPropertyTable = InstancePropertyCount($interface) > 0 ? "true" : "false";
1108     push(@headerContent, "    static const bool hasStaticPropertyTable = $hasStaticPropertyTable;\n\n");
1109
1110     # Prototype
1111     unless (IsDOMGlobalObject($interface)) {
1112         push(@headerContent, "    static JSC::JSObject* createPrototype(JSC::VM&, JSC::JSGlobalObject*);\n");
1113         push(@headerContent, "    static JSC::JSObject* prototype(JSC::VM&, JSC::JSGlobalObject*);\n");
1114     }
1115
1116     # JSValue to implementation type
1117     if (ShouldGenerateToWrapped($hasParent, $interface)) {
1118         if ($interfaceName eq "NodeFilter") {
1119             push(@headerContent, "    static RefPtr<NodeFilter> toWrapped(JSC::VM&, JSC::JSValue);\n");
1120         } elsif ($interfaceName eq "DOMStringList") {
1121             push(@headerContent, "    static RefPtr<DOMStringList> toWrapped(JSC::ExecState*, JSC::JSValue);\n");
1122         } else {
1123             push(@headerContent, "    static $implType* toWrapped(JSC::JSValue);\n");
1124         }
1125     }
1126
1127     $headerTrailingIncludes{"${className}Custom.h"} = 1 if $interface->extendedAttributes->{"JSCustomHeader"};
1128
1129     my $namedGetterFunction = GetNamedGetterFunction($interface);
1130     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
1131
1132     my $hasNamedGetter = $namedGetterFunction
1133         || $interface->extendedAttributes->{"CustomNamedGetter"};
1134
1135     my $hasComplexGetter =
1136         $indexedGetterFunction
1137         || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
1138         || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
1139         || $hasNamedGetter;
1140     
1141     my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
1142
1143     if ($hasNamedGetter) {
1144         if ($interface->extendedAttributes->{"OverrideBuiltins"}) {
1145             $structureFlags{"JSC::GetOwnPropertySlotIsImpure"} = 1;
1146         } else {
1147             $structureFlags{"JSC::GetOwnPropertySlotIsImpureForPropertyAbsence"} = 1;
1148         }
1149     }
1150     if ($interface->extendedAttributes->{"NewImpurePropertyFiresWatchpoints"}) {
1151         $structureFlags{"JSC::NewImpurePropertyFiresWatchpoints"} = 1;
1152     }
1153     if ($interface->extendedAttributes->{"CustomCall"}) {
1154         $structureFlags{"JSC::TypeOfShouldCallGetCallData"} = 1;
1155     }
1156
1157     # Getters
1158     if ($hasGetter) {
1159         push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
1160         push(@headerContent, "    bool getOwnPropertySlotDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n") if $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"};
1161         $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
1162
1163         if ($hasComplexGetter) {
1164             push(@headerContent, "    static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n");
1165             $structureFlags{"JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero"} = 1;
1166         }
1167     }
1168
1169     my $overridesPut = InstanceOverridesPutDeclaration($interface);
1170
1171     # Getters
1172     if ($overridesPut) {
1173         push(@headerContent, "    static bool put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1174         push(@headerContent, "    static bool putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n");
1175         push(@headerContent, "    bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&, bool& putResult);\n") if $interface->extendedAttributes->{"CustomNamedSetter"};
1176     }
1177
1178     if (!$hasParent) {
1179         push(@headerContent, "    static void destroy(JSC::JSCell*);\n");
1180     }
1181
1182     # Class info
1183     if ($interfaceName eq "Node") {
1184         push(@headerContent, "\n");
1185         push(@headerContent, "protected:\n");
1186         push(@headerContent, "    static const JSC::ClassInfo s_info;\n");
1187         push(@headerContent, "public:\n");
1188         push(@headerContent, "    static const JSC::ClassInfo* info() { return &s_info; }\n\n");
1189     } else {
1190         push(@headerContent, "\n");
1191         push(@headerContent, "    DECLARE_INFO;\n\n");
1192     }
1193     # Structure ID
1194     if ($interfaceName eq "DOMWindow") {
1195         $structureFlags{"JSC::ImplementsHasInstance | JSC::ImplementsDefaultHasInstance"} = 1;
1196     }
1197     push(@headerContent, "    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
1198     push(@headerContent, "    {\n");
1199     if (IsDOMGlobalObject($interface)) {
1200         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info());\n");
1201     } elsif ($codeGenerator->InheritsInterface($interface, "Document")) {
1202         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSDocumentWrapperType), StructureFlags), info());\n");
1203     } elsif ($codeGenerator->InheritsInterface($interface, "Element")) {
1204         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSElementType), StructureFlags), info());\n");
1205     } elsif ($codeGenerator->InheritsInterface($interface, "Node")) {
1206         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSNodeType), StructureFlags), info());\n");
1207     } else {
1208         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n");
1209     }
1210     push(@headerContent, "    }\n\n");
1211
1212     # Custom pushEventHandlerScope function
1213     push(@headerContent, "    JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{"JSCustomPushEventHandlerScope"};
1214
1215     # Custom call functions
1216     push(@headerContent, "    static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $interface->extendedAttributes->{"CustomCall"};
1217
1218     # Custom deleteProperty function
1219     push(@headerContent, "    static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
1220     push(@headerContent, "    static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
1221
1222     # Custom getPropertyNames function exists on DOMWindow
1223     if ($interfaceName eq "DOMWindow") {
1224         push(@headerContent, "    static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1225         push(@headerContent, "    static void getGenericPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1226         push(@headerContent, "    static void getStructurePropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1227         push(@headerContent, "    static uint32_t getEnumerableLength(JSC::ExecState*, JSC::JSObject*);\n");
1228         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
1229     }
1230
1231     # Custom getOwnPropertyNames function
1232     if ($interface->extendedAttributes->{"CustomEnumerateProperty"} || $indexedGetterFunction || $namedGetterFunction) {
1233         push(@headerContent, "    static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
1234         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;       
1235     }
1236
1237     # Custom defineOwnProperty function
1238     push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnProperty"};
1239
1240     # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
1241     if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
1242         $structureFlags{"JSC::MasqueradesAsUndefined"} = 1;
1243     }
1244
1245     # Constructor object getter
1246     unless ($interface->extendedAttributes->{"NoInterfaceObject"}) {
1247         push(@headerContent, "    static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);\n");
1248         push(@headerContent, "    static JSC::JSValue getNamedConstructor(JSC::VM&, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{"NamedConstructor"};
1249     }
1250
1251     my $numCustomFunctions = 0;
1252     my $numCustomAttributes = 0;
1253
1254     my $hasForwardDeclaringFunctions = 0;
1255     my $hasForwardDeclaringAttributes = 0;
1256
1257     # Attribute and function enums
1258     if ($numAttributes > 0) {
1259         foreach (@{$interface->attributes}) {
1260             my $attribute = $_;
1261             $numCustomAttributes++ if HasCustomGetter($attribute->signature->extendedAttributes);
1262             $numCustomAttributes++ if HasCustomSetter($attribute->signature->extendedAttributes);
1263             if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
1264                 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1265                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1266                 push(@headerContent, "    mutable JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->signature->name . ";\n");
1267                 $numCachedAttributes++;
1268                 $needsVisitChildren = 1;
1269                 push(@headerContent, "#endif\n") if $conditionalString;
1270             }
1271
1272             if ($attribute->signature->extendedAttributes->{"ForwardDeclareInHeader"}) {
1273                 $hasForwardDeclaringAttributes = 1;
1274             }
1275         }
1276     }
1277
1278     # visit function
1279     if ($needsVisitChildren) {
1280         push(@headerContent, "    static void visitChildren(JSCell*, JSC::SlotVisitor&);\n");
1281         push(@headerContent, "    void visitAdditionalChildren(JSC::SlotVisitor&);\n") if $interface->extendedAttributes->{"JSCustomMarkFunction"};
1282         push(@headerContent, "\n");
1283     }
1284
1285     if ($numCustomAttributes > 0) {
1286         push(@headerContent, "\n    // Custom attributes\n");
1287
1288         foreach my $attribute (@{$interface->attributes}) {
1289             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1290             if (HasCustomGetter($attribute->signature->extendedAttributes)) {
1291                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1292                 my $methodName = $codeGenerator->WK_lcfirst($attribute->signature->name);
1293                 push(@headerContent, "    JSC::JSValue " . $methodName . "(JSC::ExecState&) const;\n");
1294                 push(@headerContent, "#endif\n") if $conditionalString;
1295             }
1296             if (HasCustomSetter($attribute->signature->extendedAttributes) && !IsReadonly($attribute)) {
1297                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1298                 push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState&, JSC::JSValue);\n");
1299                 push(@headerContent, "#endif\n") if $conditionalString;
1300             }
1301         }
1302     }
1303
1304     foreach my $function (@{$interface->functions}) {
1305         $numCustomFunctions++ if HasCustomMethod($function->signature->extendedAttributes);
1306
1307         if ($function->signature->extendedAttributes->{"ForwardDeclareInHeader"}) {
1308             $hasForwardDeclaringFunctions = 1;
1309         }
1310     }
1311
1312     if ($numCustomFunctions > 0) {
1313         my $inAppleCopyright = 0;
1314         push(@headerContent, "\n    // Custom functions\n");
1315         foreach my $function (@{$interface->functions}) {
1316             my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
1317             if ($needsAppleCopyright) {
1318                 if (!$inAppleCopyright) {
1319                     push(@headerContent, $beginAppleCopyrightForHeaderFiles);
1320                     $inAppleCopyright = 1;
1321                 }
1322             } elsif ($inAppleCopyright) {
1323                 push(@headerContent, $endAppleCopyright);
1324                 $inAppleCopyright = 0;
1325             }
1326             next unless HasCustomMethod($function->signature->extendedAttributes);
1327             next if $function->{overloads} && $function->{overloadIndex} != 1;
1328             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1329             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1330             my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
1331             push(@headerContent, "    " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState&);\n");
1332             push(@headerContent, "#endif\n") if $conditionalString;
1333         }
1334         push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
1335     }
1336
1337     if (NeedsImplementationClass($interface)) {
1338         if ($hasParent) {
1339             push(@headerContent, "    $interfaceName& wrapped() const\n");
1340             push(@headerContent, "    {\n");
1341             push(@headerContent, "        return static_cast<$interfaceName&>(Base::wrapped());\n");
1342             push(@headerContent, "    }\n");
1343         }
1344     }
1345
1346     # structure flags
1347     if (%structureFlags) {
1348         push(@headerContent, "public:\n");
1349         push(@headerContent, "    static const unsigned StructureFlags = ");
1350         foreach my $structureFlag (sort (keys %structureFlags)) {
1351             push(@headerContent, $structureFlag . " | ");
1352         }
1353         push(@headerContent, "Base::StructureFlags;\n");
1354     }
1355
1356     push(@headerContent, "protected:\n");
1357
1358     # Constructor
1359     if ($interfaceName eq "DOMWindow") {
1360         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&, JSDOMWindowShell*);\n");
1361     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1362         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&);\n");
1363     } elsif (!NeedsImplementationClass($interface)) {
1364         push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject&);\n\n");
1365      } else {
1366         push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject&, Ref<$implType>&&);\n\n");
1367         push(@headerContent, "    void finishCreation(JSC::VM& vm)\n");
1368         push(@headerContent, "    {\n");
1369         push(@headerContent, "        Base::finishCreation(vm);\n");
1370         push(@headerContent, "        ASSERT(inherits(info()));\n");
1371         push(@headerContent, "    }\n\n");
1372     }
1373
1374     if (IsDOMGlobalObject($interface)) {
1375         if ($interfaceName eq "DOMWindow") {
1376             push(@headerContent, "    void finishCreation(JSC::VM&, JSDOMWindowShell*);\n");
1377         } else {
1378             push(@headerContent, "    void finishCreation(JSC::VM&);\n");
1379         }
1380     }
1381
1382     # Index setter
1383     if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
1384         push(@headerContent, "    void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
1385     }
1386     # Name getter
1387     if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
1388         push(@headerContent, "private:\n");
1389         push(@headerContent, "    bool nameGetter(JSC::ExecState*, JSC::PropertyName, JSC::JSValue&);\n");
1390     }
1391
1392     push(@headerContent, "};\n\n");
1393
1394     if (ShouldGenerateWrapperOwnerCode($hasParent, $interface)) {
1395         if ($interfaceName ne "Node" && $codeGenerator->InheritsInterface($interface, "Node")) {
1396             $headerIncludes{"JSNode.h"} = 1;
1397             push(@headerContent, "class JS${interfaceName}Owner : public JSNodeOwner {\n");
1398         } else {
1399             push(@headerContent, "class JS${interfaceName}Owner : public JSC::WeakHandleOwner {\n");
1400         }
1401         $headerIncludes{"<wtf/NeverDestroyed.h>"} = 1;
1402         push(@headerContent, "public:\n");
1403         push(@headerContent, "    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
1404         push(@headerContent, "    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
1405         push(@headerContent, "};\n");
1406         push(@headerContent, "\n");
1407         push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, $implType*)\n");
1408         push(@headerContent, "{\n");
1409         push(@headerContent, "    static NeverDestroyed<JS${interfaceName}Owner> owner;\n");
1410         push(@headerContent, "    return &owner.get();\n");
1411         push(@headerContent, "}\n");
1412         push(@headerContent, "\n");
1413         push(@headerContent, "inline void* wrapperKey($implType* wrappableObject)\n");
1414         push(@headerContent, "{\n");
1415         push(@headerContent, "    return wrappableObject;\n");
1416         push(@headerContent, "}\n");
1417         push(@headerContent, "\n");
1418     }
1419     if (ShouldGenerateToJSDeclaration($hasParent, $interface)) {
1420         # Node and NodeList have custom inline implementations which thus cannot be exported.
1421         # FIXME: The special case for Node and NodeList should probably be implemented via an IDL attribute.
1422         if ($implType eq "Node" or $implType eq "NodeList") {
1423             push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
1424         } else {
1425             push(@headerContent, $exportMacro."JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
1426         }
1427         push(@headerContent, "inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, $implType& impl) { return toJS(state, globalObject, &impl); }\n");
1428
1429         push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
1430     }
1431
1432     push(@headerContent, "\n");
1433
1434     GeneratePrototypeDeclaration(\@headerContent, $className, $interface) if HeaderNeedsPrototypeDeclaration($interface);
1435
1436     if ($hasForwardDeclaringFunctions) {
1437         my $inAppleCopyright = 0;
1438         push(@headerContent,"// Functions\n\n");
1439         foreach my $function (@{$interface->functions}) {
1440             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1441             next unless $function->signature->extendedAttributes->{"ForwardDeclareInHeader"};
1442
1443             my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
1444             if ($needsAppleCopyright) {
1445                 if (!$inAppleCopyright) {
1446                     push(@headerContent, $beginAppleCopyrightForHeaderFiles);
1447                     $inAppleCopyright = 1;
1448                 }
1449             } elsif ($inAppleCopyright) {
1450                 push(@headerContent, $endAppleCopyright);
1451                 $inAppleCopyright = 0;
1452             }
1453
1454             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1455             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1456             my $functionName = GetFunctionName($interface, $className, $function);
1457             push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
1458             push(@headerContent, "#endif\n") if $conditionalString;
1459         }
1460
1461         push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
1462         push(@headerContent,"\n");
1463     }
1464
1465     if ($hasForwardDeclaringAttributes) {
1466         push(@headerContent,"// Attributes\n\n");
1467         foreach my $attribute (@{$interface->attributes}) {
1468             next unless $attribute->signature->extendedAttributes->{"ForwardDeclareInHeader"};
1469
1470             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1471             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1472             my $getter = GetAttributeGetterName($interface, $className, $attribute);
1473             push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
1474             if (!IsReadonly($attribute)) {
1475                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
1476                 push(@headerContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
1477             }
1478             push(@headerContent, "#endif\n") if $conditionalString;
1479         }
1480     }
1481
1482     if (HasCustomConstructor($interface)) {
1483         push(@headerContent, "// Custom constructor\n");
1484         push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState*);\n\n");
1485     }
1486
1487     if ($codeGenerator->IsConstructorTemplate($interface, "Event")) {
1488         push(@headerContent, "bool fill${interfaceName}Init(${interfaceName}Init&, JSDictionary&);\n\n");
1489     }
1490
1491     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
1492     push(@headerContent, "\n} // namespace WebCore\n");
1493     push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
1494
1495     if ($interface->extendedAttributes->{"AppleCopyright"}) {
1496         push(@headerContent, "\n");
1497         push(@headerContent, split("\r", $endAppleCopyright));
1498     }
1499 }
1500
1501 sub GeneratePropertiesHashTable
1502 {
1503     my ($object, $interface, $isInstance, $hashKeys, $hashSpecials, $hashValue1, $hashValue2, $conditionals, $runtimeEnabledFunctions, $runtimeEnabledAttributes) = @_;
1504
1505     # FIXME: These should be functions on $interface.
1506     my $interfaceName = $interface->name;
1507     my $className = "JS$interfaceName";
1508     
1509     # - Add all properties in a hashtable definition
1510     my $propertyCount = $isInstance ? InstancePropertyCount($interface) : PrototypePropertyCount($interface);
1511
1512     if (!$isInstance && NeedsConstructorProperty($interface)) {
1513         die if !$propertyCount;
1514         push(@$hashKeys, "constructor");
1515         my $getter = "js" . $interfaceName . "Constructor";
1516         push(@$hashValue1, $getter);
1517
1518         my $setter = "setJS" . $interfaceName . "Constructor";
1519         push(@$hashValue2, $setter);
1520         push(@$hashSpecials, "DontEnum");
1521     }
1522
1523     return 0 if !$propertyCount;
1524
1525     foreach my $attribute (@{$interface->attributes}) {
1526         next if ($attribute->isStatic);
1527         next if AttributeShouldBeOnInstance($interface, $attribute) != $isInstance;
1528
1529         # Global objects add RuntimeEnabled attributes after creation so do not add them to the static table.
1530         if (IsDOMGlobalObject($interface) && $attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1531             $propertyCount -= 1;
1532             next;
1533         }
1534
1535         my $name = $attribute->signature->name;
1536         push(@$hashKeys, $name);
1537
1538         my $special = GetJSCAttributesForAttribute($interface, $attribute);
1539         push(@$hashSpecials, $special);
1540
1541         my $getter = GetAttributeGetterName($interface, $className, $attribute);
1542         push(@$hashValue1, $getter);
1543
1544         if (IsReadonly($attribute)) {
1545             push(@$hashValue2, "0");
1546         } else {
1547             my $setter = GetAttributeSetterName($interface, $className, $attribute);
1548             push(@$hashValue2, $setter);
1549         }
1550
1551         my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
1552         if ($conditional) {
1553             $conditionals->{$name} =  $conditional;
1554         }
1555
1556         if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1557             if ($isInstance) {
1558                 die "We currently do not support [EnabledAtRuntime] attributes on the instance (except for global objects).";
1559             } else {
1560                 push(@$runtimeEnabledAttributes, $attribute);
1561             }
1562         }
1563     }
1564
1565     my @functions = @{$interface->functions};
1566     push(@functions, @{$interface->iterable->functions}) if $interface->iterable;
1567     foreach my $function (@functions) {
1568         next if ($function->signature->extendedAttributes->{"Private"});
1569         next if ($function->isStatic);
1570         next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1571         next if OperationShouldBeOnInstance($interface, $function) != $isInstance;
1572         next if $function->signature->name eq "[Symbol.Iterator]";
1573
1574         # Global objects add RuntimeEnabled operations after creation so do not add them to the static table.
1575         if (IsDOMGlobalObject($interface) && $function->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1576             $propertyCount -= 1;
1577             next;
1578         }
1579
1580         my $name = $function->signature->name;
1581         push(@$hashKeys, $name);
1582
1583         my $functionName = GetFunctionName($interface, $className, $function);
1584         push(@$hashValue1, $functionName);
1585
1586         my $functionLength = GetFunctionLength($function);
1587         push(@$hashValue2, $functionLength);
1588
1589         push(@$hashSpecials, ComputeFunctionSpecial($interface, $function));
1590
1591         my $conditional = $function->signature->extendedAttributes->{"Conditional"};
1592         if ($conditional) {
1593             $conditionals->{$name} = $conditional;
1594         }
1595
1596         if ($function->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1597             if ($isInstance) {
1598                 die "We currently do not support [EnabledAtRuntime] operations on the instance (except for global objects).";
1599             } else {
1600                 push(@$runtimeEnabledFunctions, $function);
1601             }
1602         }
1603     }
1604
1605     return $propertyCount;
1606 }
1607
1608 sub GenerateParametersCheckExpression
1609 {
1610     my $numParameters = shift;
1611     my $function = shift;
1612
1613     my @andExpression = ();
1614     push(@andExpression, "argsCount == $numParameters");
1615     my $parameterIndex = 0;
1616     my %usedArguments = ();
1617     foreach my $parameter (@{$function->parameters}) {
1618         last if $parameterIndex >= $numParameters;
1619         my $value = "arg$parameterIndex";
1620         my $type = $parameter->type;
1621
1622         # Only DOMString or wrapper types are checked.
1623         # For DOMString with StrictTypeChecking only Null, Undefined and Object
1624         # are accepted for compatibility. Otherwise, no restrictions are made to
1625         # match the non-overloaded behavior.
1626         # FIXME: Implement WebIDL overload resolution algorithm.
1627         if ($type eq "DOMString" || $codeGenerator->IsEnumType($type)) {
1628             if ($parameter->extendedAttributes->{"StrictTypeChecking"}) {
1629                 push(@andExpression, "(${value}.isUndefinedOrNull() || ${value}.isString() || ${value}.isObject())");
1630                 $usedArguments{$parameterIndex} = 1;
1631             }
1632         } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) {
1633             # For Callbacks only checks if the value is null or object.
1634             if ($codeGenerator->IsFunctionOnlyCallbackInterface($parameter->type)) {
1635                 push(@andExpression, "(${value}.isNull() || ${value}.isFunction())");
1636             } else {
1637                 push(@andExpression, "(${value}.isNull() || ${value}.isObject())");
1638             }
1639             $usedArguments{$parameterIndex} = 1;
1640         } elsif (!IsNativeType($type)) {
1641             my $condition = "";
1642             $condition .= "${value}.isUndefined() || " if $parameter->isOptional;
1643
1644             # FIXME: WebIDL says that undefined is also acceptable for nullable parameters and
1645             # should be converted to null:
1646             # http://heycam.github.io/webidl/#es-nullable-type
1647             $condition .= "${value}.isNull() || " if $parameter->isNullable;
1648
1649             if ($codeGenerator->GetArrayOrSequenceType($type)) {
1650                 # FIXME: Add proper support for T[], T[]?, sequence<T>.
1651                 $condition .= "(${value}.isObject() && isJSArray(${value}))";
1652             } else {
1653                 $condition .= "(${value}.isObject() && asObject(${value})->inherits(JS${type}::info()))";
1654             }
1655             push(@andExpression, "(" . $condition . ")");
1656             $usedArguments{$parameterIndex} = 1;
1657         }
1658         $parameterIndex++;
1659     }
1660     my $res = join(" && ", @andExpression);
1661     $res = "($res)" if @andExpression > 1;
1662     return ($res, sort {$a <=> $b} (keys %usedArguments));
1663 }
1664
1665 # As per Web IDL specification, the length of a function Object is its number of mandatory parameters.
1666 sub GetFunctionLength
1667 {
1668     my $function = shift;
1669
1670     my $length = 0;
1671     foreach my $parameter (@{$function->parameters}) {
1672         # Abort as soon as we find the first optional parameter as no mandatory
1673         # parameter can follow an optional one.
1674         last if $parameter->isOptional || $parameter->isVariadic;
1675         $length++;
1676     }
1677     return $length;
1678 }
1679
1680 sub GenerateFunctionParametersCheck
1681 {
1682     my $function = shift;
1683
1684     my @orExpression = ();
1685     my $numParameters = 0;
1686     my @neededArguments = ();
1687     my $hasVariadic = 0;
1688     my $numMandatoryParams = @{$function->parameters};
1689
1690     foreach my $parameter (@{$function->parameters}) {
1691         if ($parameter->isOptional) {
1692             my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1693             push(@orExpression, $expression);
1694             push(@neededArguments, @usedArguments);
1695             $numMandatoryParams--;
1696         }
1697         if ($parameter->isVariadic) {
1698             $hasVariadic = 1;
1699             last;
1700         }
1701         $numParameters++;
1702     }
1703     if (!$hasVariadic) {
1704         my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1705         push(@orExpression, $expression);
1706         push(@neededArguments, @usedArguments);
1707     }
1708     return ($numMandatoryParams, join(" || ", @orExpression), @neededArguments);
1709 }
1710
1711 sub LengthOfLongestFunctionParameterList
1712 {
1713     my ($overloads) = @_;
1714     my $result = 0;
1715     foreach my $overload (@{$overloads}) {
1716         my @parameters = @{$overload->parameters};
1717         $result = @parameters if $result < @parameters;
1718     }
1719     return $result;
1720 }
1721
1722 sub GenerateOverloadedFunction
1723 {
1724     my ($function, $interface) = @_;
1725
1726     # Generate code for choosing the correct overload to call. Overloads are
1727     # chosen based on the total number of arguments passed and the type of
1728     # values passed in non-primitive argument slots. When more than a single
1729     # overload is applicable, precedence is given according to the order of
1730     # declaration in the IDL.
1731
1732     my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
1733     my $interfaceName = $interface->name;
1734     my $functionName = "js${interfaceName}${kind}Function" . $codeGenerator->WK_ucfirst($function->signature->name);
1735
1736     # FIXME: Implement support for overloaded functions with variadic arguments.
1737     my $lengthOfLongestOverloadedFunctionParameterList = LengthOfLongestFunctionParameterList($function->{overloads});
1738
1739     push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* state)\n");
1740     push(@implContent, <<END);
1741 {
1742     size_t argsCount = std::min<size_t>($lengthOfLongestOverloadedFunctionParameterList, state->argumentCount());
1743 END
1744
1745     my %fetchedArguments = ();
1746     my $leastNumMandatoryParams = 255;
1747
1748     foreach my $overload (@{$function->{overloads}}) {
1749         my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload);
1750         $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams);
1751
1752         foreach my $parameterIndex (@neededArguments) {
1753             next if exists $fetchedArguments{$parameterIndex};
1754             push(@implContent, "    JSValue arg$parameterIndex(state->argument($parameterIndex));\n");
1755             $fetchedArguments{$parameterIndex} = 1;
1756         }
1757
1758         my $conditionalString = $codeGenerator->GenerateConditionalString($overload->signature);
1759         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
1760
1761         push(@implContent, "    if ($parametersCheck)\n");
1762         push(@implContent, "        return ${functionName}$overload->{overloadIndex}(state);\n");
1763         push(@implContent, "#endif\n\n") if $conditionalString;
1764
1765     }
1766     if ($leastNumMandatoryParams >= 1) {
1767         push(@implContent, "    if (UNLIKELY(argsCount < $leastNumMandatoryParams))\n");
1768         push(@implContent, "        return throwVMError(state, createNotEnoughArgumentsError(state));\n");
1769     }
1770     push(@implContent, <<END);
1771     return throwVMTypeError(state);
1772 }
1773
1774 END
1775 }
1776
1777 sub GetNativeTypeForConversions
1778 {
1779     my $interface = shift;
1780     my $interfaceName = $interface->name;
1781     $interfaceName = $codeGenerator->GetSVGTypeNeedingTearOff($interfaceName) if $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName);
1782     return $interfaceName;
1783 }
1784
1785 # See http://refspecs.linux-foundation.org/cxxabi-1.83.html.
1786 sub GetGnuVTableRefForInterface
1787 {
1788     my $interface = shift;
1789     my $vtableName = GetGnuVTableNameForInterface($interface);
1790     if (!$vtableName) {
1791         return "0";
1792     }
1793     my $typename = GetNativeTypeForConversions($interface);
1794     my $offset = GetGnuVTableOffsetForType($typename);
1795     return "&" . $vtableName . "[" . $offset . "]";
1796 }
1797
1798 sub GetGnuVTableNameForInterface
1799 {
1800     my $interface = shift;
1801     my $typename = GetNativeTypeForConversions($interface);
1802     my $templatePosition = index($typename, "<");
1803     return "" if $templatePosition != -1;
1804     return "" if GetImplementationLacksVTableForInterface($interface);
1805     return "" if GetSkipVTableValidationForInterface($interface);
1806     return "_ZTV" . GetGnuMangledNameForInterface($interface);
1807 }
1808
1809 sub GetGnuMangledNameForInterface
1810 {
1811     my $interface = shift;
1812     my $typename = GetNativeTypeForConversions($interface);
1813     my $templatePosition = index($typename, "<");
1814     if ($templatePosition != -1) {
1815         return "";
1816     }
1817     my $mangledType = length($typename) . $typename;
1818     my $namespace = GetNamespaceForInterface($interface);
1819     my $mangledNamespace =  "N" . length($namespace) . $namespace;
1820     return $mangledNamespace . $mangledType . "E";
1821 }
1822
1823 sub GetGnuVTableOffsetForType
1824 {
1825     my $typename = shift;
1826     if ($typename eq "SVGAElement"
1827         || $typename eq "SVGCircleElement"
1828         || $typename eq "SVGClipPathElement"
1829         || $typename eq "SVGDefsElement"
1830         || $typename eq "SVGEllipseElement"
1831         || $typename eq "SVGForeignObjectElement"
1832         || $typename eq "SVGGElement"
1833         || $typename eq "SVGImageElement"
1834         || $typename eq "SVGLineElement"
1835         || $typename eq "SVGPathElement"
1836         || $typename eq "SVGPolyElement"
1837         || $typename eq "SVGPolygonElement"
1838         || $typename eq "SVGPolylineElement"
1839         || $typename eq "SVGRectElement"
1840         || $typename eq "SVGSVGElement"
1841         || $typename eq "SVGGraphicsElement"
1842         || $typename eq "SVGSwitchElement"
1843         || $typename eq "SVGTextElement"
1844         || $typename eq "SVGUseElement") {
1845         return "3";
1846     }
1847     return "2";
1848 }
1849
1850 # See http://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B_Name_Mangling.
1851 sub GetWinVTableRefForInterface
1852 {
1853     my $interface = shift;
1854     my $vtableName = GetWinVTableNameForInterface($interface);
1855     return 0 if !$vtableName;
1856     return "__identifier(\"" . $vtableName . "\")";
1857 }
1858
1859 sub GetWinVTableNameForInterface
1860 {
1861     my $interface = shift;
1862     my $typename = GetNativeTypeForConversions($interface);
1863     my $templatePosition = index($typename, "<");
1864     return "" if $templatePosition != -1;
1865     return "" if GetImplementationLacksVTableForInterface($interface);
1866     return "" if GetSkipVTableValidationForInterface($interface);
1867     return "??_7" . GetWinMangledNameForInterface($interface) . "6B@";
1868 }
1869
1870 sub GetWinMangledNameForInterface
1871 {
1872     my $interface = shift;
1873     my $typename = GetNativeTypeForConversions($interface);
1874     my $namespace = GetNamespaceForInterface($interface);
1875     return $typename . "@" . $namespace . "@@";
1876 }
1877
1878 sub GetNamespaceForInterface
1879 {
1880     my $interface = shift;
1881     return $interface->extendedAttributes->{"ImplementationNamespace"} || "WebCore";
1882 }
1883
1884 sub GetImplementationLacksVTableForInterface
1885 {
1886     my $interface = shift;
1887     return $interface->extendedAttributes->{"ImplementationLacksVTable"};
1888 }
1889
1890 sub GetSkipVTableValidationForInterface
1891 {
1892     my $interface = shift;
1893     return $interface->extendedAttributes->{"SkipVTableValidation"};
1894 }
1895
1896 # URL becomes url, but SetURL becomes setURL.
1897 sub ToMethodName
1898 {
1899     my $param = shift;
1900     my $ret = lcfirst($param);
1901     $ret =~ s/hTML/html/ if $ret =~ /^hTML/;
1902     $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
1903     $ret =~ s/jS/js/ if $ret =~ /^jS/;
1904     $ret =~ s/xML/xml/ if $ret =~ /^xML/;
1905     $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
1906     $ret =~ s/cSS/css/ if $ret =~ /^cSS/;
1907
1908     # For HTML5 FileSystem API Flags attributes.
1909     # (create is widely used to instantiate an object and must be avoided.)
1910     $ret =~ s/^create/isCreate/ if $ret =~ /^create$/;
1911     $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/;
1912
1913     return $ret;
1914 }
1915
1916 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
1917 sub GetRuntimeEnableFunctionName
1918 {
1919     my $signature = shift;
1920
1921     # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::sharedFeatures().{FeatureName}Enabled() method.
1922     return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "VALUE_IS_MISSING");
1923
1924     # Otherwise return a function named RuntimeEnabledFeatures::sharedFeatures().{methodName}Enabled().
1925     return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->name) . "Enabled";
1926 }
1927
1928 sub GetCastingHelperForThisObject
1929 {
1930     my $interface = shift;
1931     my $interfaceName = $interface->name;
1932
1933     return "jsNodeCast" if $interfaceName eq "Node";
1934     return "jsElementCast" if $interfaceName eq "Element";
1935     return "jsDocumentCast" if $interfaceName eq "Document";
1936     return "jsEventTargetCast" if $interfaceName eq "EventTarget";
1937     return "jsDynamicCast<JS$interfaceName*>";
1938 }
1939
1940 sub GetIndexedGetterExpression
1941 {
1942     my $indexedGetterFunction = shift;
1943     if ($indexedGetterFunction->signature->type eq "DOMString") {
1944         return "jsStringOrUndefined(state, thisObject->wrapped().item(index))";
1945     }
1946     return "toJS(state, thisObject->globalObject(), thisObject->wrapped().item(index))";
1947 }
1948
1949 sub GenerateImplementation
1950 {
1951     my ($object, $interface, $enumerations, $dictionaries) = @_;
1952
1953     my $interfaceName = $interface->name;
1954     my $className = "JS$interfaceName";
1955
1956     my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
1957     my $hasRealParent = $interface->parent;
1958     my $hasParent = $hasLegacyParent || $hasRealParent;
1959     my $parentClassName = GetParentClassName($interface);
1960     my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
1961     my $eventTarget = $codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->name ne "EventTarget";
1962     my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
1963
1964     my $namedGetterFunction = GetNamedGetterFunction($interface);
1965     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
1966
1967     # - Add default header template
1968     push(@implContentHeader, GenerateImplementationContentHeader($interface));
1969
1970     $implIncludes{"JSDOMBinding.h"} = 1;
1971     $implIncludes{"<wtf/GetPtr.h>"} = 1;
1972     $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $indexedGetterFunction;
1973
1974     my $implType = GetImplClassName($interfaceName);
1975
1976     AddJSBuiltinIncludesIfNeeded($interface);
1977
1978     @implContent = ();
1979
1980     push(@implContent, "\nusing namespace JSC;\n\n");
1981     push(@implContent, "namespace WebCore {\n\n");
1982
1983     push(@implContent, GenerateEnumerationImplementationContent($interface, $enumerations));
1984     push(@implContent, GenerateDictionaryImplementationContent($interface, $dictionaries));
1985
1986     my @functions = @{$interface->functions};
1987     push(@functions, @{$interface->iterable->functions}) if $interface->iterable;
1988
1989     my $numConstants = @{$interface->constants};
1990     my $numFunctions = @functions;
1991     my $numAttributes = @{$interface->attributes};
1992
1993     if ($numFunctions > 0) {
1994         my $inAppleCopyright = 0;
1995         push(@implContent,"// Functions\n\n");
1996         foreach my $function (@functions) {
1997             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1998             next if $function->signature->extendedAttributes->{"ForwardDeclareInHeader"};
1999             next if IsJSBuiltin($interface, $function);
2000
2001             my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
2002             if ($needsAppleCopyright) {
2003                 if (!$inAppleCopyright) {
2004                     push(@implContent, $beginAppleCopyrightForHeaderFiles);
2005                     $inAppleCopyright = 1;
2006                 }
2007             } elsif ($inAppleCopyright) {
2008                 push(@implContent, $endAppleCopyright);
2009                 $inAppleCopyright = 0;
2010             }
2011
2012             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2013             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2014             my $functionName = GetFunctionName($interface, $className, $function);
2015             push(@implContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
2016             push(@implContent, "#endif\n") if $conditionalString;
2017         }
2018
2019         push(@implContent, $endAppleCopyright) if $inAppleCopyright;
2020
2021         push(@implContent, "\n");
2022     }
2023
2024     if ($numAttributes > 0 || NeedsConstructorProperty($interface)) {
2025         push(@implContent, "// Attributes\n\n");
2026         foreach my $attribute (@{$interface->attributes}) {
2027             next if $attribute->signature->extendedAttributes->{"ForwardDeclareInHeader"};
2028             next if IsJSBuiltin($interface, $attribute);
2029
2030             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2031             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2032             my $getter = GetAttributeGetterName($interface, $className, $attribute);
2033             push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
2034             if (!IsReadonly($attribute)) {
2035                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
2036                 push(@implContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
2037             }
2038             push(@implContent, "#endif\n") if $conditionalString;
2039         }
2040         
2041         if (NeedsConstructorProperty($interface)) {
2042             my $getter = "js" . $interfaceName . "Constructor";
2043             push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
2044         }
2045
2046         my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2047         push(@implContent, "bool ${constructorFunctionName}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
2048
2049         push(@implContent, "\n");
2050     }
2051
2052     GeneratePrototypeDeclaration(\@implContent, $className, $interface) if !HeaderNeedsPrototypeDeclaration($interface);
2053
2054     GenerateConstructorDeclaration(\@implContent, $className, $interface) if NeedsConstructorProperty($interface);
2055
2056     my @hashKeys = ();
2057     my @hashValue1 = ();
2058     my @hashValue2 = ();
2059     my @hashSpecials = ();
2060     my %conditionals = ();
2061     my $hashName = $className . "Table";
2062     my @runtimeEnabledFunctions = ();
2063     my @runtimeEnabledAttributes = ();
2064
2065     # Generate hash table for properties on the instance.
2066     my $numInstanceProperties = GeneratePropertiesHashTable($object, $interface, 1,
2067         \@hashKeys, \@hashSpecials,
2068         \@hashValue1, \@hashValue2,
2069         \%conditionals, \@runtimeEnabledFunctions, \@runtimeEnabledAttributes);
2070
2071     $object->GenerateHashTable($hashName, $numInstanceProperties,
2072         \@hashKeys, \@hashSpecials,
2073         \@hashValue1, \@hashValue2,
2074         \%conditionals, 0) if $numInstanceProperties > 0;
2075
2076     # - Add all interface object (aka constructor) properties (constants, static attributes, static operations).
2077     if (NeedsConstructorProperty($interface)) {
2078         my $hashSize = 0;
2079         my $hashName = $className . "ConstructorTable";
2080
2081         my @hashKeys = ();
2082         my @hashValue1 = ();
2083         my @hashValue2 = ();
2084         my @hashSpecials = ();
2085         my %conditionals = ();
2086
2087         my $needsConstructorTable = 0;
2088
2089         foreach my $constant (@{$interface->constants}) {
2090             my $name = $constant->name;
2091             push(@hashKeys, $name);
2092             push(@hashValue1, $constant->value);
2093             push(@hashValue2, "0");
2094             push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
2095
2096             my $implementedBy = $constant->extendedAttributes->{"ImplementedBy"};
2097             if ($implementedBy) {
2098                 $implIncludes{"${implementedBy}.h"} = 1;
2099             }
2100             my $conditional = $constant->extendedAttributes->{"Conditional"};
2101             if ($conditional) {
2102                 $conditionals{$name} = $conditional;
2103             }
2104             
2105             $hashSize++;
2106         }
2107
2108         foreach my $attribute (@{$interface->attributes}) {
2109             next unless ($attribute->isStatic);
2110             my $name = $attribute->signature->name;
2111             push(@hashKeys, $name);
2112
2113             my @specials = ();
2114             push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
2115             push(@specials, "ReadOnly") if IsReadonly($attribute);
2116             my $special = (@specials > 0) ? join(" | ", @specials) : "0";
2117             push(@hashSpecials, $special);
2118
2119             my $getter = GetAttributeGetterName($interface, $className, $attribute);
2120             push(@hashValue1, $getter);
2121
2122             if (IsReadonly($attribute)) {
2123                 push(@hashValue2, "0");
2124             } else {
2125                 my $setter = GetAttributeSetterName($interface, $className, $attribute);
2126                 push(@hashValue2, $setter);
2127             }
2128
2129             my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
2130             if ($conditional) {
2131                 $conditionals{$name} = $conditional;
2132             }
2133
2134             $hashSize++;
2135         }
2136
2137         foreach my $function (@{$interface->functions}) {
2138             next unless ($function->isStatic);
2139             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2140             my $name = $function->signature->name;
2141             push(@hashKeys, $name);
2142
2143             my $functionName = GetFunctionName($interface, $className, $function);
2144             push(@hashValue1, $functionName);
2145
2146             my $functionLength = GetFunctionLength($function);
2147             push(@hashValue2, $functionLength);
2148
2149             push(@hashSpecials, ComputeFunctionSpecial($interface, $function));
2150
2151             my $conditional = $function->signature->extendedAttributes->{"Conditional"};
2152             if ($conditional) {
2153                 $conditionals{$name} = $conditional;
2154             }
2155             
2156             $hashSize++;
2157         }
2158
2159         $object->GenerateHashTable($hashName, $hashSize,
2160                                    \@hashKeys, \@hashSpecials,
2161                                    \@hashValue1, \@hashValue2,
2162                                    \%conditionals, 1) if $hashSize > 0;
2163
2164         push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($interface));
2165
2166         my $protoClassName = "${className}Prototype";
2167         GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $visibleInterfaceName, $interface);
2168         if ($interface->extendedAttributes->{"NamedConstructor"}) {
2169             GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interface->extendedAttributes->{"NamedConstructor"}, $interface, "GeneratingNamedConstructor");
2170         }
2171     }
2172
2173     # - Add functions and constants to a hashtable definition
2174
2175     $hashName = $className . "PrototypeTable";
2176
2177     @hashKeys = ();
2178     @hashValue1 = ();
2179     @hashValue2 = ();
2180     @hashSpecials = ();
2181     %conditionals = ();
2182     @runtimeEnabledFunctions = ();
2183     @runtimeEnabledAttributes = ();
2184
2185     # Generate hash table for properties on the prototype.
2186     my $numPrototypeProperties = GeneratePropertiesHashTable($object, $interface, 0,
2187         \@hashKeys, \@hashSpecials,
2188         \@hashValue1, \@hashValue2,
2189         \%conditionals, \@runtimeEnabledFunctions, \@runtimeEnabledAttributes);
2190     my $hashSize = $numPrototypeProperties;
2191
2192     foreach my $constant (@{$interface->constants}) {
2193         my $name = $constant->name;
2194
2195         push(@hashKeys, $name);
2196         push(@hashValue1, $constant->value);
2197         push(@hashValue2, "0");
2198         push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
2199
2200         my $conditional = $constant->extendedAttributes->{"Conditional"};
2201         if ($conditional) {
2202             $conditionals{$name} = $conditional;
2203         }
2204         
2205         $hashSize++;
2206     }
2207
2208     my $justGenerateValueArray = !IsDOMGlobalObject($interface);
2209
2210     $object->GenerateHashTable($hashName, $hashSize,
2211                                \@hashKeys, \@hashSpecials,
2212                                \@hashValue1, \@hashValue2,
2213                                \%conditionals, $justGenerateValueArray);
2214
2215     if ($justGenerateValueArray) {
2216         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
2217     } else {
2218         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, &${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
2219     }
2220
2221     if (PrototypeOverridesGetOwnPropertySlot($interface)) {
2222         my $prototypePropertyCount = PrototypePropertyCount($interface);
2223         my $prototypeFunctionCount = PrototypeFunctionCount($interface);
2224         my $prototypeAttributeCount = $prototypePropertyCount - $prototypeFunctionCount;
2225         if (IsDOMGlobalObject($interface)) {
2226             push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)\n");
2227             push(@implContent, "{\n");
2228             push(@implContent, "    VM& vm = state->vm();\n");
2229             push(@implContent, "    UNUSED_PARAM(vm);\n");
2230             push(@implContent, "    auto* thisObject = jsCast<${className}Prototype*>(object);\n");
2231
2232             if ($numConstants eq 0 && $prototypePropertyCount eq 0) {
2233                 push(@implContent, "    return Base::getOwnPropertySlot(thisObject, state, propertyName, slot);\n");        
2234             } elsif ($numConstants eq 0 && $prototypeAttributeCount eq 0) {
2235                 push(@implContent, "    return getStaticFunctionSlot<JSObject>(state, ${className}PrototypeTable, thisObject, propertyName, slot);\n");
2236             } elsif ($prototypePropertyCount eq 0) {
2237                 push(@implContent, "    return getStaticValueSlot<${className}Prototype, JSObject>(state, ${className}PrototypeTable, thisObject, propertyName, slot);\n");
2238             } else {
2239                 push(@implContent, "    return getStaticPropertySlot<${className}Prototype, JSObject>(state, ${className}PrototypeTable, thisObject, propertyName, slot);\n");
2240             }
2241             push(@implContent, "}\n\n");
2242         } elsif ($numConstants > 0 || $numPrototypeProperties > 0) {
2243             push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
2244             push(@implContent, "{\n");
2245             push(@implContent, "    Base::finishCreation(vm);\n");
2246             push(@implContent, "    reifyStaticProperties(vm, ${className}PrototypeTableValues, *this);\n");
2247
2248             my @runtimeEnabledProperties = @runtimeEnabledFunctions;
2249             push(@runtimeEnabledProperties, @runtimeEnabledAttributes);
2250             foreach my $functionOrAttribute (@runtimeEnabledProperties) {
2251                 my $signature = $functionOrAttribute->signature;
2252                 my $conditionalString = $codeGenerator->GenerateConditionalString($signature);
2253                 push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2254                 AddToImplIncludes("RuntimeEnabledFeatures.h");
2255                 my $enable_function = GetRuntimeEnableFunctionName($signature);
2256                 my $name = $signature->name;
2257                 push(@implContent, "    if (!${enable_function}()) {\n");
2258                 push(@implContent, "        Identifier propertyName = Identifier::fromString(&vm, reinterpret_cast<const LChar*>(\"$name\"), strlen(\"$name\"));\n");
2259                 push(@implContent, "        removeDirect(vm, propertyName);\n");
2260                 push(@implContent, "    }\n");
2261                 push(@implContent, "#endif\n") if $conditionalString;
2262             }
2263
2264             my $firstPrivateFunction = 1;
2265             foreach my $function (@{$interface->functions}) {
2266                 next unless ($function->signature->extendedAttributes->{"Private"});
2267                 AddToImplIncludes("WebCoreJSClientData.h");
2268                 push(@implContent, "    JSVMClientData& clientData = *static_cast<JSVMClientData*>(vm.clientData);\n") if $firstPrivateFunction;
2269                 $firstPrivateFunction = 0;
2270                 push(@implContent, "    putDirect(vm, clientData.builtinNames()." . $function->signature->name . "PrivateName(), JSFunction::create(vm, globalObject(), 0, String(), " . GetFunctionName($interface, $className, $function) . "), ReadOnly | DontEnum);\n");
2271             }
2272
2273             if ($interface->iterable) {
2274                 my $functionName = GetFunctionName($interface, $className, @{$interface->iterable->functions}[0]);
2275                 push(@implContent, "    putDirect(vm, vm.propertyNames->iteratorSymbol, JSFunction::create(vm, globalObject(), 0, ASCIILiteral(\"[Symbol.Iterator]\"), $functionName), ReadOnly | DontEnum);\n");
2276             }
2277
2278             push(@implContent, "}\n\n");
2279         } else {
2280             push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
2281             push(@implContent, "{\n");
2282             push(@implContent, "    Base::finishCreation(vm);\n");
2283             push(@implContent, "}\n\n");
2284         }
2285     }
2286
2287     if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {
2288         push(@implContent, "bool ${className}Prototype::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
2289         push(@implContent, "{\n");
2290         push(@implContent, "    auto* thisObject = jsCast<${className}Prototype*>(cell);\n");
2291         push(@implContent, "    bool putResult = false;\n");
2292         push(@implContent, "    if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
2293         push(@implContent, "        return putResult;\n");
2294         push(@implContent, "    return Base::put(thisObject, state, propertyName, value, slot);\n");
2295         push(@implContent, "}\n\n");
2296     }
2297
2298     # - Initialize static ClassInfo object
2299     push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleInterfaceName}\", &Base::s_info, ");
2300
2301     if ($numInstanceProperties > 0) {
2302         push(@implContent, "&${className}Table");
2303     } else {
2304         push(@implContent, "0");
2305     }
2306     push(@implContent, ", CREATE_METHOD_TABLE($className) };\n\n");
2307
2308     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($interfaceName);
2309     my $svgPropertyOrListPropertyType;
2310     $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
2311     $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
2312
2313     # Constructor
2314     if ($interfaceName eq "DOMWindow") {
2315         AddIncludesForTypeInImpl("JSDOMWindowShell");
2316         push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* shell)\n");
2317         push(@implContent, "    : $parentClassName(vm, structure, WTFMove(impl), shell)\n");
2318         push(@implContent, "{\n");
2319         push(@implContent, "}\n\n");
2320     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
2321         AddIncludesForTypeInImpl($interfaceName);
2322         push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl)\n");
2323         push(@implContent, "    : $parentClassName(vm, structure, WTFMove(impl))\n");
2324         push(@implContent, "{\n");
2325         push(@implContent, "}\n\n");
2326     } elsif (!NeedsImplementationClass($interface)) {
2327         push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject& globalObject)\n");
2328         push(@implContent, "    : $parentClassName(structure, globalObject) { }\n\n");
2329     } else {
2330         push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject& globalObject, Ref<$implType>&& impl)\n");
2331         push(@implContent, "    : $parentClassName(structure, globalObject, WTFMove(impl))\n");
2332         push(@implContent, "{\n");
2333         push(@implContent, "}\n\n");
2334     }
2335
2336     if (IsDOMGlobalObject($interface)) {
2337         if ($interfaceName eq "DOMWindow") {
2338             push(@implContent, "void ${className}::finishCreation(VM& vm, JSDOMWindowShell* shell)\n");
2339             push(@implContent, "{\n");
2340             push(@implContent, "    Base::finishCreation(vm, shell);\n\n");
2341         } else {
2342             push(@implContent, "void ${className}::finishCreation(VM& vm)\n");
2343             push(@implContent, "{\n");
2344             push(@implContent, "    Base::finishCreation(vm);\n\n");
2345         }
2346         # Support for RuntimeEnabled attributes on global objects.
2347         foreach my $attribute (@{$interface->attributes}) {
2348             next unless $attribute->signature->extendedAttributes->{"EnabledAtRuntime"};
2349
2350             AddToImplIncludes("RuntimeEnabledFeatures.h");
2351             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2352             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2353             my $enable_function = GetRuntimeEnableFunctionName($attribute->signature);
2354             my $attributeName = $attribute->signature->name;
2355             push(@implContent, "    if (${enable_function}()) {\n");
2356             my $getter = GetAttributeGetterName($interface, $className, $attribute);
2357             my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interface, $className, $attribute);
2358             push(@implContent, "        auto* customGetterSetter = CustomGetterSetter::create(vm, $getter, $setter);\n");
2359             my $jscAttributes = GetJSCAttributesForAttribute($interface, $attribute);
2360             push(@implContent, "        putDirectCustomAccessor(vm, vm.propertyNames->$attributeName, customGetterSetter, attributesForStructure($jscAttributes));\n");
2361             push(@implContent, "    }\n");
2362             push(@implContent, "#endif\n") if $conditionalString;
2363         }
2364         # Support for RuntimeEnabled operations on global objects.
2365         foreach my $function (@{$interface->functions}) {
2366             next unless $function->signature->extendedAttributes->{"EnabledAtRuntime"};
2367             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
2368
2369             AddToImplIncludes("RuntimeEnabledFeatures.h");
2370             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2371             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2372             my $enable_function = GetRuntimeEnableFunctionName($function->signature);
2373             my $functionName = $function->signature->name;
2374             my $implementationFunction = GetFunctionName($interface, $className, $function);
2375             my $functionLength = GetFunctionLength($function);
2376             my $jsAttributes = ComputeFunctionSpecial($interface, $function);
2377             push(@implContent, "    if (${enable_function}())\n");
2378             push(@implContent, "        putDirectNativeFunction(vm, this, vm.propertyNames->$functionName, $functionLength, $implementationFunction, NoIntrinsic, attributesForStructure($jsAttributes));\n");
2379             push(@implContent, "#endif\n") if $conditionalString;
2380         }
2381         push(@implContent, "}\n\n");
2382     } else {
2383         push(@implContent, "JSObject* ${className}::createPrototype(VM& vm, JSGlobalObject* globalObject)\n");
2384         push(@implContent, "{\n");
2385         if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") {
2386             push(@implContent, "    return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, ${parentClassName}::prototype(vm, globalObject)));\n");
2387         } else {
2388             my $prototype = $interface->isException ? "errorPrototype" : "objectPrototype";
2389             push(@implContent, "    return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, globalObject->${prototype}()));\n");
2390         }
2391         push(@implContent, "}\n\n");
2392
2393         push(@implContent, "JSObject* ${className}::prototype(VM& vm, JSGlobalObject* globalObject)\n");
2394         push(@implContent, "{\n");
2395         push(@implContent, "    return getDOMPrototype<${className}>(vm, globalObject);\n");
2396         push(@implContent, "}\n\n");
2397     }
2398
2399     if (!$hasParent) {
2400         push(@implContent, "void ${className}::destroy(JSC::JSCell* cell)\n");
2401         push(@implContent, "{\n");
2402         push(@implContent, "    ${className}* thisObject = static_cast<${className}*>(cell);\n");
2403         push(@implContent, "    thisObject->${className}::~${className}();\n");
2404         push(@implContent, "}\n\n");
2405     }
2406
2407     my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
2408
2409     # Attributes
2410     if ($hasGetter) {
2411         if (!$interface->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
2412             push(@implContent, "bool ${className}::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)\n");
2413             push(@implContent, "{\n");
2414             push(@implContent, "    auto* thisObject = jsCast<${className}*>(object);\n");
2415             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2416             push(@implContent, GenerateGetOwnPropertySlotBody($interface, $className, $numInstanceProperties > 0, 0));
2417             push(@implContent, "}\n\n");
2418         }
2419
2420         if ($indexedGetterFunction || $namedGetterFunction
2421                 || $interface->extendedAttributes->{"CustomNamedGetter"}
2422                 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
2423             push(@implContent, "bool ${className}::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot)\n");
2424             push(@implContent, "{\n");
2425             push(@implContent, "    auto* thisObject = jsCast<${className}*>(object);\n");
2426             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2427
2428             # Sink the int-to-string conversion that happens when we create a PropertyName
2429             # to the point where we actually need it.
2430             my $generatedPropertyName = 0;
2431             my $propertyNameGeneration = sub {
2432                 if ($generatedPropertyName) {
2433                     return;
2434                 }
2435                 push(@implContent, "    Identifier propertyName = Identifier::from(state, index);\n");
2436                 $generatedPropertyName = 1;
2437             };
2438
2439             if ($indexedGetterFunction) {
2440                 if ($indexedGetterFunction->signature->type eq "DOMString") {
2441                     push(@implContent, "    if (LIKELY(index <= MAX_ARRAY_INDEX)) {\n");
2442                 } else {
2443                     push(@implContent, "    if (LIKELY(index < thisObject->wrapped().length())) {\n");
2444                 }
2445                 # Assume that if there's a setter, the index will be writable
2446                 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2447                     push(@implContent, "        unsigned attributes = DontDelete;\n");
2448                 } else {
2449                     push(@implContent, "        unsigned attributes = DontDelete | ReadOnly;\n");
2450                 }
2451                 push(@implContent, "        slot.setValue(thisObject, attributes, " . GetIndexedGetterExpression($indexedGetterFunction) . ");\n");
2452                 push(@implContent, "        return true;\n");
2453                 push(@implContent, "    }\n");
2454             }
2455
2456             # Indexing an object with an integer that is not a supported property index should not call the named property getter.
2457             # https://heycam.github.io/webidl/#idl-indexed-properties
2458             if (!$indexedGetterFunction && ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"})) {
2459                 &$propertyNameGeneration();
2460
2461                 # This condition is to make sure we use the subclass' named getter instead of the base class one when possible.
2462                 push(@implContent, "    if (thisObject->classInfo() == info()) {\n");
2463                 push(@implContent, "        JSValue value;\n");
2464                 push(@implContent, "        if (thisObject->nameGetter(state, propertyName, value)) {\n");
2465                 push(@implContent, "            slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, value);\n");
2466                 push(@implContent, "            return true;\n");
2467                 push(@implContent, "        }\n");
2468                 push(@implContent, "    }\n");
2469                 $implIncludes{"wtf/text/AtomicString.h"} = 1;
2470             }
2471
2472             if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
2473                 &$propertyNameGeneration();
2474                 push(@implContent, "    if (thisObject->getOwnPropertySlotDelegate(state, propertyName, slot))\n");
2475                 push(@implContent, "        return true;\n");
2476             }
2477
2478             push(@implContent, "    return Base::getOwnPropertySlotByIndex(thisObject, state, index, slot);\n");
2479             push(@implContent, "}\n\n");
2480         }
2481
2482     }
2483     $numAttributes = $numAttributes + 1 if NeedsConstructorProperty($interface);
2484     if ($numAttributes > 0) {
2485         foreach my $attribute (@{$interface->attributes}) {
2486             next if IsJSBuiltin($interface, $attribute);
2487
2488             my $name = $attribute->signature->name;
2489             my $type = $attribute->signature->type;
2490             $codeGenerator->AssertNotSequenceType($type);
2491             my $getFunctionName = GetAttributeGetterName($interface, $className, $attribute);
2492             my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->extendedAttributes->{"ImplementedAs"} || $name);
2493             my $getterExceptionsWithMessage = $attribute->signature->extendedAttributes->{"GetterRaisesExceptionWithMessage"};
2494             my $getterExceptions = $attribute->signature->extendedAttributes->{"GetterRaisesException"} || $getterExceptionsWithMessage;
2495
2496             if ($getterExceptions) {
2497                 $implIncludes{"ExceptionCode.h"} = 1;
2498             }
2499
2500             my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2501             push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2502
2503             push(@implContent, "EncodedJSValue ${getFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
2504             push(@implContent, "{\n");
2505
2506             push(@implContent, "    UNUSED_PARAM(state);\n");
2507             push(@implContent, "    UNUSED_PARAM(thisValue);\n");
2508
2509             if (!$attribute->isStatic || $attribute->signature->type =~ /Constructor$/) {
2510                 push(@implContent, "    JSValue decodedThisValue = JSValue::decode(thisValue);\n");
2511                 my $castingFunction = $interface->extendedAttributes->{"CustomProxyToJSObject"} ? "to${className}" : GetCastingHelperForThisObject($interface);
2512                 # http://heycam.github.io/webidl/#ImplicitThis
2513                 if ($interface->extendedAttributes->{"ImplicitThis"}) {
2514                     push(@implContent, "    auto* castedThis = decodedThisValue.isUndefinedOrNull() ? $castingFunction(state->thisValue().toThis(state, NotStrictMode)) : $castingFunction(decodedThisValue);\n");
2515                 } else {
2516                     push(@implContent, "    auto* castedThis = $castingFunction(decodedThisValue);\n");
2517                 }
2518                 push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2519                 if ($attribute->signature->extendedAttributes->{"LenientThis"}) {
2520                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2521                 } elsif (InterfaceRequiresAttributesOnInstanceForCompatibility($interface)) {
2522                     # Fallback to trying to searching the prototype chain for compatibility reasons.
2523                     push(@implContent, "        JSObject* thisObject = JSValue::decode(thisValue).getObject();\n");
2524                     push(@implContent, "        for (thisObject = thisObject ? thisObject->getPrototypeDirect().getObject() : nullptr; thisObject; thisObject = thisObject->getPrototypeDirect().getObject()) {\n");
2525                     push(@implContent, "            if ((castedThis = " . GetCastingHelperForThisObject($interface) . "(thisObject)))\n");
2526                     push(@implContent, "                break;\n");
2527                     push(@implContent, "        }\n");
2528                     push(@implContent, "        if (!castedThis)\n");
2529                     push(@implContent, "            return throwGetterTypeError(*state, \"$interfaceName\", \"$name\");\n");
2530                     push(@implContent, "        reportDeprecatedGetterError(*state, \"$interfaceName\", \"$name\");\n");
2531                 } else {
2532                     push(@implContent, "        return throwGetterTypeError(*state, \"$interfaceName\", \"$name\");\n");
2533                 }
2534                 push(@implContent, "    }\n");
2535             }
2536
2537             my @arguments = ();
2538             if ($getterExceptions && !HasCustomGetter($attribute->signature->extendedAttributes)) {
2539                 push(@arguments, "ec");
2540                 if ($getterExceptionsWithMessage) {
2541                     push(@implContent, "    ExceptionCodeWithMessage ec;\n");
2542                 } else {
2543                     push(@implContent, "    ExceptionCode ec = 0;\n");
2544                 }
2545             }
2546
2547             # Global constructors can be disabled at runtime.
2548             if ($attribute->signature->type =~ /Constructor$/) {
2549                 if ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) {
2550                     AddToImplIncludes("Frame.h");
2551                     AddToImplIncludes("Settings.h");
2552                     my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{"EnabledBySetting"}) . "Enabled";
2553                     push(@implContent, "    if (UNLIKELY(!castedThis->wrapped().frame()))\n");
2554                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2555                     push(@implContent, "    Settings& settings = castedThis->wrapped().frame()->settings();\n");
2556                     push(@implContent, "    if (!settings.$enable_function())\n");
2557                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2558                 }
2559             }
2560
2561             if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2562                 $needsVisitChildren = 1;
2563             }
2564
2565             if ($interface->extendedAttributes->{"CheckSecurity"} &&
2566                 !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"} &&
2567                 !$attribute->signature->extendedAttributes->{"DoNotCheckSecurityOnGetter"}) {
2568                 push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, castedThis->wrapped()))\n");
2569                 push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2570             }
2571
2572             if ($attribute->signature->extendedAttributes->{"Nondeterministic"}) {
2573                 AddToImplIncludes("MemoizedDOMResult.h", "WEB_REPLAY");
2574                 AddToImplIncludes("<replay/InputCursor.h>", "WEB_REPLAY");
2575                 AddToImplIncludes("<wtf/NeverDestroyed.h>", "WEB_REPLAY");
2576
2577                 push(@implContent, "#if ENABLE(WEB_REPLAY)\n");
2578                 push(@implContent, "    JSGlobalObject* globalObject = state->lexicalGlobalObject();\n");
2579                 push(@implContent, "    InputCursor& cursor = globalObject->inputCursor();\n");
2580
2581                 my $nativeType = GetNativeType($interface, $type);
2582                 my $memoizedType = GetNativeTypeForMemoization($interface, $type);
2583                 my $exceptionCode = $getterExceptionsWithMessage ? "ec.code" : ($getterExceptions ? "ec" : "0");
2584                 push(@implContent, "    static NeverDestroyed<const AtomicString> bindingName(\"$interfaceName.$name\", AtomicString::ConstructFromLiteral);\n");
2585                 push(@implContent, "    if (cursor.isCapturing()) {\n");
2586                 push(@implContent, "        $memoizedType memoizedResult = castedThis->wrapped().$implGetterFunctionName(" . join(", ", @arguments) . ");\n");
2587                 push(@implContent, "        cursor.appendInput<MemoizedDOMResult<$memoizedType>>(bindingName.get().string(), memoizedResult, $exceptionCode);\n");
2588                 push(@implContent, "        JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "memoizedResult", "castedThis") . ";\n");
2589                 push(@implContent, "        setDOMException(state, ec);\n") if $getterExceptions;
2590                 push(@implContent, "        return JSValue::encode(result);\n");
2591                 push(@implContent, "    }\n");
2592                 push(@implContent, "\n");
2593                 push(@implContent, "    if (cursor.isReplaying()) {\n");
2594                 push(@implContent, "        $memoizedType memoizedResult;\n");
2595                 push(@implContent, "        MemoizedDOMResultBase* input = cursor.fetchInput<MemoizedDOMResultBase>();\n");
2596                 push(@implContent, "        if (input && input->convertTo<$memoizedType>(memoizedResult)) {\n");
2597                 # FIXME: the generated code should report an error if an input cannot be fetched or converted.
2598                 push(@implContent, "            JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "memoizedResult", "castedThis") . ";\n");
2599                 push(@implContent, "            setDOMException(state, input->exceptionCode());\n") if $getterExceptions;
2600                 push(@implContent, "            return JSValue::encode(result);\n");
2601                 push(@implContent, "        }\n");
2602                 push(@implContent, "    }\n");
2603                 push(@implContent, "#endif\n");
2604             } # attribute Nondeterministic
2605
2606             if (HasCustomGetter($attribute->signature->extendedAttributes)) {
2607                 push(@implContent, "    return JSValue::encode(castedThis->$implGetterFunctionName(*state));\n");
2608             } elsif ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
2609                 $implIncludes{"JSDOMBinding.h"} = 1;
2610                 push(@implContent, "    auto& impl = castedThis->wrapped();\n");
2611                 push(@implContent, "    return JSValue::encode(shouldAllowAccessToNode(state, impl." . $attribute->signature->name . "()) ? " . NativeToJSValue($attribute->signature, 0, $interface, "impl.$implGetterFunctionName()", "castedThis") . " : jsNull());\n");
2612             } elsif ($type eq "EventHandler") {
2613                 my $getter = $attribute->signature->extendedAttributes->{"WindowEventHandler"} ? "windowEventHandlerAttribute"
2614                     : $attribute->signature->extendedAttributes->{"DocumentEventHandler"} ? "documentEventHandlerAttribute"
2615                     : "eventHandlerAttribute";
2616                 my $eventName = EventHandlerAttributeEventName($attribute);
2617                 push(@implContent, "    UNUSED_PARAM(state);\n");
2618                 push(@implContent, "    return JSValue::encode($getter(castedThis->wrapped(), $eventName));\n");
2619             } elsif ($attribute->signature->type =~ /Constructor$/) {
2620                 my $constructorType = $attribute->signature->type;
2621                 $constructorType =~ s/Constructor$//;
2622                 # When Constructor attribute is used by DOMWindow.idl, it's correct to pass castedThis as the global object
2623                 # When JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject()
2624                 if ($interfaceName eq "DOMWindow") {
2625                     my $named = ($constructorType =~ /Named$/) ? "Named" : "";
2626                     $constructorType =~ s/Named$//;
2627                     push(@implContent, "    return JSValue::encode(JS" . $constructorType . "::get${named}Constructor(state->vm(), castedThis));\n");
2628                 } else {
2629                     AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2630                     push(@implContent, "    return JSValue::encode(JS" . $constructorType . "::getConstructor(state->vm(), castedThis->globalObject()));\n");
2631                 }
2632             } elsif (!$attribute->signature->extendedAttributes->{"GetterRaisesException"} && !$attribute->signature->extendedAttributes->{"GetterRaisesExceptionWithMessage"}) {
2633                 my $cacheIndex = 0;
2634                 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2635                     $cacheIndex = $currentCachedAttribute;
2636                     $currentCachedAttribute++;
2637                     push(@implContent, "    if (JSValue cachedValue = castedThis->m_" . $attribute->signature->name . ".get())\n");
2638                     push(@implContent, "        return JSValue::encode(cachedValue);\n");
2639                 }
2640
2641                 my @callWithArgs = GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "JSValue::encode(jsUndefined())");
2642
2643                 if ($svgListPropertyType) {
2644                     push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $interface, "castedThis->wrapped().$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
2645                 } elsif ($svgPropertyOrListPropertyType) {
2646                     push(@implContent, "    $svgPropertyOrListPropertyType& impl = castedThis->wrapped().propertyReference();\n");
2647                     if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
2648                         push(@implContent, "    JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "impl", "castedThis") . ";\n");
2649                     } else {
2650                         push(@implContent, "    JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "impl.$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
2651
2652                     }
2653                 } else {
2654                     my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
2655                     if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
2656                         my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
2657                         $implIncludes{"${implementedBy}.h"} = 1;
2658                         $functionName = "WebCore::${implementedBy}::${functionName}";
2659                         unshift(@arguments, "impl") if !$attribute->isStatic;
2660                     } elsif ($attribute->isStatic) {
2661                         $functionName = "${interfaceName}::${functionName}";
2662                     } else {
2663                         $functionName = "impl.${functionName}";
2664                     }
2665
2666                     unshift(@arguments, @callWithArgs);
2667                     my $jsType = NativeToJSValue($attribute->signature, 0, $interface, "${functionName}(" . join(", ", @arguments) . ")", "castedThis");
2668                     push(@implContent, "    auto& impl = castedThis->wrapped();\n") if !$attribute->isStatic;
2669                     if ($codeGenerator->IsSVGAnimatedType($type)) {
2670                         push(@implContent, "    RefPtr<$type> obj = $jsType;\n");
2671                         push(@implContent, "    JSValue result = toJS(state, castedThis->globalObject(), obj.get());\n");
2672                     } else {
2673                         push(@implContent, "    JSValue result = $jsType;\n");
2674                     }
2675                 }
2676
2677                 push(@implContent, "    castedThis->m_" . $attribute->signature->name . ".set(state->vm(), castedThis, result);\n") if ($attribute->signature->extendedAttributes->{"CachedAttribute"});
2678                 push(@implContent, "    return JSValue::encode(result);\n");
2679
2680             } else {
2681                 unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "JSValue::encode(jsUndefined())"));
2682
2683                 if ($svgPropertyOrListPropertyType) {
2684                     push(@implContent, "    $svgPropertyOrListPropertyType impl(*castedThis->wrapped());\n");
2685                     push(@implContent, "    JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
2686                 } else {
2687                     push(@implContent, "    auto& impl = castedThis->wrapped();\n");
2688                     push(@implContent, "    JSValue result = " . NativeToJSValue($attribute->signature, 0, $interface, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
2689                 }
2690
2691                 push(@implContent, "    setDOMException(state, ec);\n");
2692
2693                 push(@implContent, "    return JSValue::encode(result);\n");
2694             }
2695
2696             push(@implContent, "}\n\n");
2697
2698             push(@implContent, "#endif\n") if $attributeConditionalString;
2699
2700             push(@implContent, "\n");
2701         }
2702
2703         if (NeedsConstructorProperty($interface)) {
2704             my $constructorFunctionName = "js" . $interfaceName . "Constructor";
2705
2706             push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
2707             push(@implContent, "{\n");
2708             push(@implContent, "    ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue));\n");
2709             push(@implContent, "    if (UNLIKELY(!domObject))\n");
2710             push(@implContent, "        return throwVMTypeError(state);\n");
2711
2712             if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
2713                 push(@implContent, "    return JSValue::encode(${className}::getConstructor(state->vm(), domObject->globalObject()));\n");
2714             } else {
2715                 push(@implContent, "    JSValue constructor = ${className}Constructor::create(state->vm(), ${className}Constructor::createStructure(state->vm(), *domObject->globalObject(), domObject->globalObject()->objectPrototype()), *jsCast<JSDOMGlobalObject*>(domObject->globalObject()));\n");
2716                 push(@implContent, "    // Shadowing constructor property to ensure reusing the same constructor object\n");
2717                 push(@implContent, "    domObject->putDirect(state->vm(), state->propertyNames().constructor, constructor, DontEnum | ReadOnly);\n");
2718                 push(@implContent, "    return JSValue::encode(constructor);\n");
2719             }
2720             push(@implContent, "}\n\n");
2721         }
2722
2723         my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2724
2725         push(@implContent, "bool ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
2726         push(@implContent, "{\n");
2727         push(@implContent, "    JSValue value = JSValue::decode(encodedValue);\n");
2728         push(@implContent, "    ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue));\n");
2729         push(@implContent, "    if (UNLIKELY(!domObject)) {\n");
2730         push(@implContent, "        throwVMTypeError(state);\n");
2731         push(@implContent, "        return false;\n");
2732         push(@implContent, "    }\n");
2733
2734         push(@implContent, "    // Shadowing a built-in constructor\n");
2735
2736         push(@implContent, "    return domObject->putDirect(state->vm(), state->propertyNames().constructor, value);\n");
2737         push(@implContent, "}\n\n");
2738     }
2739     my $hasCustomSetter = $interface->extendedAttributes->{"CustomNamedSetter"}
2740                           || $interface->extendedAttributes->{"CustomIndexedSetter"};
2741
2742     if ($hasCustomSetter) {
2743         if (!$interface->extendedAttributes->{"CustomPutFunction"}) {
2744             push(@implContent, "bool ${className}::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
2745             push(@implContent, "{\n");
2746             push(@implContent, "    auto* thisObject = jsCast<${className}*>(cell);\n");
2747             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2748             if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2749                 push(@implContent, "    if (Optional<uint32_t> index = parseIndex(propertyName)) {\n");
2750                 push(@implContent, "        thisObject->indexSetter(state, index.value(), value);\n");
2751                 push(@implContent, "        return true;\n");
2752                 push(@implContent, "    }\n");
2753             }
2754             if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2755                 push(@implContent, "    bool putResult = false;\n");
2756                 push(@implContent, "    if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
2757                 push(@implContent, "        return putResult;\n");
2758             }
2759
2760             push(@implContent, "    return Base::put(thisObject, state, propertyName, value, slot);\n");
2761             push(@implContent, "}\n\n");
2762
2763             if ($interface->extendedAttributes->{"CustomIndexedSetter"} || $interface->extendedAttributes->{"CustomNamedSetter"}) {
2764                 push(@implContent, "bool ${className}::putByIndex(JSCell* cell, ExecState* state, unsigned index, JSValue value, bool shouldThrow)\n");
2765                 push(@implContent, "{\n");
2766                 push(@implContent, "    auto* thisObject = jsCast<${className}*>(cell);\n");
2767                 push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2768
2769                 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2770                     push(@implContent, "    if (LIKELY(index <= MAX_ARRAY_INDEX)) {\n");
2771                     push(@implContent, "        thisObject->indexSetter(state, index, value);\n");
2772                     push(@implContent, "        return true;\n");
2773                     push(@implContent, "    }\n");
2774                 }
2775
2776                 if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2777                     push(@implContent, "    Identifier propertyName = Identifier::from(state, index);\n");
2778                     push(@implContent, "    PutPropertySlot slot(thisObject, shouldThrow);\n");
2779                     push(@implContent, "    bool putResult = false;\n");
2780                     push(@implContent, "    if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
2781                     push(@implContent, "        return putResult;\n");
2782                 }
2783
2784                 push(@implContent, "    return Base::putByIndex(cell, state, index, value, shouldThrow);\n");
2785                 push(@implContent, "}\n\n");
2786             }
2787         }
2788     }
2789
2790     foreach my $attribute (@{$interface->attributes}) {
2791         if (!IsReadonly($attribute)) {
2792             next if IsJSBuiltin($interface, $attribute);
2793
2794             my $name = $attribute->signature->name;
2795             my $type = $attribute->signature->type;
2796             my $putFunctionName = GetAttributeSetterName($interface, $className, $attribute);
2797             my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
2798             my $setterRaisesExceptionWithMessage = $attribute->signature->extendedAttributes->{"SetterRaisesExceptionWithMessage"};
2799             my $setterRaisesException = $attribute->signature->extendedAttributes->{"SetterRaisesException"} || $setterRaisesExceptionWithMessage;
2800
2801             if ($setterRaisesException) {
2802                 $implIncludes{"ExceptionCode.h"} = 1;
2803             }
2804
2805             my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2806             push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2807
2808             push(@implContent, "bool ${putFunctionName}(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
2809             push(@implContent, "{\n");
2810             push(@implContent, "    JSValue value = JSValue::decode(encodedValue);\n");
2811             push(@implContent, "    UNUSED_PARAM(thisValue);\n") if !$attribute->isStatic;
2812             if (!$attribute->isStatic) {
2813                 if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
2814                     push(@implContent, "    ${className}* castedThis = to${className}(JSValue::decode(thisValue));\n");
2815                 } else {
2816                     push(@implContent, "    ${className}* castedThis = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
2817                 }
2818                 push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2819                 if ($attribute->signature->extendedAttributes->{"LenientThis"}) {
2820                     push(@implContent, "        return false;\n");
2821                 } elsif (InterfaceRequiresAttributesOnInstanceForCompatibility($interface)) {
2822                     # Fallback to trying to searching the prototype chain for compatibility reasons.
2823                     push(@implContent, "        JSObject* thisObject = JSValue::decode(thisValue).getObject();\n");
2824                     push(@implContent, "        for (thisObject = thisObject ? thisObject->getPrototypeDirect().getObject() : nullptr; thisObject; thisObject = thisObject->getPrototypeDirect().getObject()) {\n");
2825                     push(@implContent, "            if ((castedThis = " . GetCastingHelperForThisObject($interface) . "(thisObject)))\n");
2826                     push(@implContent, "                break;\n");
2827                     push(@implContent, "        }\n");
2828                     push(@implContent, "        if (!castedThis)\n");
2829                     push(@implContent, "            return throwSetterTypeError(*state, \"$interfaceName\", \"$name\");\n");
2830                     push(@implContent, "        reportDeprecatedSetterError(*state, \"$interfaceName\", \"$name\");\n");
2831                 } else {
2832                     push(@implContent, "        return throwSetterTypeError(*state, \"$interfaceName\", \"$name\");\n");
2833                 }
2834                 push(@implContent, "    }\n");
2835             }
2836             if ($interface->extendedAttributes->{"CheckSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2837                 if ($interfaceName eq "DOMWindow") {
2838                     push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, castedThis->wrapped()))\n");
2839                 } else {
2840                     push(@implContent, "    if (!shouldAllowAccessToFrame(state, castedThis->wrapped().frame()))\n");
2841                 }
2842                 push(@implContent, "        return false;\n");
2843             }
2844
2845             if (HasCustomSetter($attribute->signature->extendedAttributes)) {
2846                 push(@implContent, "    castedThis->set$implSetterFunctionName(*state, value);\n");
2847                 push(@implContent, "    return true;\n");
2848             } elsif ($type eq "EventHandler") {
2849                 $implIncludes{"JSEventListener.h"} = 1;
2850                 my $eventName = EventHandlerAttributeEventName($attribute);
2851                 # FIXME: Find a way to do this special case without hardcoding the class and attribute names here.
2852                 if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerGlobalScope")) and $name eq "onerror") {
2853                     $implIncludes{"JSErrorHandler.h"} = 1;
2854                     push(@implContent, "    castedThis->wrapped().setAttributeEventListener($eventName, createJSErrorHandler(state, value, castedThis));\n");
2855                 } else {
2856                     $implIncludes{"JSEventListener.h"} = 1;
2857                     my $setter = $attribute->signature->extendedAttributes->{"WindowEventHandler"} ? "setWindowEventHandlerAttribute"
2858                         : $attribute->signature->extendedAttributes->{"DocumentEventHandler"} ? "setDocumentEventHandlerAttribute"
2859                         : "setEventHandlerAttribute";
2860                     push(@implContent, "    $setter(*state, *castedThis, castedThis->wrapped(), $eventName, value);\n");
2861                 }
2862                 push(@implContent, "    return true;\n");
2863             } elsif ($type =~ /Constructor$/) {
2864                 my $constructorType = $type;
2865                 $constructorType =~ s/Constructor$//;
2866                 # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
2867                 # We do not generate the header file for NamedConstructor of class XXXX,
2868                 # since we generate the NamedConstructor declaration into the header file of class XXXX.
2869                 if ($constructorType ne "any" and $constructorType !~ /Named$/) {
2870                     AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2871                 }
2872                 push(@implContent, "    // Shadowing a built-in constructor.\n");
2873                 push(@implContent, "    return castedThis->putDirect(state->vm(), Identifier::fromString(state, \"$name\"), value);\n");
2874             } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
2875                 push(@implContent, "    // Shadowing a built-in object.\n");
2876                 push(@implContent, "    return castedThis->putDirect(state->vm(), Identifier::fromString(state, \"$name\"), value);\n");
2877             } else {
2878                 if (!$attribute->isStatic) {
2879                     my $putForwards = $attribute->signature->extendedAttributes->{"PutForwards"};
2880                     if ($putForwards) {
2881                         my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->extendedAttributes->{"ImplementedAs"} || $name);
2882                         if ($attribute->signature->isNullable) {
2883                             push(@implContent, "    RefPtr<${type}> forwardedImpl = castedThis->wrapped().${implGetterFunctionName}();\n");
2884                             push(@implContent, "    if (!forwardedImpl)\n");
2885                             push(@implContent, "        return false;\n");
2886                             push(@implContent, "    auto& impl = *forwardedImpl;\n");
2887                         } else {
2888                             # Attribute is not nullable, the implementation is expected to return a reference.
2889                             push(@implContent, "    Ref<${type}> forwardedImpl = castedThis->wrapped().${implGetterFunctionName}();\n");
2890                             push(@implContent, "    auto& impl = forwardedImpl.get();\n");
2891                         }
2892                         $attribute = $codeGenerator->GetAttributeFromInterface($interface, $type, $putForwards);
2893                     } else {
2894                         push(@implContent, "    auto& impl = castedThis->wrapped();\n");
2895                     }
2896                 }
2897                 if ($setterRaisesExceptionWithMessage) {
2898                     push(@implContent, "    ExceptionCodeWithMessage ec;\n");
2899                 } elsif ($setterRaisesException) {
2900                     push(@implContent, "    ExceptionCode ec = 0;\n");
2901                 }
2902
2903                 # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
2904                 # interface type, then if the incoming value does not implement that interface, a TypeError
2905                 # is thrown rather than silently passing NULL to the C++ code.
2906                 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to
2907                 # both strings and numbers, so do not throw TypeError if the attribute is of these types.
2908                 my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $attribute->signature, "value", $attribute->signature->extendedAttributes->{"Conditional"});
2909                 if ($codeGenerator->IsWrapperType($type) && $attribute->signature->extendedAttributes->{"StrictTypeChecking"} && $attribute->signature->isNullable) {
2910                     $implIncludes{"<runtime/Error.h>"} = 1;
2911                     push(@implContent, "    " . GetNativeTypeFromSignature($interface, $attribute->signature) . " nativeValue = nullptr;\n");
2912                     push(@implContent, "    if (!value.isUndefinedOrNull()) {\n");
2913                     push(@implContent, "        nativeValue = $nativeValue;\n");
2914                     if ($mayThrowException) {
2915                         push(@implContent, "    if (UNLIKELY(state->hadException()))\n");
2916                         push(@implContent, "        return false;\n");
2917                     }
2918                     push(@implContent, "        if (UNLIKELY(!nativeValue)) {\n");
2919                     push(@implContent, "            throwAttributeTypeError(*state, \"$interfaceName\", \"$name\", \"$type\");\n");
2920                     push(@implContent, "            return false;\n");
2921                     push(@implContent, "        }\n");
2922                     push(@implContent, "    }\n");
2923                 } else {
2924                     push(@implContent, "    auto nativeValue = $nativeValue;\n");
2925                     if ($mayThrowException) {
2926                         push(@implContent, "    if (UNLIKELY(state->hadException()))\n");
2927                         push(@implContent, "        return false;\n");
2928                     }
2929                 }
2930
2931                 if ($codeGenerator->IsEnumType($type)) {
2932                     push (@implContent, "    if (UNLIKELY(!nativeValue))\n");
2933                     push (@implContent, "        return false;\n");
2934                 }
2935
2936                 my $shouldPassByReference = ShouldPassWrapperByReference($attribute->signature, $interface);
2937                 if ($shouldPassByReference) {
2938                     push(@implContent, "    if (UNLIKELY(!nativeValue)) {\n");
2939                     push(@implContent, "        throwVMTypeError(state);\n");
2940                     push(@implContent, "        return false;\n");
2941                     push(@implContent, "    }\n");
2942                 }
2943
2944                 if ($svgPropertyOrListPropertyType) {
2945                     if ($svgPropertyType) {
2946                         push(@implContent, "    if (impl.isReadOnly()) {\n");
2947                         push(@implContent, "        setDOMException(state, NO_MODIFICATION_ALLOWED_ERR);\n");
2948                         push(@implContent, "        return false;\n");
2949                         push(@implContent, "    }\n");
2950                         $implIncludes{"ExceptionCode.h"} = 1;
2951                     }
2952                     push(@implContent, "    $svgPropertyOrListPropertyType& podImpl = impl.propertyReference();\n");
2953                     if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
2954                         push(@implContent, "    podImpl = nativeValue;\n");
2955                     } else {
2956                         push(@implContent, "    podImpl.set$implSetterFunctionName(nativeValue");
2957                         push(@implContent, ", ec") if $setterRaisesException;
2958                         push(@implContent, ");\n");
2959                         push(@implContent, "    setDOMException(state, ec);\n") if $setterRaisesException;
2960                     }
2961                     if ($svgPropertyType) {
2962                         if ($setterRaisesExceptionWithMessage) {
2963                             push(@implContent, "    if (LIKELY(!ec.code))\n");
2964                             push(@implContent, "        impl.commitChange();\n");
2965                         } elsif ($setterRaisesException) {
2966                             push(@implContent, "    if (LIKELY(!ec))\n");
2967                             push(@implContent, "        impl.commitChange();\n");
2968                         } else {
2969                             push(@implContent, "    impl.commitChange();\n");
2970                         }
2971                     }
2972                     push(@implContent, "    return true;\n");
2973                 } else {
2974                     my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
2975                     if ($codeGenerator->IsTypedArrayType($type) and not $type eq "ArrayBuffer") {
2976                         push(@arguments, "nativeValue.get()");
2977                     } elsif ($codeGenerator->IsEnumType($type)) {
2978                         push(@arguments, "nativeValue.value()");
2979                     } else {
2980                         push(@arguments, $shouldPassByReference ? "*nativeValue" : "WTFMove(nativeValue)");
2981                     }
2982                     if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
2983                         my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
2984                         AddToImplIncludes("${implementedBy}.h", $attribute->signature->extendedAttributes->{"Conditional"});
2985                         unshift(@arguments, "impl") if !$attribute->isStatic;
2986                         $functionName = "WebCore::${implementedBy}::${functionName}";
2987                     } elsif ($attribute->isStatic) {
2988                         $functionName = "${interfaceName}::${functionName}";
2989                     } else {
2990                         $functionName = "impl.${functionName}";
2991                     }
2992
2993                     unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"SetterCallWith"}, \@implContent, "false"));
2994                     unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "false"));
2995
2996                     push(@arguments, "ec") if $setterRaisesException;
2997                     push(@implContent, "    ${functionName}(" . join(", ", @arguments) . ");\n");
2998                     push(@implContent, "    setDOMException(state, ec);\n") if $setterRaisesException;
2999                     push(@implConten