61a9a814e9006f7420f5d229a0dcd0b7e8f3a1f6
[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 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}HashEntry* 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     } else {
963         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n");
964     }
965     push(@headerContent, "    }\n\n");
966
967     # Custom pushEventHandlerScope function
968     push(@headerContent, "    JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{"JSCustomPushEventHandlerScope"};
969
970     # Custom call functions
971     push(@headerContent, "    static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $interface->extendedAttributes->{"CustomCall"};
972
973     # Custom deleteProperty function
974     push(@headerContent, "    static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
975     push(@headerContent, "    static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
976
977     # Custom getPropertyNames function exists on DOMWindow
978     if ($interfaceName eq "DOMWindow") {
979         push(@headerContent, "    static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
980         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
981     }
982
983     # Custom getOwnPropertyNames function
984     if ($interface->extendedAttributes->{"CustomEnumerateProperty"} || $indexedGetterFunction) {
985         push(@headerContent, "    static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
986         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;       
987     }
988
989     # Custom defineOwnProperty function
990     push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnProperty"};
991
992     # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
993     if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
994         $structureFlags{"JSC::MasqueradesAsUndefined"} = 1;
995     }
996
997     # Constructor object getter
998     unless ($interface->extendedAttributes->{"NoInterfaceObject"}) {
999         push(@headerContent, "    static JSC::JSValue getConstructor(JSC::VM&, JSC::JSGlobalObject*);\n");
1000         push(@headerContent, "    static JSC::JSValue getNamedConstructor(JSC::VM&, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{"NamedConstructor"};
1001     }
1002
1003     my $numCustomFunctions = 0;
1004     my $numCustomAttributes = 0;
1005
1006     # Attribute and function enums
1007     if ($numAttributes > 0) {
1008         foreach (@{$interface->attributes}) {
1009             my $attribute = $_;
1010             $numCustomAttributes++ if HasCustomGetter($attribute->signature->extendedAttributes);
1011             $numCustomAttributes++ if HasCustomSetter($attribute->signature->extendedAttributes);
1012             if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
1013                 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1014                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1015                 push(@headerContent, "    JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->signature->name . ";\n");
1016                 $numCachedAttributes++;
1017                 $needsVisitChildren = 1;
1018                 push(@headerContent, "#endif\n") if $conditionalString;
1019             }
1020         }
1021     }
1022
1023     # visit function
1024     if ($needsVisitChildren) {
1025         push(@headerContent, "    static void visitChildren(JSCell*, JSC::SlotVisitor&);\n\n");
1026         $structureFlags{"JSC::OverridesVisitChildren"} = 1;
1027     }
1028
1029     if ($numCustomAttributes > 0) {
1030         push(@headerContent, "\n    // Custom attributes\n");
1031
1032         foreach my $attribute (@{$interface->attributes}) {
1033             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1034             if (HasCustomGetter($attribute->signature->extendedAttributes)) {
1035                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1036                 my $methodName = $codeGenerator->WK_lcfirst($attribute->signature->name);
1037                 push(@headerContent, "    JSC::JSValue " . $methodName . "(JSC::ExecState*) const;\n");
1038                 push(@headerContent, "#endif\n") if $conditionalString;
1039             }
1040             if (HasCustomSetter($attribute->signature->extendedAttributes) && !IsReadonly($attribute)) {
1041                 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1042                 push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue);\n");
1043                 push(@headerContent, "#endif\n") if $conditionalString;
1044             }
1045         }
1046     }
1047
1048     foreach my $function (@{$interface->functions}) {
1049         $numCustomFunctions++ if HasCustomMethod($function->signature->extendedAttributes);
1050     }
1051
1052     if ($numCustomFunctions > 0) {
1053         my $inAppleCopyright = 0;
1054         push(@headerContent, "\n    // Custom functions\n");
1055         foreach my $function (@{$interface->functions}) {
1056             # PLATFORM_IOS
1057             my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
1058             if ($needsAppleCopyright) {
1059                 if (!$inAppleCopyright) {
1060                     push(@headerContent, $beginAppleCopyrightForHeaderFiles);
1061                     $inAppleCopyright = 1;
1062                 }
1063             } elsif ($inAppleCopyright) {
1064                 push(@headerContent, $endAppleCopyright);
1065                 $inAppleCopyright = 0;
1066             }
1067             # end PLATFORM_IOS
1068             next unless HasCustomMethod($function->signature->extendedAttributes);
1069             next if $function->{overloads} && $function->{overloadIndex} != 1;
1070             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1071             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1072             my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
1073             push(@headerContent, "    " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState*);\n");
1074             push(@headerContent, "#endif\n") if $conditionalString;
1075         }
1076         push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
1077     }
1078
1079     if (!$hasParent) {
1080         push(@headerContent, "    $implType& impl() const { return *m_impl; }\n");
1081         push(@headerContent, "    void releaseImpl() { m_impl->deref(); m_impl = 0; }\n\n");
1082         push(@headerContent, "    void releaseImplIfNotNull()\n");
1083         push(@headerContent, "    {\n");
1084         push(@headerContent, "        if (m_impl) {\n");
1085         push(@headerContent, "            m_impl->deref();\n");
1086         push(@headerContent, "            m_impl = 0;\n");
1087         push(@headerContent, "        }\n");
1088         push(@headerContent, "    }\n\n");
1089         push(@headerContent, "private:\n");
1090         push(@headerContent, "    $implType* m_impl;\n");
1091     } else {
1092         push(@headerContent, "    $interfaceName& impl() const\n");
1093         push(@headerContent, "    {\n");
1094         push(@headerContent, "        return static_cast<$interfaceName&>(Base::impl());\n");
1095         push(@headerContent, "    }\n");
1096     }
1097
1098     push(@headerContent, "protected:\n");
1099     # Constructor
1100     if ($interfaceName eq "DOMWindow") {
1101         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, PassRefPtr<$implType>, JSDOMWindowShell*);\n");
1102     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1103         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, PassRefPtr<$implType>);\n");
1104     } else {
1105         push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject*, PassRefPtr<$implType>);\n");
1106         push(@headerContent, "    void finishCreation(JSC::VM&);\n");
1107     }
1108
1109     # structure flags
1110     push(@headerContent, "    static const unsigned StructureFlags = ");
1111     foreach my $structureFlag (sort (keys %structureFlags)) {
1112         push(@headerContent, $structureFlag . " | ");
1113     }
1114     push(@headerContent, "Base::StructureFlags;\n");
1115
1116     # Index getter
1117     if ($indexedGetterFunction) {
1118         if ($hasNumericIndexedGetter) {
1119             push(@headerContent, "    JSC::JSValue getByIndex(JSC::ExecState*, unsigned index);\n");
1120         } else {
1121             push(@headerContent, "    static JSC::EncodedJSValue indexGetter(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, unsigned);\n");
1122         }
1123     }
1124
1125     # Index setter
1126     if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
1127         push(@headerContent, "    void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
1128     }
1129     # Name getter
1130     if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
1131         push(@headerContent, "private:\n");
1132         push(@headerContent, "    static bool canGetItemsForName(JSC::ExecState*, $interfaceName*, JSC::PropertyName);\n");
1133         push(@headerContent, "    static JSC::EncodedJSValue nameGetter(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::PropertyName);\n");
1134     }
1135
1136     push(@headerContent, "};\n\n");
1137
1138     if (!$hasParent ||
1139         GetGenerateIsReachable($interface) ||
1140         GetCustomIsReachable($interface) ||
1141         $interface->extendedAttributes->{"JSCustomFinalize"} ||
1142         $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
1143         if ($interfaceName ne "Node" && $codeGenerator->InheritsInterface($interface, "Node")) {
1144             $headerIncludes{"JSNode.h"} = 1;
1145             push(@headerContent, "class JS${interfaceName}Owner : public JSNodeOwner {\n");
1146         } else {
1147             push(@headerContent, "class JS${interfaceName}Owner : public JSC::WeakHandleOwner {\n");
1148         }
1149         push(@headerContent, "public:\n");
1150         push(@headerContent, "    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
1151         push(@headerContent, "    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
1152         push(@headerContent, "};\n");
1153         push(@headerContent, "\n");
1154         push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, $implType*)\n");
1155         push(@headerContent, "{\n");
1156         push(@headerContent, "    DEFINE_STATIC_LOCAL(JS${interfaceName}Owner, js${interfaceName}Owner, ());\n");
1157         push(@headerContent, "    return &js${interfaceName}Owner;\n");
1158         push(@headerContent, "}\n");
1159         push(@headerContent, "\n");
1160         push(@headerContent, "inline void* wrapperContext(DOMWrapperWorld& world, $implType*)\n");
1161         push(@headerContent, "{\n");
1162         push(@headerContent, "    return &world;\n");
1163         push(@headerContent, "}\n");
1164         push(@headerContent, "\n");
1165     }
1166     if (ShouldGenerateToJSDeclaration($hasParent, $interface)) {
1167         push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
1168     }
1169     if (!$hasParent || $interface->extendedAttributes->{"JSGenerateToNativeObject"}) {
1170         if ($interfaceName eq "NodeFilter") {
1171             push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::VM&, JSC::JSValue);\n");
1172         } elsif ($interfaceName eq "DOMStringList") {
1173             push(@headerContent, "PassRefPtr<DOMStringList> toDOMStringList(JSC::ExecState*, JSC::JSValue);\n");
1174         } else {
1175             push(@headerContent, "$implType* to${interfaceName}(JSC::JSValue);\n");
1176         }
1177     }
1178     if ($usesToJSNewlyCreated{$interfaceName}) {
1179         push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, $interfaceName*);\n");
1180     }
1181     
1182     push(@headerContent, "\n");
1183
1184     # Add prototype declaration.
1185     %structureFlags = ();
1186     push(@headerContent, "class ${className}Prototype : public JSC::JSNonFinalObject {\n");
1187     push(@headerContent, "public:\n");
1188     push(@headerContent, "    typedef JSC::JSNonFinalObject Base;\n");
1189     unless (IsDOMGlobalObject($interface)) {
1190         push(@headerContent, "    static JSC::JSObject* self(JSC::VM&, JSC::JSGlobalObject*);\n");
1191     }
1192
1193     push(@headerContent, "    static ${className}Prototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)\n");
1194     push(@headerContent, "    {\n");
1195     push(@headerContent, "        ${className}Prototype* ptr = new (NotNull, JSC::allocateCell<${className}Prototype>(vm.heap)) ${className}Prototype(vm, globalObject, structure);\n");
1196     push(@headerContent, "        ptr->finishCreation(vm);\n");
1197     push(@headerContent, "        return ptr;\n");
1198     push(@headerContent, "    }\n\n");
1199
1200     push(@headerContent, "    DECLARE_INFO;\n");
1201     if (PrototypeOverridesGetOwnPropertySlot($interface)) {
1202         push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
1203         $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
1204     }
1205     if ($interface->extendedAttributes->{"JSCustomMarkFunction"} or $needsVisitChildren) {
1206         $structureFlags{"JSC::OverridesVisitChildren"} = 1;
1207     }
1208     push(@headerContent,
1209         "    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n" .
1210         "    {\n" .
1211         "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n" .
1212         "    }\n");
1213     if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {
1214         push(@headerContent, "    static void put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1215         push(@headerContent, "    bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1216     }
1217
1218     # Custom defineOwnProperty function
1219     push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnPropertyOnPrototype"};
1220
1221     push(@headerContent, "\nprivate:\n");
1222     push(@headerContent, "    ${className}Prototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) : JSC::JSNonFinalObject(vm, structure) { }\n");
1223
1224     # structure flags
1225     push(@headerContent, "protected:\n");
1226     push(@headerContent, "    static const unsigned StructureFlags = ");
1227     foreach my $structureFlag (sort (keys %structureFlags)) {
1228         push(@headerContent, $structureFlag . " | ");
1229     }
1230     push(@headerContent, "Base::StructureFlags;\n");
1231
1232     push(@headerContent, "};\n\n");
1233
1234     if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
1235         $headerIncludes{"JSDOMBinding.h"} = 1;
1236         if ($interface->extendedAttributes->{"NamedConstructor"}) {
1237             $headerIncludes{"DOMConstructorWithDocument.h"} = 1;
1238         }
1239         GenerateConstructorDeclaration(\@headerContent, $className, $interface, $interfaceName);
1240     }
1241
1242     if ($numFunctions > 0) {
1243         my $inAppleCopyright = 0;
1244         push(@headerContent,"// Functions\n\n");
1245         foreach my $function (@{$interface->functions}) {
1246             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1247             my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
1248             if ($needsAppleCopyright) {
1249                 if (!$inAppleCopyright) {
1250                     push(@headerContent, $beginAppleCopyrightForHeaderFiles);
1251                     $inAppleCopyright = 1;
1252                 }
1253             } elsif ($inAppleCopyright) {
1254                 push(@headerContent, $endAppleCopyright);
1255                 $inAppleCopyright = 0;
1256             }
1257
1258             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1259             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1260             my $functionName = GetFunctionName($className, $function);
1261             push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
1262             push(@headerContent, "#endif\n") if $conditionalString;
1263         }
1264
1265         push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
1266     }
1267
1268     if ($numAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"}) {
1269         push(@headerContent,"// Attributes\n\n");
1270         foreach my $attribute (@{$interface->attributes}) {
1271             my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1272             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1273             my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
1274             push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::PropertyName);\n");
1275             if (!IsReadonly($attribute)) {
1276                 my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
1277                 push(@headerContent, "void ${setter}(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
1278             }
1279             push(@headerContent, "#endif\n") if $conditionalString;
1280         }
1281         
1282         if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
1283             my $getter = "js" . $interfaceName . "Constructor";
1284             push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::PropertyName);\n");
1285         }
1286
1287         if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
1288             my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
1289             push(@headerContent, "void ${constructorFunctionName}(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
1290         }
1291     }
1292
1293     if ($numConstants > 0) {
1294         push(@headerContent,"// Constants\n\n");
1295         foreach my $constant (@{$interface->constants}) {
1296             my $conditionalString = $codeGenerator->GenerateConditionalString($constant);
1297             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1298             my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
1299             push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::PropertyName);\n");
1300             push(@headerContent, "#endif\n") if $conditionalString;
1301         }
1302     }
1303
1304     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
1305     push(@headerContent, "\n} // namespace WebCore\n\n");
1306     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
1307     push(@headerContent, "#endif\n");
1308
1309     if ($interface->extendedAttributes->{"AppleCopyright"}) {
1310         push(@headerContent, split("\r", $endAppleCopyright));
1311     }
1312 }
1313
1314 sub GenerateAttributesHashTable
1315 {
1316     my ($object, $interface, $isInstance, $hashKeys, $hashSpecials, $hashValue1, $hashValue2, $conditionals, $entries) = @_;
1317
1318     # FIXME: These should be functions on $interface.
1319     my $interfaceName = $interface->name;
1320     my $className = "JS$interfaceName";
1321     
1322     # - Add all attributes in a hashtable definition
1323     my $numAttributes = 0;
1324     if ($isInstance) {
1325         $numAttributes = InstanceAttributeCount($interface);
1326     } else {
1327         $numAttributes = PrototypeAttributeCount($interface);
1328     }
1329
1330
1331     if (ConstructorShouldBeOnInstance($interface) == $isInstance) {
1332
1333         if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
1334             die if !$numAttributes;
1335             push(@$hashKeys, "constructor");
1336             my $getter = "js" . $interfaceName . "Constructor";
1337             push(@$hashValue1, $getter);
1338             if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
1339                 my $setter = "setJS" . $interfaceName . "Constructor";
1340                 push(@$hashValue2, $setter);
1341                 push(@$hashSpecials, "DontEnum | DontDelete");
1342             } else {
1343                 push(@$hashValue2, "0");
1344                 push(@$hashSpecials, "DontEnum | ReadOnly");
1345             }
1346         }
1347     }
1348
1349     return 0 if !$numAttributes;
1350
1351     foreach my $attribute (@{$interface->attributes}) {
1352         next if ($attribute->isStatic);
1353         next if AttributeShouldBeOnInstance($interface, $attribute) != $isInstance;
1354         my $name = $attribute->signature->name;
1355         push(@$hashKeys, $name);
1356
1357         my @specials = ();
1358         # As per Web IDL specification, constructor properties on the ECMAScript global object should be
1359         # configurable and should not be enumerable.
1360         my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
1361         push(@specials, "DontDelete") unless ($attribute->signature->extendedAttributes->{"Deletable"} || $is_global_constructor);
1362         push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor);
1363         push(@specials, "ReadOnly") if IsReadonly($attribute);
1364         push(@specials, "CustomAccessor") unless $is_global_constructor;
1365         my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1366         push(@$hashSpecials, $special);
1367
1368         my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
1369         push(@$hashValue1, $getter);
1370
1371         if (IsReadonly($attribute)) {
1372             push(@$hashValue2, "0");
1373         } else {
1374             my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
1375             push(@$hashValue2, $setter);
1376         }
1377
1378         my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
1379         if ($conditional) {
1380             $conditionals->{$name} =  $conditional;
1381         }
1382     }
1383
1384     return $numAttributes;
1385 }
1386
1387 sub GenerateParametersCheckExpression
1388 {
1389     my $numParameters = shift;
1390     my $function = shift;
1391
1392     my @andExpression = ();
1393     push(@andExpression, "argsCount == $numParameters");
1394     my $parameterIndex = 0;
1395     my %usedArguments = ();
1396     foreach my $parameter (@{$function->parameters}) {
1397         last if $parameterIndex >= $numParameters;
1398         my $value = "arg$parameterIndex";
1399         my $type = $parameter->type;
1400
1401         # Only DOMString or wrapper types are checked.
1402         # For DOMString with StrictTypeChecking only Null, Undefined and Object
1403         # are accepted for compatibility. Otherwise, no restrictions are made to
1404         # match the non-overloaded behavior.
1405         # FIXME: Implement WebIDL overload resolution algorithm.
1406         if ($codeGenerator->IsStringType($type)) {
1407             if ($parameter->extendedAttributes->{"StrictTypeChecking"}) {
1408                 push(@andExpression, "(${value}.isUndefinedOrNull() || ${value}.isString() || ${value}.isObject())");
1409                 $usedArguments{$parameterIndex} = 1;
1410             }
1411         } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) {
1412             # For Callbacks only checks if the value is null or object.
1413             push(@andExpression, "(${value}.isNull() || ${value}.isFunction())");
1414             $usedArguments{$parameterIndex} = 1;
1415         } elsif ($codeGenerator->GetArrayType($type) || $codeGenerator->GetSequenceType($type)) {
1416             # FIXME: Add proper support for T[], T[]?, sequence<T>
1417             if ($parameter->isNullable) {
1418                 push(@andExpression, "(${value}.isNull() || (${value}.isObject() && isJSArray(${value})))");
1419             } else {
1420                 push(@andExpression, "(${value}.isObject() && isJSArray(${value}))");
1421             }
1422             $usedArguments{$parameterIndex} = 1;
1423         } elsif (!IsNativeType($type)) {
1424             if ($parameter->isNullable) {
1425                 push(@andExpression, "(${value}.isNull() || (${value}.isObject() && asObject(${value})->inherits(JS${type}::info())))");
1426             } else {
1427                 push(@andExpression, "(${value}.isObject() && asObject(${value})->inherits(JS${type}::info()))");
1428             }
1429             $usedArguments{$parameterIndex} = 1;
1430         }
1431         $parameterIndex++;
1432     }
1433     my $res = join(" && ", @andExpression);
1434     $res = "($res)" if @andExpression > 1;
1435     return ($res, sort {$a <=> $b} (keys %usedArguments));
1436 }
1437
1438 # As per Web IDL specification, the length of a function Object is
1439 # its number of mandatory parameters.
1440 sub GetFunctionLength
1441 {
1442   my $function = shift;
1443
1444   my $numMandatoryParams = 0;
1445   foreach my $parameter (@{$function->parameters}) {
1446     # Abort as soon as we find the first optional parameter as no mandatory
1447     # parameter can follow an optional one.
1448     last if $parameter->isOptional;
1449     $numMandatoryParams++;
1450   }
1451   return $numMandatoryParams;
1452 }
1453
1454 sub GenerateFunctionParametersCheck
1455 {
1456     my $function = shift;
1457
1458     my @orExpression = ();
1459     my $numParameters = 0;
1460     my @neededArguments = ();
1461     my $hasVariadic = 0;
1462     my $numMandatoryParams = @{$function->parameters};
1463
1464     foreach my $parameter (@{$function->parameters}) {
1465         if ($parameter->isOptional) {
1466             my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1467             push(@orExpression, $expression);
1468             push(@neededArguments, @usedArguments);
1469             $numMandatoryParams--;
1470         }
1471         if ($parameter->isVariadic) {
1472             $hasVariadic = 1;
1473             last;
1474         }
1475         $numParameters++;
1476     }
1477     if (!$hasVariadic) {
1478         my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1479         push(@orExpression, $expression);
1480         push(@neededArguments, @usedArguments);
1481     }
1482     return ($numMandatoryParams, join(" || ", @orExpression), @neededArguments);
1483 }
1484
1485 sub GenerateOverloadedFunction
1486 {
1487     my $function = shift;
1488     my $interface = shift;
1489     my $interfaceName = shift;
1490
1491     # Generate code for choosing the correct overload to call. Overloads are
1492     # chosen based on the total number of arguments passed and the type of
1493     # values passed in non-primitive argument slots. When more than a single
1494     # overload is applicable, precedence is given according to the order of
1495     # declaration in the IDL.
1496
1497     my $kind = $function->isStatic ? "Constructor" : "Prototype";
1498     my $functionName = "js${interfaceName}${kind}Function" . $codeGenerator->WK_ucfirst($function->signature->name);
1499
1500     push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
1501     push(@implContent, <<END);
1502 {
1503     size_t argsCount = exec->argumentCount();
1504 END
1505
1506     my %fetchedArguments = ();
1507     my $leastNumMandatoryParams = 255;
1508
1509     foreach my $overload (@{$function->{overloads}}) {
1510         my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload);
1511         $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams);
1512
1513         foreach my $parameterIndex (@neededArguments) {
1514             next if exists $fetchedArguments{$parameterIndex};
1515             push(@implContent, "    JSValue arg$parameterIndex(exec->argument($parameterIndex));\n");
1516             $fetchedArguments{$parameterIndex} = 1;
1517         }
1518
1519         my $conditionalString = $codeGenerator->GenerateConditionalString($overload->signature);
1520         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
1521
1522         push(@implContent, "    if ($parametersCheck)\n");
1523         push(@implContent, "        return ${functionName}$overload->{overloadIndex}(exec);\n");
1524         push(@implContent, "#endif\n\n") if $conditionalString;
1525
1526     }
1527     if ($leastNumMandatoryParams >= 1) {
1528         push(@implContent, "    if (argsCount < $leastNumMandatoryParams)\n");
1529         push(@implContent, "        return throwVMError(exec, createNotEnoughArgumentsError(exec));\n");
1530     }
1531     push(@implContent, <<END);
1532     return throwVMTypeError(exec);
1533 }
1534
1535 END
1536 }
1537
1538 sub GetNativeTypeForConversions
1539 {
1540     my $interface = shift;
1541     my $interfaceName = $interface->name;
1542     $interfaceName = $codeGenerator->GetSVGTypeNeedingTearOff($interfaceName) if $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName);
1543     return $interfaceName;
1544 }
1545
1546 # See http://refspecs.linux-foundation.org/cxxabi-1.83.html.
1547 sub GetGnuVTableRefForInterface
1548 {
1549     my $interface = shift;
1550     my $vtableName = GetGnuVTableNameForInterface($interface);
1551     if (!$vtableName) {
1552         return "0";
1553     }
1554     my $typename = GetNativeTypeForConversions($interface);
1555     my $offset = GetGnuVTableOffsetForType($typename);
1556     return "&" . $vtableName . "[" . $offset . "]";
1557 }
1558
1559 sub GetGnuVTableNameForInterface
1560 {
1561     my $interface = shift;
1562     my $typename = GetNativeTypeForConversions($interface);
1563     my $templatePosition = index($typename, "<");
1564     return "" if $templatePosition != -1;
1565     return "" if GetImplementationLacksVTableForInterface($interface);
1566     return "" if GetSkipVTableValidationForInterface($interface);
1567     return "_ZTV" . GetGnuMangledNameForInterface($interface);
1568 }
1569
1570 sub GetGnuMangledNameForInterface
1571 {
1572     my $interface = shift;
1573     my $typename = GetNativeTypeForConversions($interface);
1574     my $templatePosition = index($typename, "<");
1575     if ($templatePosition != -1) {
1576         return "";
1577     }
1578     my $mangledType = length($typename) . $typename;
1579     my $namespace = GetNamespaceForInterface($interface);
1580     my $mangledNamespace =  "N" . length($namespace) . $namespace;
1581     return $mangledNamespace . $mangledType . "E";
1582 }
1583
1584 sub GetGnuVTableOffsetForType
1585 {
1586     my $typename = shift;
1587     if ($typename eq "SVGAElement"
1588         || $typename eq "SVGCircleElement"
1589         || $typename eq "SVGClipPathElement"
1590         || $typename eq "SVGDefsElement"
1591         || $typename eq "SVGEllipseElement"
1592         || $typename eq "SVGForeignObjectElement"
1593         || $typename eq "SVGGElement"
1594         || $typename eq "SVGImageElement"
1595         || $typename eq "SVGLineElement"
1596         || $typename eq "SVGPathElement"
1597         || $typename eq "SVGPolyElement"
1598         || $typename eq "SVGPolygonElement"
1599         || $typename eq "SVGPolylineElement"
1600         || $typename eq "SVGRectElement"
1601         || $typename eq "SVGSVGElement"
1602         || $typename eq "SVGGraphicsElement"
1603         || $typename eq "SVGSwitchElement"
1604         || $typename eq "SVGTextElement"
1605         || $typename eq "SVGUseElement") {
1606         return "3";
1607     }
1608     return "2";
1609 }
1610
1611 # See http://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B_Name_Mangling.
1612 sub GetWinVTableRefForInterface
1613 {
1614     my $interface = shift;
1615     my $vtableName = GetWinVTableNameForInterface($interface);
1616     return 0 if !$vtableName;
1617     return "__identifier(\"" . $vtableName . "\")";
1618 }
1619
1620 sub GetWinVTableNameForInterface
1621 {
1622     my $interface = shift;
1623     my $typename = GetNativeTypeForConversions($interface);
1624     my $templatePosition = index($typename, "<");
1625     return "" if $templatePosition != -1;
1626     return "" if GetImplementationLacksVTableForInterface($interface);
1627     return "" if GetSkipVTableValidationForInterface($interface);
1628     return "??_7" . GetWinMangledNameForInterface($interface) . "6B@";
1629 }
1630
1631 sub GetWinMangledNameForInterface
1632 {
1633     my $interface = shift;
1634     my $typename = GetNativeTypeForConversions($interface);
1635     my $namespace = GetNamespaceForInterface($interface);
1636     return $typename . "@" . $namespace . "@@";
1637 }
1638
1639 sub GetNamespaceForInterface
1640 {
1641     my $interface = shift;
1642     return $interface->extendedAttributes->{"ImplementationNamespace"} || "WebCore";
1643 }
1644
1645 sub GetImplementationLacksVTableForInterface
1646 {
1647     my $interface = shift;
1648     return $interface->extendedAttributes->{"ImplementationLacksVTable"};
1649 }
1650
1651 sub GetSkipVTableValidationForInterface
1652 {
1653     my $interface = shift;
1654     return $interface->extendedAttributes->{"SkipVTableValidation"};
1655 }
1656
1657 # URL becomes url, but SetURL becomes setURL.
1658 sub ToMethodName
1659 {
1660     my $param = shift;
1661     my $ret = lcfirst($param);
1662     $ret =~ s/hTML/html/ if $ret =~ /^hTML/;
1663     $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
1664     $ret =~ s/jS/js/ if $ret =~ /^jS/;
1665     $ret =~ s/xML/xml/ if $ret =~ /^xML/;
1666     $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
1667     $ret =~ s/cSS/css/ if $ret =~ /^cSS/;
1668
1669     # For HTML5 FileSystem API Flags attributes.
1670     # (create is widely used to instantiate an object and must be avoided.)
1671     $ret =~ s/^create/isCreate/ if $ret =~ /^create$/;
1672     $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/;
1673
1674     return $ret;
1675 }
1676
1677 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
1678 sub GetRuntimeEnableFunctionName
1679 {
1680     my $signature = shift;
1681
1682     # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::sharedFeatures().{FeatureName}Enabled() method.
1683     return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "VALUE_IS_MISSING");
1684
1685     # Otherwise return a function named RuntimeEnabledFeatures::sharedFeatures().{methodName}Enabled().
1686     return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->name) . "Enabled";
1687 }
1688
1689 sub GenerateImplementation
1690 {
1691     my ($object, $interface) = @_;
1692
1693     my $interfaceName = $interface->name;
1694     my $className = "JS$interfaceName";
1695
1696     my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
1697     my $hasRealParent = $interface->parent;
1698     my $hasParent = $hasLegacyParent || $hasRealParent;
1699     my $parentClassName = GetParentClassName($interface);
1700     my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
1701     my $eventTarget = $interface->extendedAttributes->{"EventTarget"} || ($codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->name ne "EventTarget");
1702     my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
1703
1704     my $namedGetterFunction = GetNamedGetterFunction($interface);
1705     my $indexedGetterFunction = GetIndexedGetterFunction($interface);
1706     my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
1707
1708     # - Add default header template
1709     push(@implContentHeader, GenerateImplementationContentHeader($interface));
1710
1711     $implIncludes{"<wtf/GetPtr.h>"} = 1;
1712     $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $indexedGetterFunction;
1713
1714     AddIncludesForTypeInImpl($interfaceName);
1715
1716     @implContent = ();
1717
1718     push(@implContent, "\nusing namespace JSC;\n\n");
1719     push(@implContent, "namespace WebCore {\n\n");
1720
1721     my @hashKeys = ();
1722     my @hashValue1 = ();
1723     my @hashValue2 = ();
1724     my @hashSpecials = ();
1725     my %conditionals = ();
1726     my $hashName = $className . "Table";
1727
1728     my $numInstanceAttributes = GenerateAttributesHashTable($object, $interface, 1,
1729         \@hashKeys, \@hashSpecials,
1730         \@hashValue1, \@hashValue2,
1731         \%conditionals);
1732
1733     my $numConstants = @{$interface->constants};
1734     my $numFunctions = @{$interface->functions};
1735     $object->GenerateHashTable($hashName, $numInstanceAttributes,
1736         \@hashKeys, \@hashSpecials,
1737         \@hashValue1, \@hashValue2,
1738         \%conditionals) if $numInstanceAttributes > 0;
1739
1740     # - Add all constants
1741     if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
1742         my $hashSize = $numConstants;
1743         my $hashName = $className . "ConstructorTable";
1744
1745         my @hashKeys = ();
1746         my @hashValue1 = ();
1747         my @hashValue2 = ();
1748         my @hashSpecials = ();
1749         my %conditionals = ();
1750
1751         # FIXME: we should not need a function for every constant.
1752         foreach my $constant (@{$interface->constants}) {
1753             my $name = $constant->name;
1754             push(@hashKeys, $name);
1755             my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name);
1756             push(@hashValue1, $getter);
1757             push(@hashValue2, "0");
1758             push(@hashSpecials, "DontDelete | ReadOnly");
1759
1760             my $implementedBy = $constant->extendedAttributes->{"ImplementedBy"};
1761             if ($implementedBy) {
1762                 $implIncludes{"${implementedBy}.h"} = 1;
1763             }
1764             my $conditional = $constant->extendedAttributes->{"Conditional"};
1765             if ($conditional) {
1766                 $conditionals{$name} = $conditional;
1767             }
1768         }
1769
1770         foreach my $attribute (@{$interface->attributes}) {
1771             next unless ($attribute->isStatic);
1772             my $name = $attribute->signature->name;
1773             push(@hashKeys, $name);
1774
1775             my @specials = ();
1776             push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
1777             push(@specials, "ReadOnly") if IsReadonly($attribute);
1778             my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1779             push(@hashSpecials, $special);
1780
1781             my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
1782             push(@hashValue1, $getter);
1783
1784             if (IsReadonly($attribute)) {
1785                 push(@hashValue2, "0");
1786             } else {
1787                 my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
1788                 push(@hashValue2, $setter);
1789             }
1790
1791             my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
1792             if ($conditional) {
1793                 $conditionals{$name} = $conditional;
1794             }
1795         }
1796
1797         foreach my $function (@{$interface->functions}) {
1798             next unless ($function->isStatic);
1799             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1800             my $name = $function->signature->name;
1801             push(@hashKeys, $name);
1802
1803             my $functionName = GetFunctionName($className, $function);
1804             push(@hashValue1, $functionName);
1805
1806             my $functionLength = GetFunctionLength($function);
1807             push(@hashValue2, $functionLength);
1808
1809             my @specials = ();
1810             push(@specials, "DontDelete") if $interface->extendedAttributes->{"OperationsNotDeletable"}
1811                 || $function->signature->extendedAttributes->{"NotDeletable"};
1812             push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"};
1813             push(@specials, "JSC::Function");
1814             my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1815             push(@hashSpecials, $special);
1816
1817             my $conditional = $function->signature->extendedAttributes->{"Conditional"};
1818             if ($conditional) {
1819                 $conditionals{$name} = $conditional;
1820             }
1821         }
1822
1823         $object->GenerateHashTable($hashName, $hashSize,
1824                                    \@hashKeys, \@hashSpecials,
1825                                    \@hashValue1, \@hashValue2,
1826                                    \%conditionals);
1827
1828         push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($interface));
1829
1830         my $protoClassName = "${className}Prototype";
1831         GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface);
1832         if ($interface->extendedAttributes->{"NamedConstructor"}) {
1833             GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interfaceName, $interface->extendedAttributes->{"NamedConstructor"}, $interface, "GeneratingNamedConstructor");
1834         }
1835     }
1836
1837     # - Add functions and constants to a hashtable definition
1838
1839     $hashName = $className . "PrototypeTable";
1840
1841     @hashKeys = ();
1842     @hashValue1 = ();
1843     @hashValue2 = ();
1844     @hashSpecials = ();
1845     %conditionals = ();
1846
1847
1848     my $numPrototypeAttributes = GenerateAttributesHashTable($object, $interface, 0,
1849         \@hashKeys, \@hashSpecials,
1850         \@hashValue1, \@hashValue2,
1851         \%conditionals);
1852     my $hashSize = $numFunctions + $numConstants + $numPrototypeAttributes;
1853
1854     # FIXME: we should not need a function for every constant.
1855     foreach my $constant (@{$interface->constants}) {
1856         my $name = $constant->name;
1857         push(@hashKeys, $name);
1858         my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name);
1859         push(@hashValue1, $getter);
1860         push(@hashValue2, "0");
1861         push(@hashSpecials, "DontDelete | ReadOnly");
1862
1863         my $conditional = $constant->extendedAttributes->{"Conditional"};
1864         if ($conditional) {
1865             $conditionals{$name} = $conditional;
1866         }
1867     }
1868
1869     foreach my $function (@{$interface->functions}) {
1870         next if ($function->isStatic);
1871         next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1872         my $name = $function->signature->name;
1873         push(@hashKeys, $name);
1874
1875         my $functionName = GetFunctionName($className, $function);
1876         push(@hashValue1, $functionName);
1877
1878         my $functionLength = GetFunctionLength($function);
1879         push(@hashValue2, $functionLength);
1880
1881         my @specials = ();
1882         push(@specials, "DontDelete") if $interface->extendedAttributes->{"OperationsNotDeletable"}
1883             || $function->signature->extendedAttributes->{"NotDeletable"};
1884         push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"};
1885         push(@specials, "JSC::Function");
1886         my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1887         push(@hashSpecials, $special);
1888
1889         my $conditional = $function->signature->extendedAttributes->{"Conditional"};
1890         if ($conditional) {
1891             $conditionals{$name} = $conditional;
1892         }
1893     }
1894
1895     $object->GenerateHashTable($hashName, $hashSize,
1896                                \@hashKeys, \@hashSpecials,
1897                                \@hashValue1, \@hashValue2,
1898                                \%conditionals);
1899
1900     if ($interface->extendedAttributes->{"JSNoStaticTables"}) {
1901         push(@implContent, "static const HashTable& get${className}PrototypeTable(VM& vm)\n");
1902         push(@implContent, "{\n");
1903         push(@implContent, "    return getHashTableForGlobalData(vm, ${className}PrototypeTable);\n");
1904         push(@implContent, "}\n\n");
1905         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, 0, get${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
1906     } else {
1907         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, &${className}PrototypeTable, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
1908     }
1909     unless (IsDOMGlobalObject($interface)) {
1910         push(@implContent, "JSObject* ${className}Prototype::self(VM& vm, JSGlobalObject* globalObject)\n");
1911         push(@implContent, "{\n");
1912         push(@implContent, "    return getDOMPrototype<${className}>(vm, globalObject);\n");
1913         push(@implContent, "}\n\n");
1914     }
1915
1916     if (PrototypeOverridesGetOwnPropertySlot($interface)) {
1917         push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
1918         push(@implContent, "{\n");
1919         push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(object);\n");
1920
1921         my $numPrototypeAttributes = PrototypeAttributeCount($interface);
1922         if ($numConstants eq 0 && $numFunctions eq 0 && $numPrototypeAttributes eq 0) {
1923             push(@implContent, "    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");        
1924         } elsif ($numConstants eq 0 && $numPrototypeAttributes eq 0) {
1925             push(@implContent, "    return getStaticFunctionSlot<JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1926         } elsif ($numFunctions eq 0 && $numPrototypeAttributes eq 0) {
1927             push(@implContent, "    return getStaticValueSlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1928         } else {
1929             push(@implContent, "    return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1930         }
1931         push(@implContent, "}\n\n");
1932     }
1933
1934     if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {
1935         push(@implContent, "void ${className}Prototype::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
1936         push(@implContent, "{\n");
1937         push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(cell);\n");
1938         push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
1939         push(@implContent, "        return;\n");
1940         push(@implContent, "    Base::put(thisObject, exec, propertyName, value, slot);\n");
1941         push(@implContent, "}\n\n");
1942     }
1943
1944     # - Initialize static ClassInfo object
1945     if ($numInstanceAttributes > 0 && $interface->extendedAttributes->{"JSNoStaticTables"}) {
1946         push(@implContent, "static const HashTable& get${className}Table(VM& vm)\n");
1947         push(@implContent, "{\n");
1948         push(@implContent, "    return getHashTableForGlobalData(vm, ${className}Table);\n");
1949         push(@implContent, "}\n\n");
1950     }
1951
1952     push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleInterfaceName}\", &Base::s_info, ");
1953
1954     if ($numInstanceAttributes > 0 && !$interface->extendedAttributes->{"JSNoStaticTables"}) {
1955         push(@implContent, "&${className}Table");
1956     } else {
1957         push(@implContent, "0");
1958     }
1959     if ($numInstanceAttributes > 0 && $interface->extendedAttributes->{"JSNoStaticTables"}) {
1960         push(@implContent, ", get${className}Table ");
1961     } else {
1962         push(@implContent, ", 0 ");
1963     }
1964     push(@implContent, ", CREATE_METHOD_TABLE($className) };\n\n");
1965
1966     my $implType = $interfaceName;
1967     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
1968     $implType = $svgNativeType if $svgNativeType;
1969
1970     my $svgPropertyOrListPropertyType;
1971     $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
1972     $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
1973
1974     # Constructor
1975     if ($interfaceName eq "DOMWindow") {
1976         AddIncludesForTypeInImpl("JSDOMWindowShell");
1977         push(@implContent, "${className}::$className(VM& vm, Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n");
1978         push(@implContent, "    : $parentClassName(vm, structure, impl, shell)\n");
1979         push(@implContent, "{\n");
1980         push(@implContent, "}\n\n");
1981     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
1982         AddIncludesForTypeInImpl($interfaceName);
1983         push(@implContent, "${className}::$className(VM& vm, Structure* structure, PassRefPtr<$implType> impl)\n");
1984         push(@implContent, "    : $parentClassName(vm, structure, impl)\n");
1985         push(@implContent, "{\n");
1986         push(@implContent, "}\n\n");
1987     } else {
1988         push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
1989         if ($hasParent) {
1990             push(@implContent, "    : $parentClassName(structure, globalObject, impl)\n");
1991         } else {
1992             push(@implContent, "    : $parentClassName(structure, globalObject)\n");
1993             push(@implContent, "    , m_impl(impl.leakRef())\n");
1994         }
1995         push(@implContent, "{\n");
1996         push(@implContent, "}\n\n");
1997
1998         push(@implContent, "void ${className}::finishCreation(VM& vm)\n");
1999         push(@implContent, "{\n");
2000         push(@implContent, "    Base::finishCreation(vm);\n");
2001         push(@implContent, "    ASSERT(inherits(info()));\n");
2002         push(@implContent, "}\n\n");
2003     }
2004
2005     unless (IsDOMGlobalObject($interface)) {
2006         push(@implContent, "JSObject* ${className}::createPrototype(VM& vm, JSGlobalObject* globalObject)\n");
2007         push(@implContent, "{\n");
2008         if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") {
2009             push(@implContent, "    return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, ${parentClassName}Prototype::self(vm, globalObject)));\n");
2010         } else {
2011             my $prototype = $interface->isException ? "errorPrototype" : "objectPrototype";
2012             push(@implContent, "    return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, globalObject->${prototype}()));\n");
2013         }
2014         push(@implContent, "}\n\n");
2015     }
2016
2017     if (!$hasParent) {
2018         # FIXME: This destroy function should not be necessary, as 
2019         # a finalizer should be called for each DOM object wrapper.
2020         # However, that seems not to be the case, so this has been
2021         # added back to avoid leaking while we figure out why the
2022         # finalizers are not always getting called. The work tracking
2023         # the finalizer issue is being tracked in http://webkit.org/b/75451
2024         push(@implContent, "void ${className}::destroy(JSC::JSCell* cell)\n");
2025         push(@implContent, "{\n");
2026         push(@implContent, "    ${className}* thisObject = static_cast<${className}*>(cell);\n");
2027         push(@implContent, "    thisObject->${className}::~${className}();\n");
2028         push(@implContent, "}\n\n");
2029
2030         # We also need a destructor for the allocateCell to work properly with the destructor-free part of the heap.
2031         # Otherwise, these destroy functions/destructors won't get called.
2032         push(@implContent, "${className}::~${className}()\n");
2033         push(@implContent, "{\n");
2034         push(@implContent, "    releaseImplIfNotNull();\n");
2035         push(@implContent, "}\n\n");
2036     }
2037
2038     my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
2039
2040     # Attributes
2041     if ($hasGetter) {
2042         if (!$interface->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
2043             push(@implContent, "bool ${className}::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
2044             push(@implContent, "{\n");
2045             push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(object);\n");
2046             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2047             push(@implContent, GenerateGetOwnPropertySlotBody($interface, $interfaceName, $className, $numInstanceAttributes > 0, 0));
2048             push(@implContent, "}\n\n");
2049         }
2050
2051         if ($indexedGetterFunction || $namedGetterFunction
2052                 || $interface->extendedAttributes->{"CustomNamedGetter"}
2053                 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
2054             push(@implContent, "bool ${className}::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)\n");
2055             push(@implContent, "{\n");
2056             push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(object);\n");
2057             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2058
2059             # Sink the int-to-string conversion that happens when we create a PropertyName
2060             # to the point where we actually need it.
2061             my $generatedPropertyName = 0;
2062             my $propertyNameGeneration = sub {
2063                 if ($generatedPropertyName) {
2064                     return;
2065                 }
2066                 push(@implContent, "    PropertyName propertyName = Identifier::from(exec, index);\n");
2067                 $generatedPropertyName = 1;
2068             };
2069
2070             if ($indexedGetterFunction) {
2071                 if ($indexedGetterFunction->signature->type eq "DOMString") {
2072                     push(@implContent, "    if (index <= MAX_ARRAY_INDEX) {\n");
2073                 } else {
2074                     push(@implContent, "    if (index < thisObject->impl().length()) {\n");
2075                 }
2076                 # Assume that if there's a setter, the index will be writable
2077                 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2078                     push(@implContent, "        unsigned attributes = DontDelete;\n");
2079                 } else {
2080                     push(@implContent, "        unsigned attributes = DontDelete | ReadOnly;\n");
2081                 }
2082                 if ($hasNumericIndexedGetter) {
2083                     push(@implContent, "        slot.setValue(thisObject, attributes, thisObject->getByIndex(exec, index));\n");
2084                 } else {
2085                     push(@implContent, "        slot.setCustomIndex(thisObject, attributes, index, thisObject->indexGetter);\n");
2086                 }
2087                 push(@implContent, "        return true;\n");
2088                 push(@implContent, "    }\n");
2089             }
2090
2091             if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
2092                 &$propertyNameGeneration();
2093                 push(@implContent, "    if (canGetItemsForName(exec, &thisObject->impl(), propertyName)) {\n");
2094                 push(@implContent, "        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);\n");
2095                 push(@implContent, "        return true;\n");
2096                 push(@implContent, "    }\n");
2097                 $implIncludes{"wtf/text/AtomicString.h"} = 1;
2098             }
2099
2100             if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
2101                 &$propertyNameGeneration();
2102                 push(@implContent, "    if (thisObject->getOwnPropertySlotDelegate(exec, propertyName, slot))\n");
2103                 push(@implContent, "        return true;\n");
2104             }
2105
2106             push(@implContent, "    return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot);\n");
2107             push(@implContent, "}\n\n");
2108         }
2109
2110     }
2111     my $numAttributes = @{$interface->attributes};
2112     $numAttributes = $numAttributes + 1 if !$interface->extendedAttributes->{"NoInterfaceObject"};
2113     if ($numAttributes > 0) {
2114         foreach my $attribute (@{$interface->attributes}) {
2115             my $name = $attribute->signature->name;
2116             my $type = $attribute->signature->type;
2117             my $isNullable = $attribute->signature->isNullable;
2118             $codeGenerator->AssertNotSequenceType($type);
2119             my $getFunctionName = GetAttributeGetterName($interfaceName, $className, $attribute);
2120             my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->extendedAttributes->{"ImplementedAs"} || $name);
2121
2122             my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2123             push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2124
2125             push(@implContent, "EncodedJSValue ${getFunctionName}(ExecState* exec, JSObject* slotBase, EncodedJSValue thisValue, PropertyName)\n");
2126             push(@implContent, "{\n");
2127
2128             if (!$attribute->isStatic || $attribute->signature->type =~ /Constructor$/) {
2129                 if ($interfaceName eq "DOMWindow") {
2130                     push(@implContent, "    ${className}* castedThis = jsDynamicCast<$className*>(JSValue::decode(thisValue));\n");
2131                     push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2132                     push(@implContent, "        if (JSDOMWindowShell* shell = jsDynamicCast<JSDOMWindowShell*>(JSValue::decode(thisValue)))\n");
2133                     push(@implContent, "            castedThis = shell->window();\n");
2134                     push(@implContent, "    }\n");
2135                     push(@implContent, "    UNUSED_PARAM(slotBase);\n");
2136                 } else {
2137                     push(@implContent, "    ${className}* castedThis = jsDynamicCast<$className*>(JSValue::decode(thisValue));\n");
2138                     push(@implContent, "    UNUSED_PARAM(slotBase);\n");
2139                 }
2140                 $implIncludes{"ScriptExecutionContext.h"} = 1;
2141                 push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2142                 push(@implContent, "        if (jsDynamicCast<${className}Prototype*>(slotBase)) {\n");
2143                 push(@implContent, "            ScriptExecutionContext* scriptExecutionContext = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();\n");
2144                 push(@implContent, "            scriptExecutionContext->addConsoleMessage(MessageSource::JS, MessageLevel::Error, String(\"Deprecated attempt to access property '$name' on a non-$interfaceName object.\"));\n");
2145                 push(@implContent, "            return JSValue::encode(jsUndefined());\n");
2146                 push(@implContent, "        }\n");
2147                 push(@implContent, "        return throwVMTypeError(exec);\n");
2148                 push(@implContent, "    }\n");
2149             } else {
2150                 push(@implContent, "    UNUSED_PARAM(thisValue);\n");
2151                 push(@implContent, "    UNUSED_PARAM(slotBase);\n");
2152             }
2153
2154             # Global constructors can be disabled at runtime.
2155             if ($attribute->signature->type =~ /Constructor$/) {
2156                 if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
2157                     AddToImplIncludes("RuntimeEnabledFeatures.h");
2158                     my $enable_function = GetRuntimeEnableFunctionName($attribute->signature);
2159                     push(@implContent, "    if (!${enable_function}())\n");
2160                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2161                 } elsif ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) {
2162                     AddToImplIncludes("Frame.h");
2163                     AddToImplIncludes("Settings.h");
2164                     my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{"EnabledBySetting"}) . "Enabled";
2165                     push(@implContent, "    if (!castedThis->impl().frame())\n");
2166                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2167                     push(@implContent, "    Settings& settings = castedThis->impl().frame()->settings();\n");
2168                     push(@implContent, "    if (!settings.$enable_function())\n");
2169                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2170                 }
2171             }
2172
2173             if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2174                 $needsVisitChildren = 1;
2175             }
2176
2177             if ($interface->extendedAttributes->{"CheckSecurity"} &&
2178                 !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"} &&
2179                 !$attribute->signature->extendedAttributes->{"DoNotCheckSecurityOnGetter"}) {
2180                 push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2181                 push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2182             }
2183
2184             if (HasCustomGetter($attribute->signature->extendedAttributes)) {
2185                 push(@implContent, "    return JSValue::encode(castedThis->$implGetterFunctionName(exec));\n");
2186             } elsif ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
2187                 $implIncludes{"JSDOMBinding.h"} = 1;
2188                 push(@implContent, "    $interfaceName& impl = castedThis->impl();\n");
2189                 push(@implContent, "    return JSValue::encode(shouldAllowAccessToNode(exec, impl." . $attribute->signature->name . "()) ? " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName()", "castedThis") . " : jsNull());\n");
2190             } elsif ($type eq "EventListener") {
2191                 $implIncludes{"EventListener.h"} = 1;
2192                 push(@implContent, "    UNUSED_PARAM(exec);\n");
2193                 push(@implContent, "    $interfaceName& impl = castedThis->impl();\n");
2194                 push(@implContent, "    if (EventListener* listener = impl.$implGetterFunctionName()) {\n");
2195                 push(@implContent, "        if (const JSEventListener* jsListener = JSEventListener::cast(listener)) {\n");
2196                 if ($interfaceName eq "Document" || $codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
2197                     push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(&impl))\n");
2198                 } else {
2199                     push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(impl.scriptExecutionContext()))\n");
2200                 }
2201                 push(@implContent, "                return JSValue::encode(jsFunction);\n");
2202                 push(@implContent, "        }\n");
2203                 push(@implContent, "    }\n");
2204                 push(@implContent, "    return JSValue::encode(jsNull());\n");
2205             } elsif ($attribute->signature->type =~ /Constructor$/) {
2206                 my $constructorType = $attribute->signature->type;
2207                 $constructorType =~ s/Constructor$//;
2208                 # When Constructor attribute is used by DOMWindow.idl, it's correct to pass castedThis as the global object
2209                 # When JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject()
2210                 if ($interfaceName eq "DOMWindow") {
2211                     my $named = ($constructorType =~ /Named$/) ? "Named" : "";
2212                     $constructorType =~ s/Named$//;
2213                     push(@implContent, "    return JSValue::encode(JS" . $constructorType . "::get${named}Constructor(exec->vm(), castedThis));\n");
2214                 } else {
2215                     AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2216                     push(@implContent, "    return JSValue::encode(JS" . $constructorType . "::getConstructor(exec->vm(), castedThis->globalObject()));\n");
2217                 }
2218             } elsif (!$attribute->signature->extendedAttributes->{"GetterRaisesException"}) {
2219                 push(@implContent, "    UNUSED_PARAM(exec);\n") if !$attribute->signature->extendedAttributes->{"CallWith"};
2220                 push(@implContent, "    bool isNull = false;\n") if $isNullable;
2221
2222                 my $cacheIndex = 0;
2223                 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2224                     $cacheIndex = $currentCachedAttribute;
2225                     $currentCachedAttribute++;
2226                     push(@implContent, "    if (JSValue cachedValue = castedThis->m_" . $attribute->signature->name . ".get())\n");
2227                     push(@implContent, "        return JSValue::encode(cachedValue);\n");
2228                 }
2229
2230                 my @callWithArgs = GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "JSValue::encode(jsUndefined())");
2231
2232                 if ($svgListPropertyType) {
2233                     push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $interfaceName, "castedThis->impl().$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
2234                 } elsif ($svgPropertyOrListPropertyType) {
2235                     push(@implContent, "    $svgPropertyOrListPropertyType& impl = castedThis->impl().propertyReference();\n");
2236                     if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
2237                         push(@implContent, "    JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl", "castedThis") . ";\n");
2238                     } else {
2239                         push(@implContent, "    JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
2240
2241                     }
2242                 } else {
2243                     my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
2244                     push(@arguments, "isNull") if $isNullable;
2245                     if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
2246                         my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
2247                         $implIncludes{"${implementedBy}.h"} = 1;
2248                         $functionName = "${implementedBy}::${functionName}";
2249                         unshift(@arguments, "&impl") if !$attribute->isStatic;
2250                     } elsif ($attribute->isStatic) {
2251                         $functionName = "${interfaceName}::${functionName}";
2252                     } else {
2253                         $functionName = "impl.${functionName}";
2254                     }
2255
2256                     unshift(@arguments, @callWithArgs);
2257                     my $jsType = NativeToJSValue($attribute->signature, 0, $interfaceName, "${functionName}(" . join(", ", @arguments) . ")", "castedThis");
2258                     push(@implContent, "    $interfaceName& impl = castedThis->impl();\n") if !$attribute->isStatic;
2259                     if ($codeGenerator->IsSVGAnimatedType($type)) {
2260                         push(@implContent, "    RefPtr<$type> obj = $jsType;\n");
2261                         push(@implContent, "    JSValue result =  toJS(exec, castedThis->globalObject(), obj.get());\n");
2262                     } else {
2263                         push(@implContent, "    JSValue result = $jsType;\n");
2264                     }
2265
2266                     if ($isNullable) {
2267                         push(@implContent, "    if (isNull)\n");
2268                         push(@implContent, "        return JSValue::encode(jsNull());\n");
2269                     }
2270                 }
2271
2272                 push(@implContent, "    castedThis->m_" . $attribute->signature->name . ".set(exec->vm(), castedThis, result);\n") if ($attribute->signature->extendedAttributes->{"CachedAttribute"});
2273                 push(@implContent, "    return JSValue::encode(result);\n");
2274
2275             } else {
2276                 my @arguments = ("ec");
2277                 push(@implContent, "    ExceptionCode ec = 0;\n");
2278
2279                 if ($isNullable) {
2280                     push(@implContent, "    bool isNull = false;\n");
2281                     unshift(@arguments, "isNull");
2282                 }
2283
2284                 unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "JSValue::encode(jsUndefined())"));
2285
2286                 if ($svgPropertyOrListPropertyType) {
2287                     push(@implContent, "    $svgPropertyOrListPropertyType impl(*castedThis->impl());\n");
2288                     push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
2289                 } else {
2290                     push(@implContent, "    $interfaceName& impl = castedThis->impl();\n");
2291                     push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
2292                 }
2293
2294                 if ($isNullable) {
2295                     push(@implContent, "    if (isNull)\n");
2296                     push(@implContent, "        return JSValue::encode(jsNull());\n");
2297                 }
2298
2299                 push(@implContent, "    setDOMException(exec, ec);\n");
2300                 push(@implContent, "    return JSValue::encode(result);\n");
2301             }
2302
2303             push(@implContent, "}\n\n");
2304
2305             push(@implContent, "#endif\n") if $attributeConditionalString;
2306
2307             push(@implContent, "\n");
2308         }
2309
2310         if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
2311             my $constructorFunctionName = "js" . $interfaceName . "Constructor";
2312
2313             push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* exec, JSObject* baseValue, EncodedJSValue thisValue, PropertyName)\n");
2314             push(@implContent, "{\n");
2315             push(@implContent, "    UNUSED_PARAM(baseValue);\n");
2316             push(@implContent, "    UNUSED_PARAM(thisValue);\n");
2317             if ($interfaceName eq "DOMWindow") {
2318                 push(@implContent, "    ${className}* domObject = jsDynamicCast<$className*>(JSValue::decode(thisValue));\n");
2319                 push(@implContent, "    if (!domObject) {\n");
2320                 push(@implContent, "        if (JSDOMWindowShell* shell = jsDynamicCast<JSDOMWindowShell*>(JSValue::decode(thisValue)))\n");
2321                 push(@implContent, "            domObject = shell->window();\n");
2322                 push(@implContent, "    }\n");
2323             } else {
2324                 push(@implContent, "    ${className}* domObject = jsDynamicCast<${className}*>(JSValue::decode(thisValue));\n") if ConstructorShouldBeOnInstance($interface);
2325                 push(@implContent, "    ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(baseValue);\n") if !ConstructorShouldBeOnInstance($interface);
2326             }
2327             push(@implContent, "    if (!domObject)\n");
2328             push(@implContent, "        return throwVMTypeError(exec);\n");
2329
2330             if ($interface->extendedAttributes->{"CheckSecurity"}) {
2331                 die if !ConstructorShouldBeOnInstance($interface);
2332                 push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, domObject->impl()))\n");
2333                 push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2334             }
2335
2336             push(@implContent, "    return JSValue::encode(${className}::getConstructor(exec->vm(), domObject->globalObject()));\n");
2337             push(@implContent, "}\n\n");
2338         }
2339
2340         if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
2341             my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2342
2343             push(@implContent, "void ${constructorFunctionName}(ExecState* exec, JSObject*, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
2344             push(@implContent, "{\n");
2345             push(@implContent, "    JSValue value = JSValue::decode(encodedValue);");
2346             push(@implContent, "    ${className}* castedThis = jsDynamicCast<${className}*>(JSValue::decode(thisValue));\n");
2347             if ($interfaceName eq "DOMWindow") {
2348                 push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2349                 push(@implContent, "        if (JSDOMWindowShell* shell = jsDynamicCast<JSDOMWindowShell*>(JSValue::decode(thisValue)))\n");
2350                 push(@implContent, "            castedThis = shell->window();\n");
2351                 push(@implContent, "    }\n");
2352             }
2353             push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2354             push(@implContent, "        throwVMTypeError(exec);\n");
2355             push(@implContent, "        return;\n");
2356             push(@implContent, "    }\n");
2357             if ($interface->extendedAttributes->{"CheckSecurity"}) {
2358                 if ($interfaceName eq "DOMWindow") {
2359                     push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2360                 } else {
2361                     push(@implContent, "    if (!shouldAllowAccessToFrame(exec, castedThis->impl().frame()))\n");
2362                 }
2363                 push(@implContent, "        return;\n");
2364             }
2365
2366             push(@implContent, "    // Shadowing a built-in constructor\n");
2367
2368             if ($interfaceName eq "DOMWindow") {
2369                 push(@implContent, "    castedThis->putDirect(exec->vm(), exec->propertyNames().constructor, value);\n");
2370             } else {
2371                 die "No way to handle interface with ReplaceableConstructor extended attribute: $interfaceName";
2372             }
2373             push(@implContent, "}\n\n");
2374         }
2375     }
2376     my $hasCustomSetter = $interface->extendedAttributes->{"CustomNamedSetter"}
2377                           || $interface->extendedAttributes->{"CustomIndexedSetter"};
2378
2379     if ($hasCustomSetter) {
2380         if (!$interface->extendedAttributes->{"CustomPutFunction"}) {
2381             push(@implContent, "void ${className}::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
2382             push(@implContent, "{\n");
2383             push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
2384             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2385             if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2386                 push(@implContent, "    unsigned index = propertyName.asIndex();\n");
2387                 push(@implContent, "    if (index != PropertyName::NotAnIndex) {\n");
2388                 push(@implContent, "        thisObject->indexSetter(exec, index, value);\n");
2389                 push(@implContent, "        return;\n");
2390                 push(@implContent, "    }\n");
2391             }
2392             if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2393                 push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
2394                 push(@implContent, "        return;\n");
2395             }
2396
2397             push(@implContent, "    Base::put(thisObject, exec, propertyName, value, slot);\n");
2398             push(@implContent, "}\n\n");
2399
2400             if ($interface->extendedAttributes->{"CustomIndexedSetter"} || $interface->extendedAttributes->{"CustomNamedSetter"}) {
2401                 push(@implContent, "void ${className}::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)\n");
2402                 push(@implContent, "{\n");
2403                 push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
2404                 push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2405                 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2406                     push(@implContent, "    if (index <= MAX_ARRAY_INDEX) {\n");
2407                     push(@implContent, "        UNUSED_PARAM(shouldThrow);\n");
2408                     push(@implContent, "        thisObject->indexSetter(exec, index, value);\n");
2409                     push(@implContent, "        return;\n");
2410                     push(@implContent, "    }\n");
2411                 }
2412
2413                 if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2414                     push(@implContent, "    PropertyName propertyName = Identifier::from(exec, index);\n");
2415                     push(@implContent, "    PutPropertySlot slot(thisObject, shouldThrow);\n");
2416                     push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
2417                     push(@implContent, "        return;\n");
2418                 }
2419
2420                 push(@implContent, "    Base::putByIndex(cell, exec, index, value, shouldThrow);\n");
2421                 push(@implContent, "}\n\n");
2422             }
2423         }
2424     }
2425
2426     # Check if we have any writable attributes
2427     my $hasReadWriteProperties = 0;
2428     foreach my $attribute (@{$interface->attributes}) {
2429         $hasReadWriteProperties = 1 if !IsReadonly($attribute) && !$attribute->isStatic;
2430
2431         if ($attribute->signature->type eq "EventListener") {
2432             $implIncludes{"JSEventListener.h"} = 1;
2433         }
2434     }
2435
2436     if ($hasReadWriteProperties) {
2437         foreach my $attribute (@{$interface->attributes}) {
2438             if (!IsReadonly($attribute)) {
2439                 my $name = $attribute->signature->name;
2440                 my $type = $attribute->signature->type;
2441                 my $putFunctionName = GetAttributeSetterName($interfaceName, $className, $attribute);
2442                 my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
2443                 my $setterRaisesException = $attribute->signature->extendedAttributes->{"SetterRaisesException"};
2444
2445                 my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2446                 push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2447
2448                 push(@implContent, "void ${putFunctionName}(ExecState* exec, JSObject* /* baseObject */, EncodedJSValue");
2449                 push(@implContent, " thisValue") if !$attribute->isStatic;
2450                 push(@implContent, ", EncodedJSValue encodedValue)\n");
2451                 push(@implContent, "{\n");
2452                 push(@implContent, "    JSValue value = JSValue::decode(encodedValue);\n");
2453                 push(@implContent, "    UNUSED_PARAM(exec);\n");
2454                 if (!$attribute->isStatic) {
2455                     push(@implContent, "    ${className}* castedThis = jsDynamicCast<${className}*>(JSValue::decode(thisValue));\n");
2456                     if ($interfaceName eq "DOMWindow") {
2457                         push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2458                         push(@implContent, "        if (JSDOMWindowShell* shell = jsDynamicCast<JSDOMWindowShell*>(JSValue::decode(thisValue)))\n");
2459                         push(@implContent, "            castedThis = shell->window();\n");
2460                         push(@implContent, "    }\n");
2461                     }
2462                     push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
2463                     push(@implContent, "        throwVMTypeError(exec);\n");
2464                     push(@implContent, "        return;\n");
2465                     push(@implContent, "    }\n");
2466                 }
2467                 if ($interface->extendedAttributes->{"CheckSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2468                     if ($interfaceName eq "DOMWindow") {
2469                         push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2470                     } else {
2471                         push(@implContent, "    if (!shouldAllowAccessToFrame(exec, castedThis->impl().frame()))\n");
2472                     }
2473                     push(@implContent, "        return;\n");
2474                 }
2475
2476                 if (HasCustomSetter($attribute->signature->extendedAttributes)) {
2477                     push(@implContent, "    castedThis->set$implSetterFunctionName(exec, value);\n");
2478                 } elsif ($type eq "EventListener") {
2479                     $implIncludes{"JSEventListener.h"} = 1;
2480                     push(@implContent, "    UNUSED_PARAM(exec);\n");
2481                     my $windowEventListener = $attribute->signature->extendedAttributes->{"JSWindowEventListener"};
2482                     if ($windowEventListener) {
2483                         push(@implContent, "    JSDOMGlobalObject* globalObject = castedThis->globalObject();\n");
2484                     }
2485                     push(@implContent, "    $interfaceName& impl = castedThis->impl();\n");
2486                     if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerGlobalScope")) and $name eq "onerror") {
2487                         $implIncludes{"JSErrorHandler.h"} = 1;
2488                         push(@implContent, "    impl.set$implSetterFunctionName(createJSErrorHandler(exec, value, castedThis));\n");
2489                     } else {
2490                         push(@implContent, GenerateAttributeEventListenerCall($className, $implSetterFunctionName, $windowEventListener));
2491                     }
2492                 } elsif ($attribute->signature->type =~ /Constructor$/) {
2493                     my $constructorType = $attribute->signature->type;
2494                     $constructorType =~ s/Constructor$//;
2495                     # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
2496                     # We do not generate the header file for NamedConstructor of class XXXX,
2497                     # since we generate the NamedConstructor declaration into the header file of class XXXX.
2498                     if ($constructorType ne "any" and $constructorType !~ /Named$/) {
2499                         AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2500                     }
2501                     push(@implContent, "    // Shadowing a built-in constructor\n");
2502                     push(@implContent, "    castedThis->putDirect(exec->vm(), Identifier(exec, \"$name\"), value);\n");
2503
2504                 } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
2505                     push(@implContent, "    // Shadowing a built-in object\n");
2506                     push(@implContent, "    castedThis->putDirect(exec->vm(), Identifier(exec, \"$name\"), value);\n");
2507                 } else {
2508                     if (!$attribute->isStatic) {
2509                         push(@implContent, "    $implType& impl = castedThis->impl();\n");
2510                     }
2511                     push(@implContent, "    ExceptionCode ec = 0;\n") if $setterRaisesException;
2512
2513                     # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
2514                     # interface type, then if the incoming value does not implement that interface, a TypeError
2515                     # is thrown rather than silently passing NULL to the C++ code.
2516                     # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to
2517                     # both strings and numbers, so do not throw TypeError if the attribute is of these types.
2518                     if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
2519                         $implIncludes{"<runtime/Error.h>"} = 1;
2520
2521                         my $argType = $attribute->signature->type;
2522                         if ($codeGenerator->IsWrapperType($argType)) {
2523                             push(@implContent, "    if (!value.isUndefinedOrNull() && !value.inherits(JS${argType}::info())) {\n");
2524                             push(@implContent, "        throwVMTypeError(exec);\n");
2525                             push(@implContent, "        return;\n");
2526                             push(@implContent, "    };\n");
2527                         }
2528                     }
2529
2530                     push(@implContent, "    " . GetNativeTypeFromSignature($attribute->signature) . " nativeValue(" . JSValueToNative($attribute->signature, "value") . ");\n");
2531                     push(@implContent, "    if (UNLIKELY(exec->hadException()))\n");
2532                     push(@implContent, "        return;\n");
2533
2534                     if ($codeGenerator->IsEnumType($type)) {
2535                         my @enumValues = $codeGenerator->ValidEnumValues($type);
2536                         my @enumChecks = ();
2537                         foreach my $enumValue (@enumValues) {
2538                             push(@enumChecks, "nativeValue != \"$enumValue\"");
2539                         }
2540                         push (@implContent, "    if (" . join(" && ", @enumChecks) . ")\n");
2541                         push (@implContent, "        return;\n");
2542                     }
2543
2544                     if ($svgPropertyOrListPropertyType) {
2545                         if ($svgPropertyType) {
2546                             push(@implContent, "    if (impl.isReadOnly()) {\n");
2547                             push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
2548                             push(@implContent, "        return;\n");
2549                             push(@implContent, "    }\n");
2550                             $implIncludes{"ExceptionCode.h"} = 1;
2551                         }
2552                         push(@implContent, "    $svgPropertyOrListPropertyType& podImpl = impl.propertyReference();\n");
2553                         if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
2554                             push(@implContent, "    podImpl = nativeValue;\n");
2555                         } else {
2556                             push(@implContent, "    podImpl.set$implSetterFunctionName(nativeValue");
2557                             push(@implContent, ", ec") if $setterRaisesException;
2558                             push(@implContent, ");\n");
2559                             push(@implContent, "    setDOMException(exec, ec);\n") if $setterRaisesException;
2560                         }
2561                         if ($svgPropertyType) {
2562                             if ($setterRaisesException) {
2563                                 push(@implContent, "    if (!ec)\n");
2564                                 push(@implContent, "        impl.commitChange();\n");
2565                             } else {
2566                                 push(@implContent, "    impl.commitChange();\n");
2567                             }
2568                         }
2569                     } else {
2570                         my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
2571                         if ($codeGenerator->IsTypedArrayType($attribute->signature->type) and not $attribute->signature->type eq "ArrayBuffer") {
2572                             push(@arguments, "nativeValue.get()");
2573                         } else {
2574                             push(@arguments, "nativeValue");
2575                         }
2576                         if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
2577                             my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
2578                             $implIncludes{"${implementedBy}.h"} = 1;
2579                             unshift(@arguments, "&impl") if !$attribute->isStatic;
2580                             $functionName = "${implementedBy}::${functionName}";
2581                         } elsif ($attribute->isStatic) {
2582                             $functionName = "${interfaceName}::${functionName}";
2583                         } else {
2584                             $functionName = "impl.${functionName}";
2585                         }
2586
2587                         unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, ""));
2588
2589                         push(@arguments, "ec") if $setterRaisesException;
2590                         push(@implContent, "    ${functionName}(" . join(", ", @arguments) . ");\n");
2591                         push(@implContent, "    setDOMException(exec, ec);\n") if $setterRaisesException;
2592                     }
2593                 }
2594
2595                 push(@implContent, "}\n\n");
2596                 push(@implContent, "#endif\n") if $attributeConditionalString;
2597                 push(@implContent, "\n");
2598             }
2599         }
2600     }
2601
2602     if ($indexedGetterFunction && !$interface->extendedAttributes->{"CustomEnumerateProperty"}) {
2603         push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
2604         push(@implContent, "{\n");
2605         push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(object);\n");
2606         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2607         push(@implContent, "    for (unsigned i = 0, count = thisObject->impl().length(); i < count; ++i)\n");
2608         push(@implContent, "        propertyNames.add(Identifier::from(exec, i));\n");
2609         push(@implContent, "     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);\n");
2610         push(@implContent, "}\n\n");
2611     }
2612
2613     if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
2614         push(@implContent, "JSValue ${className}::getConstructor(VM& vm, JSGlobalObject* globalObject)\n{\n");
2615         push(@implContent, "    return getDOMConstructor<${className}Constructor>(vm, jsCast<JSDOMGlobalObject*>(globalObject));\n");
2616         push(@implContent, "}\n\n");
2617         if ($interface->extendedAttributes->{"NamedConstructor"}) {
2618             push(@implContent, "JSValue ${className}::getNamedConstructor(VM& vm, JSGlobalObject* globalObject)\n{\n");
2619             push(@implContent, "    return getDOMConstructor<${className}NamedConstructor>(vm, jsCast<JSDOMGlobalObject*>(globalObject));\n");
2620             push(@implContent, "}\n\n");
2621         }
2622     }
2623
2624     # Functions
2625     if ($numFunctions > 0) {
2626         my $inAppleCopyright = 0;
2627         foreach my $function (@{$interface->functions}) {
2628             my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
2629             if ($needsAppleCopyright) {
2630                 if (!$inAppleCopyright) {
2631                     push(@implContent, $beginAppleCopyrightForSourceFiles);
2632                     $inAppleCopyright = 1;
2633                 }
2634             } elsif ($inAppleCopyright) {
2635                 push(@implContent, $endAppleCopyright);
2636                 $inAppleCopyright = 0;
2637             }
2638
2639             my $isCustom = HasCustomMethod($function->signature->extendedAttributes);
2640             my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
2641             my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
2642
2643             next if $isCustom && $isOverloaded && $function->{overloadIndex} > 1;
2644
2645             AddIncludesForTypeInImpl($function->signature->type) unless $isCustom;
2646
2647             my $functionName = GetFunctionName($className, $function);
2648
2649             my $conditional = $function->signature->extendedAttributes->{"Conditional"};
2650             if ($conditional) {
2651                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2652                 push(@implContent, "#if ${conditionalString}\n");
2653             }
2654
2655
2656             if (!$isCustom && $isOverloaded) {
2657                 # Append a number to an overloaded method's name to make it unique:
2658                 $functionName = $functionName . $function->{overloadIndex};
2659                 # Make this function static to avoid compiler warnings, since we
2660                 # don't generate a prototype for it in the header.
2661                 push(@implContent, "static ");
2662             }
2663
2664             my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
2665
2666             push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
2667             push(@implContent, "{\n");
2668
2669             $implIncludes{"<runtime/Error.h>"} = 1;
2670
2671             if ($function->isStatic) {
2672                 if ($isCustom) {
2673                     GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2674                     push(@implContent, "    return JSValue::encode(${className}::" . $functionImplementationName . "(exec));\n");
2675                 } else {
2676                     GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2677
2678                     push(@implContent, "    ExceptionCode ec = 0;\n") if $raisesException;
2679
2680                     my $numParameters = @{$function->parameters};
2681                     my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
2682                     GenerateImplementationFunctionCall($function, $functionString, "    ", $svgPropertyType, $interfaceName);
2683                 }
2684             } else {
2685                 if ($interfaceName eq "DOMWindow") {
2686                     push(@implContent, "    $className* castedThis = toJSDOMWindow(exec->hostThisValue().toThis(exec, NotStrictMode));\n");
2687                     push(@implContent, "    if (UNLIKELY(!castedThis))\n");
2688                     push(@implContent, "        return throwVMTypeError(exec);\n");
2689                 } elsif ($interface->extendedAttributes->{"WorkerGlobalScope"}) {
2690                     push(@implContent, "    $className* castedThis = to${className}(exec->hostThisValue().toThis(exec, NotStrictMode));\n");
2691                     push(@implContent, "    if (UNLIKELY(!castedThis))\n");
2692                     push(@implContent, "        return throwVMTypeError(exec);\n");
2693                 } else {
2694                     push(@implContent, "    JSValue thisValue = exec->hostThisValue();\n");
2695                     push(@implContent, "    $className* castedThis = jsDynamicCast<$className*>(thisValue);\n");
2696                     push(@implContent, "    if (UNLIKELY(!castedThis))\n");
2697                     push(@implContent, "        return throwVMTypeError(exec);\n");
2698                 }
2699
2700                 push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(castedThis, ${className}::info());\n");
2701
2702                 if ($interface->extendedAttributes->{"CheckSecurity"} and
2703                     !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2704                     push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2705                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2706                 }
2707
2708                 if ($isCustom) {
2709                     push(@implContent, "    return JSValue::encode(castedThis->" . $functionImplementationName . "(exec));\n");
2710                 } else {
2711                     push(@implContent, "    $implType& impl = castedThis->impl();\n");
2712                     if ($svgPropertyType) {
2713                         push(@implContent, "    if (impl.isReadOnly()) {\n");
2714                         push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
2715                         push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2716                         push(@implContent, "    }\n");
2717                         push(@implContent, "    $svgPropertyType& podImpl = impl.propertyReference();\n");
2718                         $implIncludes{"ExceptionCode.h"} = 1;
2719                     }
2720
2721                     # For compatibility with legacy content, the EventListener calls are generated without GenerateArgumentsCountCheck.
2722                     if ($function->signature->name eq "addEventListener") {
2723                         push(@implContent, GenerateEventListenerCall($className, "add"));
2724                     } elsif ($function->signature->name eq "removeEventListener") {
2725                         push(@implContent, GenerateEventListenerCall($className, "remove"));
2726                     } else {
2727                         GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2728
2729                         push(@implContent, "    ExceptionCode ec = 0;\n") if $raisesException;
2730
2731                         if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) {
2732                             push(@implContent, "    if (!shouldAllowAccessToNode(exec, impl." . $function->signature->name . "(" . ($raisesException ? "ec" : "") .")))\n");
2733                             push(@implContent, "        return JSValue::encode(jsNull());\n");
2734                             $implIncludes{"JSDOMBinding.h"} = 1;
2735                         }
2736
2737                         my $numParameters = @{$function->parameters};
2738                         my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
2739                         GenerateImplementationFunctionCall($function, $functionString, "    ", $svgPropertyType, $interfaceName);
2740                     }
2741                 }
2742             }
2743
2744             push(@implContent, "}\n\n");
2745             push(@implContent, "#endif\n\n") if $conditional;
2746
2747             if (!$isCustom && $isOverloaded && $function->{overloadIndex} == @{$function->{overloads}}) {
2748                 # Generate a function dispatching call to the rest of the overloads.
2749                 GenerateOverloadedFunction($function, $interface, $interfaceName);
2750             }
2751
2752         }
2753
2754         push(@implContent, $endAppleCopyright) if $inAppleCopyright;
2755
2756     }
2757
2758     if ($needsVisitChildren && !$interface->extendedAttributes->{"JSCustomMarkFunction"}) {
2759         push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n");
2760         push(@implContent, "{\n");
2761         push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
2762         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
2763         push(@implContent, "    COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);\n");
2764         push(@implContent, "    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());\n");
2765         push(@implContent, "    Base::visitChildren(thisObject, visitor);\n");
2766         if ($interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget") {
2767             push(@implContent, "    thisObject->impl().visitJSEventListeners(visitor);\n");
2768         }
2769         if ($interface->extendedAttributes->{"ReportExtraMemoryCost"}) {
2770             push(@implContent, "    visitor.reportExtraMemoryUsage(cell, thisObject->impl().memoryCost());\n");
2771         }
2772         if ($numCachedAttributes > 0) {
2773             foreach (@{$interface->attributes}) {
2774                 my $attribute = $_;
2775                 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2776                     push(@implContent, "    visitor.append(&thisObject->m_" . $attribute->signature->name . ");\n");
2777                 }
2778             }
2779         }
2780         push(@implContent, "}\n\n");
2781     }
2782
2783     # Cached attributes are indeed allowed when there is a custom mark/visitChildren function.
2784     # The custom function must make sure to account for the cached attribute.
2785     # Uncomment the below line to temporarily enforce generated mark functions when cached attributes are present.
2786     # die "Can't generate binding for class with cached attribute and custom mark." if (($numCachedAttributes > 0) and ($interface->extendedAttributes->{"JSCustomMarkFunction"}));
2787
2788     if ($numConstants > 0) {
2789         push(@implContent, "// Constant getters\n\n");
2790
2791         foreach my $constant (@{$interface->constants}) {
2792             my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
2793             my $conditional = $constant->extendedAttributes->{"Conditional"};
2794
2795             if ($conditional) {
2796                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2797                 push(@implContent, "#if ${conditionalString}\n");
2798             }
2799
2800             # FIXME: this casts into int to match our previous behavior which turned 0xFFFFFFFF in -1 for NodeFilter.SHOW_ALL
2801             push(@implContent, "EncodedJSValue ${getter}(ExecState* exec, JSObject*, EncodedJSValue, PropertyName)\n");
2802             push(@implContent, "{\n");
2803             if ($constant->type eq "DOMString") {
2804                 push(@implContent, "    return JSValue::encode(jsStringOrNull(exec, String(" . $constant->value . ")));\n");
2805             } else {
2806                 push(@implContent, "    UNUSED_PARAM(exec);\n");
2807                 push(@implContent, "    return JSValue::encode(jsNumber(static_cast<int>(" . $constant->value . ")));\n");
2808             }
2809             push(@implContent, "}\n\n");
2810             push(@implContent, "#endif\n") if $conditional;
2811         }
2812     }
2813
2814     if ($indexedGetterFunction && !$hasNumericIndexedGetter) {
2815         push(@implContent, "\nEncodedJSValue ${className}::indexGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, unsigned index)\n");
2816         push(@implContent, "{\n");
2817         push(@implContent, "    ${className}* thisObj = jsCast<$className*>(slotBase);\n");
2818         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObj, info());\n");
2819         if ($indexedGetterFunction->signature->type eq "DOMString") {
2820             $implIncludes{"URL.h"} = 1;
2821             push(@implContent, "    return JSValue::encode(jsStringOrUndefined(exec, thisObj->impl().item(index)));\n");
2822         } else {
2823             push(@implContent, "    return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().item(index)));\n");
2824         }
2825         push(@implContent, "}\n\n");
2826         if ($interfaceName =~ /^HTML\w*Collection$/ or $interfaceName eq "RadioNodeList") {
2827             $implIncludes{"JSNode.h"} = 1;
2828             $implIncludes{"Node.h"} = 1;
2829         }
2830     }
2831
2832     if ($hasNumericIndexedGetter) {
2833         push(@implContent, "\nJSValue ${className}::getByIndex(ExecState*, unsigned index)\n");
2834         push(@implContent, "{\n");
2835         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(this, info());\n");
2836         push(@implContent, "    double result = impl().item(index);\n");
2837         # jsNumber conversion doesn't suppress signalling NaNs, so enforce that here.
2838         push(@implContent, "    if (std::isnan(result))\n");
2839         push(@implContent, "        return jsNaN();\n");
2840         push(@implContent, "    return JSValue(result);\n");
2841         push(@implContent, "}\n\n");
2842         if ($interfaceName =~ /^HTML\w*Collection$/) {
2843             $implIncludes{"JSNode.h"} = 1;
2844             $implIncludes{"Node.h"} = 1;
2845         }
2846     }
2847
2848     if ($interfaceName eq "DOMNamedFlowCollection") {
2849         if ($namedGetterFunction) {
2850             push(@implContent, "bool ${className}::canGetItemsForName(ExecState*, $interfaceName* collection, PropertyName propertyName)\n");
2851             push(@implContent, "{\n");
2852             push(@implContent, "    return collection->hasNamedItem(propertyNameToAtomicString(propertyName));\n");
2853             push(@implContent, "}\n\n");
2854             push(@implContent, "EncodedJSValue ${className}::nameGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName propertyName)\n");
2855             push(@implContent, "{\n");
2856             push(@implContent, "    ${className}* thisObj = jsCast<$className*>(slotBase);\n");
2857             push(@implContent, "    return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().namedItem(propertyNameToAtomicString(propertyName))));\n");
2858             push(@implContent, "}\n\n");
2859         }
2860     }
2861
2862     if ((!$hasParent && !GetCustomIsReachable($interface)) || GetGenerateIsReachable($interface) || $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
2863         if (GetGenerateIsReachable($interface)) {
2864             push(@implContent, "static inline bool isObservable(JS${interfaceName}* js${interfaceName})\n");
2865             push(@implContent, "{\n");
2866             push(@implContent, "    if (js${interfaceName}->hasCustomProperties())\n");
2867             push(@implContent, "        return true;\n");
2868             if ($eventTarget) {
2869                 push(@implContent, "    if (js${interfaceName}->impl().hasEventListeners())\n");
2870                 push(@implContent, "        return true;\n");
2871             }
2872             push(@implContent, "    return false;\n");
2873             push(@implContent, "}\n\n");
2874         }
2875
2876         push(@implContent, "bool JS${interfaceName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)\n");
2877         push(@implContent, "{\n");
2878         # All ActiveDOMObjects implement hasPendingActivity(), but not all of them
2879         # increment their C++ reference counts when hasPendingActivity() becomes
2880         # true. As a result, ActiveDOMObjects can be prematurely destroyed before
2881         # their pending activities complete. To wallpaper over this bug, JavaScript
2882         # wrappers unconditionally keep ActiveDOMObjects with pending activity alive.
2883         # FIXME: Fix this lifetime issue in the DOM, and move this hasPendingActivity
2884         # check below the isObservable check.
2885         my $emittedJSCast = 0;
2886         if ($codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
2887             push(@implContent, "    JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
2888             $emittedJSCast = 1;
2889             push(@implContent, "    if (js${interfaceName}->impl().hasPendingActivity())\n");
2890             push(@implContent, "        return true;\n");
2891         }
2892         if ($codeGenerator->InheritsExtendedAttribute($interface, "EventTarget")) {
2893             if (!$emittedJSCast) {
2894                 push(@implContent, "    JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
2895                 $emittedJSCast = 1;
2896             }
2897             push(@implContent, "    if (js${interfaceName}->impl().isFiringEventListeners())\n");
2898             push(@implContent, "        return true;\n");
2899         }
2900         if ($codeGenerator->InheritsInterface($interface, "Node")) {
2901             if (!$emittedJSCast) {
2902                 push(@implContent, "    JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
2903                 $emittedJSCast = 1;
2904             }
2905             push(@implContent, "    if (JSNodeOwner::isReachableFromOpaqueRoots(handle, 0, visitor))\n");
2906             push(@implContent, "        return true;\n");
2907         }
2908         if (GetGenerateIsReachable($interface)) {
2909             if (!$emittedJSCast) {
2910                 push(@implContent, "    JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
2911                 $emittedJSCast = 1;
2912             }
2913             push(@implContent, "    if (!isObservable(js${interfaceName}))\n");
2914             push(@implContent, "        return false;\n");
2915
2916             my $rootString;
2917             if (GetGenerateIsReachable($interface) eq "Impl") {
2918                 $rootString  = "    ${implType}* root = &js${interfaceName}->impl();\n";
2919             } elsif (GetGenerateIsReachable($interface) eq "ImplWebGLRenderingContext") {
2920                 $rootString  = "    WebGLRenderingContext* root = js${interfaceName}->impl().context();\n";
2921             } elsif (GetGenerateIsReachable($interface) eq "ImplFrame") {
2922                 $rootString  = "    Frame* root = js${interfaceName}->impl().frame();\n";
2923                 $rootString .= "    if (!root)\n";
2924                 $rootString .= "        return false;\n";
2925             } elsif (GetGenerateIsReachable($interface) eq "ImplDocument") {
2926                 $rootString  = "    Document* root = js${interfaceName}->impl().document();\n";
2927                 $rootString .= "    if (!root)\n";
2928                 $rootString .= "        return false;\n";
2929             } elsif (GetGenerateIsReachable($interface) eq "ImplElementRoot") {
2930                 $implIncludes{"Element.h"} = 1;
2931                 $implIncludes{"JSNodeCustom.h"} = 1;
2932                 $rootString  = "    Element* element = js${interfaceName}->impl().element();\n";
2933                 $rootString .= "    if (!element)\n";
2934                 $rootString .= "        return false;\n";
2935                 $rootString .= "    void* root = WebCore::root(element);\n";
2936             } elsif ($interfaceName eq "CanvasRenderingContext") {
2937                 $implIncludes{"Element.h"} = 1;
2938                 $implIncludes{"JSNodeCustom.h"} = 1;
2939                 $rootString  = "    void* root = WebCore::root(js${interfaceName}->impl().canvas());\n";
2940             } elsif (GetGenerateIsReachable($interface) eq "ImplOwnerNodeRoot") {
2941                 $implIncludes{"Element.h"} = 1;
2942                 $implIncludes{"JSNodeCustom.h"} = 1;
2943                 $rootString  = "    void* root = WebCore::root(js${interfaceName}->impl().ownerNode());\n";
2944             } else {
2945                 $rootString  = "    void* root = WebCore::root(&js${interfaceName}->impl());\n";
2946             }
2947
2948             push(@implContent, $rootString);
2949             push(@implContent, "    return visitor.containsOpaqueRoot(root);\n");
2950         } else {
2951             if (!$emittedJSCast) {
2952                 push(@implContent, "    UNUSED_PARAM(handle);\n");
2953             }
2954             push(@implContent, "    UNUSED_PARAM(visitor);\n");
2955             push(@implContent, "    return false;\n");
2956         }
2957         push(@implContent, "}\n\n");
2958     }
2959
2960     if (!$interface->extendedAttributes->{"JSCustomFinalize"} &&
2961         (!$hasParent ||
2962          GetGenerateIsReachable($interface) ||
2963          GetCustomIsReachable($interface) ||
2964          $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject"))) {
2965         push(@implContent, "void JS${interfaceName}Owner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)\n");
2966         push(@implContent, "{\n");
2967         push(@implContent, "    JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
2968         push(@implContent, "    DOMWrapperWorld& world = *static_cast<DOMWrapperWorld*>(context);\n");
2969         push(@implContent, "    uncacheWrapper(world, &js${interfaceName}->impl(), js${interfaceName});\n");
2970         push(@implContent, "    js${interfaceName}->releaseImpl();\n");
2971         push(@implContent, "}\n\n");
2972     }
2973
2974     if (ShouldGenerateToJSImplementation($hasParent, $interface)) {
2975         my $vtableNameGnu = GetGnuVTableNameForInterface($interface);
2976         my $vtableRefGnu = GetGnuVTableRefForInterface($interface);
2977         my $vtableRefWin = GetWinVTableRefForInterface($interface);
2978
2979         push(@implContent, <<END) if $vtableNameGnu;
2980 #if ENABLE(BINDING_INTEGRITY)
2981 #if PLATFORM(WIN)
2982 #pragma warning(disable: 4483)
2983 extern "C" { extern void (*const ${vtableRefWin}[])(); }
2984 #else
2985 extern "C" { extern void* ${vtableNameGnu}[]; }
2986 #endif
2987 #endif
2988 END
2989
2990         push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n");
2991         push(@implContent, "{\n");
2992         push(@implContent, <<END);
2993     if (!impl)
2994         return jsNull();
2995 END
2996
2997         if ($svgPropertyType) {
2998             push(@implContent, "    if (JSValue result = getExistingWrapper<$className, $implType>(exec, impl))\n");
2999             push(@implContent, "        return result;\n");
3000         } else {
3001             push(@implContent, "    if (JSValue result = getExistingWrapper<$className>(exec, impl))\n");
3002             push(@implContent, "        return result;\n");
3003         }
3004         push(@implContent, <<END) if $vtableNameGnu;
3005
3006 #if ENABLE(BINDING_INTEGRITY)
3007     void* actualVTablePointer = *(reinterpret_cast<void**>(impl));
3008 #if PLATFORM(WIN)
3009     void* expectedVTablePointer = reinterpret_cast<void*>(${vtableRefWin});
3010 #else
3011     void* expectedVTablePointer = ${vtableRefGnu};
3012 #if COMPILER(CLANG)
3013     // If this fails $implType does not have a vtable, so you need to add the
3014     // ImplementationLacksVTable attribute to the interface definition
3015     COMPILE_ASSERT(__is_polymorphic($implType), ${implType}_is_not_polymorphic);
3016 #endif
3017 #endif
3018     // If you hit this assertion you either have a use after free bug, or
3019     // $implType has subclasses. If $implType has subclasses that get passed
3020     // to toJS() we currently require $interfaceName you to opt out of binding hardening
3021     // by adding the SkipVTableValidation attribute to the interface IDL definition
3022     RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer);
3023 #endif
3024 END
3025         push(@implContent, <<END) if $interface->extendedAttributes->{"ImplementationLacksVTable"};
3026 #if COMPILER(CLANG)
3027     // If you hit this failure the interface definition has the ImplementationLacksVTable
3028     // attribute. You should remove that attribute. If the class has subclasses
3029     // that may be passed through this toJS() function you should use the SkipVTableValidation
3030     // attribute to $interfaceName.
3031     COMPILE_ASSERT(!__is_polymorphic($implType), ${implType}_is_polymorphic_but_idl_claims_not_to_be);
3032 #endif
3033 END
3034         push(@implContent, <<END) if $interface->extendedAttributes->{"ReportExtraMemoryCost"};
3035     exec->heap()->reportExtraMemoryCost(impl->memoryCost());
3036 END
3037
3038         if ($svgPropertyType) {
3039             push(@implContent, "    return createNewWrapper<$className, $implType>(exec, globalObject, impl);\n");
3040         } else {
3041             push(@implContent, "    return createNewWrapper<$className>(exec, globalObject, impl);\n");
3042         }
3043
3044         push(@implContent, "}\n\n");
3045     }
3046
3047     if ((!$hasParent or $interface->extendedAttributes->{"JSGenerateToNativeObject"}) and !$interface->extendedAttributes->{"JSCustomToNativeObject"}) {
3048         push(@implContent, "$implType* to${interfaceName}(JSC::JSValue value)\n");
3049         push(@implContent, "{\n");
3050         push(@implContent, "    return value.inherits(${className}::info()) ? &jsCast<$className*>(value)->impl() : 0");
3051         push(@implContent, ";\n}\n");
3052     }
3053
3054     push(@implContent, "\n}\n");
3055
3056     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
3057     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
3058 }
3059
3060 sub GenerateCallWith
3061 {
3062     my $callWith = shift;
3063     return () unless $callWith;
3064     my $outputArray = shift;
3065     my $returnValue = shift;
3066     my $function = shift;
3067
3068     my @callWithArgs;
3069     if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
3070         push(@callWithArgs, "exec");
3071     }
3072     if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptExecutionContext")) {
3073         push(@$outputArray, "    ScriptExecutionContext* scriptContext = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();\n");
3074         push(@$outputArray, "    if (!scriptContext)\n");
3075         push(@$outputArray, "        return" . ($returnValue ? " " . $returnValue : "") . ";\n");
3076         push(@callWithArgs, "scriptContext");
3077     }
3078     if ($function and $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments")) {
3079         push(@$outputArray, "    RefPtr<Inspector::ScriptArguments> scriptArguments(Inspector::createScriptArguments(exec, " . @{$function->parameters} . "));\n");
3080         $implIncludes{"<inspector/ScriptArguments.h>"} = 1;
3081         $implIncludes{"<inspector/ScriptCallStackFactory.h>"} = 1;
3082         push(@callWithArgs, "scriptArguments.release()");
3083     }
3084     return @callWithArgs;
3085 }
3086
3087 sub GenerateArgumentsCountCheck
3088 {
3089     my $outputArray = shift;
3090     my $function = shift;
3091     my $interface = shift;
3092
3093     my $numMandatoryParams = @{$function->parameters};
3094     foreach my $param (reverse(@{$function->parameters})) {
3095         if ($param->isOptional or $param->isVariadic) {
3096             $numMandatoryParams--;
3097         } else {
3098             last;
3099         }
3100     }
3101     if ($numMandatoryParams >= 1)
3102     {
3103         push(@$outputArray, "    if (exec->argumentCount() < $numMandatoryParams)\n");
3104         push(@$outputArray, "        return throwVMError(exec, createNotEnoughArgumentsError(exec));\n");
3105     }
3106 }
3107
3108 sub GenerateParametersCheck
3109 {
3110     my $outputArray = shift;
3111     my $function = shift;
3112     my $interface = shift;
3113     my $numParameters = shift;
3114     my $interfaceName = shift;
3115     my $functionImplementationName = shift;
3116     my $svgPropertyType = shift;
3117     my $svgPropertyOrListPropertyType = shift;
3118     my $svgListPropertyType = shift;
3119
3120     my $argsIndex = 0;
3121     my $hasOptionalArguments = 0;
3122     my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
3123
3124     my @arguments;
3125     my $functionName;
3126     my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
3127     if ($implementedBy) {
3128         AddToImplIncludes("${implementedBy}.h");
3129         unshift(@arguments, "&impl") if !$function->isStatic;
3130         $functionName = "${implementedBy}::${functionImplementationName}";
3131     } elsif ($function->isStatic) {
3132         $functionName = "${interfaceName}::${functionImplementationName}";
3133     } elsif ($svgPropertyOrListPropertyType and !$svgListPropertyType) {
3134         $functionName = "podImpl.${functionImplementationName}";
3135     } else {
3136         $functionName = "impl.${functionImplementationName}";
3137     }
3138
3139     if (!$function->signature->extendedAttributes->{"Constructor"}) {
3140         push(@arguments, GenerateCallWith($function->signature->extendedAttributes->{"CallWith"}, \@$outputArray, "JSValue::encode(jsUndefined())", $function));
3141     }
3142
3143     $implIncludes{"ExceptionCode.h"} = 1;
3144     $implIncludes{"JSDOMBinding.h"} = 1;
3145
3146     foreach my $parameter (@{$function->parameters}) {
3147         my $argType = $parameter->type;
3148
3149         # Optional arguments with [Optional] should generate an early call with fewer arguments.
3150         # Optional arguments with [Optional=...] should not generate the early call.
3151         # Optional Dictionary arguments always considered to have default of empty dictionary.
3152         my $optional = $parameter->isOptional;
3153         my $defaultAttribute = $parameter->extendedAttributes->{"Default"};
3154         if ($optional && !$defaultAttribute && $argType ne "Dictionary" && !$codeGenerator->IsCallbackInterface($parameter->type)) {
3155             # Generate early call if there are enough parameters.
3156             if (!$hasOptionalArguments) {
3157                 push(@$outputArray, "\n    size_t argsCount = exec->argumentCount();\n");
3158                 $hasOptionalArguments = 1;
3159             }
3160             push(@$outputArray, "    if (argsCount <= $argsIndex) {\n");
3161
3162             my @optionalCallbackArguments = @arguments;
3163             push(@optionalCallbackArguments, "ec") if $raisesException;
3164             my $functionString = "$functionName(" . join(", ", @optionalCallbackArguments) . ")";
3165             GenerateImplementationFunctionCall($function, $functionString, "    " x 2, $svgPropertyType, $interfaceName);
3166             push(@$outputArray, "    }\n\n");
3167         }
3168
3169         my $name = $parameter->name;
3170
3171         if ($argType eq "XPathNSResolver") {
3172             push(@$outputArray, "    RefPtr<XPathNSResolver> customResolver;\n");
3173             push(@$outputArray, "    XPathNSResolver* resolver = toXPathNSResolver(exec->argument($argsIndex));\n");
3174             push(@$outputArray, "    if (!resolver) {\n");
3175             push(@$outputArray, "        customResolver = JSCustomXPathNSResolver::create(exec, exec->argument($argsIndex));\n");
3176             push(@$outputArray, "        if (UNLIKELY(exec->hadException()))\n");
3177             push(@$outputArray, "            return JSValue::encode(jsUndefined());\n");
3178             push(@$outputArray, "        resolver = customResolver.get();\n");
3179             push(@$outputArray, "    }\n");
3180         } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) {
3181             my $callbackClassName = GetCallbackClassName($argType);
3182             $implIncludes{"$callbackClassName.h"} = 1;
3183             if ($optional) {
3184                 push(@$outputArray, "    RefPtr<$argType> $name;\n");
3185                 push(@$outputArray, "    if (!exec->argument($argsIndex).isUndefinedOrNull()) {\n");
3186                 push(@$outputArray, "        if (!exec->uncheckedArgument($argsIndex).isFunction())\n");
3187                 push(@$outputArray, "            return throwVMTypeError(exec);\n");
3188                 if ($function->isStatic) {
3189                     AddToImplIncludes("CallbackFunction.h");
3190                     push(@$outputArray, "        $name = createFunctionOnlyCallback<${callbackClassName}>(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->uncheckedArgument($argsIndex));\n");
3191                 } else {
3192                     push(@$outputArray, "        $name = ${callbackClassName}::create(asObject(exec->uncheckedArgument($argsIndex)), castedThis->globalObject());\n");
3193                 }
3194                 push(@$outputArray, "    }\n");
3195             } else {
3196                 push(@$outputArray, "    if (!exec->argument($argsIndex).isFunction())\n");
3197                 push(@$outputArray, "        return throwVMTypeError(exec);\n");
3198                 if ($function->isStatic) {
3199                     AddToImplIncludes("CallbackFunction.h");
3200                     push(@$outputArray, "    RefPtr<$argType> $name = createFunctionOnlyCallback<${callbackClassName}>(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->uncheckedArgument($argsIndex));\n");
3201                 } else {
3202                     push(@$outputArray, "    RefPtr<$argType> $name = ${callbackClassName}::create(asObject(exec->uncheckedArgument($argsIndex)), castedThis->globalObject());\n");
3203                 }
3204             }
3205         } elsif ($parameter->extendedAttributes->{"Clamp"}) {
3206             my $nativeValue = "${name}NativeValue";
3207             push(@$outputArray, "    $argType $name = 0;\n");
3208             push(@$outputArray, "    double $nativeValue = exec->argument($argsIndex).toNumber(exec);\n");
3209             push(@$outputArray, "    if (UNLIKELY(exec->hadException()))\n");
3210             push(@$outputArray, "        return JSValue::encode(jsUndefined());\n\n");
3211             push(@$outputArray, "    if (!std::isnan($nativeValue))\n");
3212             push(@$outputArray, "        $name = clampTo<$argType>($nativeValue);\n\n");
3213         } elsif ($parameter->isVariadic) {
3214             my $nativeElementType;
3215             if ($argType eq "DOMString") {
3216                 $nativeElementType = "String";
3217             } else {
3218                 $nativeElementType = GetNativeType($argType);
3219             }
3220
3221             if (!IsNativeType($argType)) {
3222                 push(@$outputArray, "    Vector<$nativeElementType> $name;\n");
3223                 push(@$outputArray, "    for (unsigned i = $argsIndex, count = exec->argumentCount(); i < count; ++i) {\n");
3224                 push(@$outputArray, "        if (!exec->uncheckedArgument(i).inherits(JS${argType}::info()))\n");
3225                 push(@$outputArray, "            return throwVMTypeError(exec);\n");
3226                 push(@$outputArray, "        $name.append(to$argType(exec->uncheckedArgument(i)));\n");
3227                 push(@$outputArray, "    }\n")
3228             } else {
3229                 push(@$outputArray, "    Vector<$nativeElementType> $name = toNativeArguments<$nativeElementType>(exec, $argsIndex);\n");
3230                 # Check if the type conversion succeeded.
3231                 push(@$outputArray, "    if (UNLIKELY(exec->hadException()))\n");
3232                 push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3233             }
3234
3235         } elsif ($codeGenerator->IsEnumType($argType)) {
3236             $implIncludes{"<runtime/Error.h>"} = 1;
3237
3238             my $argValue = "exec->argument($argsIndex)";
3239             push(@$outputArray, "    const String ${name}(${argValue}.isEmpty() ? String() : ${argValue}.toString(exec)->value(exec));\n");
3240             push(@$outputArray, "    if (UNLIKELY(exec->hadException()))\n");
3241             push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3242
3243             my @enumValues = $codeGenerator->ValidEnumValues($argType);
3244             my @enumChecks = ();
3245             foreach my $enumValue (@enumValues) {
3246                 push(@enumChecks, "${name} != \"$enumValue\"");
3247             }
3248             push (@$outputArray, "    if (" . join(" && ", @enumChecks) . ")\n");
3249             push (@$outputArray, "        return throwVMTypeError(exec);\n");
3250         } else {
3251             # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
3252             # interface type, then if the incoming value does not implement that interface, a TypeError
3253             # is thrown rather than silently passing NULL to the C++ code.
3254             # Per the Web IDL and ECMAScript semantics, incoming values can always be converted to both
3255             # strings and numbers, so do not throw TypeError if the argument is of these types.
3256             if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
3257                 $implIncludes{"<runtime/Error.h>"} = 1;
3258
3259                 my $argValue = "exec->argument($argsIndex)";
3260                 if ($codeGenerator->IsWrapperType($argType)) {
3261                     push(@$outputArray, "    if (exec->argumentCount() > $argsIndex && !${argValue}.isUndefinedOrNull() && !${argValue}.inherits(JS${argType}::info()))\n");
3262                     push(@$outputArray, "        return throwVMTypeError(exec);\n");
3263                 }
3264             }
3265
3266             push(@$outputArray, "    " . GetNativeTypeFromSignature($parameter) . " $name(" . JSValueToNative($parameter, $optional && $defaultAttribute && $defaultAttribute eq "NullString" ? "argumentOrNull(exec, $argsIndex)" : "exec->argument($argsIndex)") . ");\n");
3267
3268             # If a parameter is "an index" and it's negative it should throw an INDEX_SIZE_ERR exception.
3269             # But this needs to be done in the bindings, because the type is unsigned and the fact that it
3270             # was negative will be lost by the time we're inside the DOM.
3271             if ($parameter->extendedAttributes->{"IsIndex"}) {
3272                 push(@$outputArray, "    if ($name < 0) {\n");
3273                 push(@$outputArray, "        setDOMException(exec, INDEX_SIZE_ERR);\n");
3274                 push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3275                 push(@$outputArray, "    }\n");
3276             }
3277
3278             # Check if the type conversion succeeded.
3279             push(@$outputArray, "    if (UNLIKELY(exec->hadException()))\n");
3280             push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3281
3282             if ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $interfaceName =~ /List$/) {
3283                 push(@$outputArray, "    if (!$name) {\n");
3284                 push(@$outputArray, "        setDOMException(exec, TYPE_MISMATCH_ERR);\n");
3285                 push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3286                 push(@$outputArray, "    }\n");
3287             }
3288         }
3289
3290         if ($argType eq "NodeFilter" || ($codeGenerator->IsTypedArrayType($argType) and not $argType eq "ArrayBuffer")) {
3291             push @arguments, "$name.get()";
3292         } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $interfaceName =~ /List$/) {
3293             push @arguments, "$name->propertyReference()";
3294         } else {
3295             push @arguments, $name;
3296         }
3297         $argsIndex++;
3298     }
3299
3300     push(@arguments, "ec") if $raisesException;
3301
3302     return ("$functionName(" . join(", ", @arguments) . ")", scalar @arguments);
3303 }
3304
3305 sub GenerateCallbackHeader
3306 {
3307     my $object = shift;
3308     my $interface = shift;
3309
3310     my $interfaceName = $interface->name;
3311     my $className = "JS$interfaceName";
3312
3313     # - Add default header template and header protection
3314     push(@headerContentHeader, GenerateHeaderContentHeader($interface));
3315
3316     $headerIncludes{"ActiveDOMCallback.h"} = 1;
3317     $headerIncludes{"$interfaceName.h"} = 1;
3318     $headerIncludes{"JSCallbackData.h"} = 1;
3319     $headerIncludes{"<wtf/Forward.h>"} = 1;
3320
3321     push(@headerContent, "\nnamespace WebCore {\n\n");
3322     push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
3323     push(@headerContent, "public:\n");
3324
3325     # The static create() method.
3326     push(@headerContent, "    static PassRefPtr<$className> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject)\n");
3327     push(@headerContent, "    {\n");
3328     push(@headerContent, "        return adoptRef(new $className(callback, globalObject));\n");
3329     push(@headerContent, "    }\n\n");
3330
3331     # ScriptExecutionContext
3332     push(@headerContent, "    virtual ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); }\n\n");
3333
3334     # Destructor
3335     push(@headerContent, "    virtual ~$className();\n");
3336
3337     if ($interface->extendedAttributes->{"CallbackNeedsOperatorEqual"}) {
3338         push(@headerContent, "    virtual bool operator==(const $interfaceName&) const;\n\n")
3339     }
3340
3341     # Functions
3342     my $numFunctions = @{$interface->functions};
3343     if ($numFunctions > 0) {
3344         push(@headerContent, "\n    // Functions\n");
3345         foreach my $function (@{$interface->functions}) {
3346             my @params = @{$function->parameters};
3347             if (!$function->signature->extendedAttributes->{"Custom"} &&
3348                 !(GetNativeType($function->signature->type) eq "bool")) {
3349                 push(@headerContent, "    COMPILE_ASSERT(false)");
3350             }
3351
3352             push(@headerContent, "    virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "(");
3353
3354             my @args = ();
3355             foreach my $param (@params) {
3356                 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
3357             }
3358             push(@headerContent, join(", ", @args));
3359
3360             push(@headerContent, ");\n");
3361         }
3362     }
3363
3364     push(@headerContent, "\nprivate:\n");
3365
3366     # Constructor
3367     push(@headerContent, "    $className(JSC::JSObject* callback, JSDOMGlobalObject*);\n\n");
3368
3369     # Private members
3370     push(@headerContent, "    JSCallbackData* m_data;\n");
3371     push(@headerContent, "};\n\n");
3372
3373     push(@headerContent, "} // namespace WebCore\n\n");
3374     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
3375     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
3376     push(@headerContent, "#endif\n");
3377 }
3378
3379 sub GenerateCallbackImplementation
3380 {
3381     my ($object, $interface) = @_;
3382
3383     my $interfaceName = $interface->name;
3384     my $className = "JS$interfaceName";
3385
3386     # - Add default header template
3387     push(@implContentHeader, GenerateImplementationContentHeader($interface));
3388
3389     $implIncludes{"ScriptExecutionContext.h"} = 1;
3390     $implIncludes{"<runtime/JSLock.h>"} = 1;
3391
3392     @implContent = ();
3393
3394     push(@implContent, "\nusing namespace JSC;\n\n");
3395     push(@implContent, "namespace WebCore {\n\n");
3396
3397     # Constructor
3398     push(@implContent, "${className}::${className}(JSObject* callback, JSDOMGlobalObject* globalObject)\n");
3399     if ($interface->extendedAttributes->{"CallbackNeedsOperatorEqual"}) {
3400         push(@implContent, "    : ${interfaceName}(${className}Type)\n");