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