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