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