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