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