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