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