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