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