1#
2# Copyright (C) 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
4# Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
5# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
6# Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
7# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
8# Copyright (C) Research In Motion Limited 2010. All rights reserved.
9# Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
10# Copyright (C) 2011 Patrick Gansterer <paroga@webkit.org>
11# Copyright (C) 2012 Ericsson AB. All rights reserved.
12# Copyright (C) 2007, 2008, 2009, 2012 Google Inc.
13# Copyright (C) 2013 Samsung Electronics. All rights reserved.
14#
15# This library is free software; you can redistribute it and/or
16# modify it under the terms of the GNU Library General Public
17# License as published by the Free Software Foundation; either
18# version 2 of the License, or (at your option) any later version.
19#
20# This library is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23# Library General Public License for more details.
24#
25# You should have received a copy of the GNU Library General Public License
26# along with this library; see the file COPYING.LIB.  If not, write to
27# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28# Boston, MA 02110-1301, USA.
29
30package CodeGeneratorJS;
31
32use strict;
33use constant FileNamePrefix => "JS";
34use Hasher;
35
36my $codeGenerator;
37
38my $writeDependencies = 0;
39
40my @headerContentHeader = ();
41my @headerContent = ();
42my %headerIncludes = ();
43my %headerTrailingIncludes = ();
44
45my @implContentHeader = ();
46my @implContent = ();
47my %implIncludes = ();
48my @depsContent = ();
49my $numCachedAttributes = 0;
50my $currentCachedAttribute = 0;
51
52# Default .h template
53my $headerTemplate = << "EOF";
54/*
55    This file is part of the WebKit open source project.
56    This file has been generated by generate-bindings.pl. DO NOT MODIFY!
57
58    This library is free software; you can redistribute it and/or
59    modify it under the terms of the GNU Library General Public
60    License as published by the Free Software Foundation; either
61    version 2 of the License, or (at your option) any later version.
62
63    This library is distributed in the hope that it will be useful,
64    but WITHOUT ANY WARRANTY; without even the implied warranty of
65    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
66    Library General Public License for more details.
67
68    You should have received a copy of the GNU Library General Public License
69    along with this library; see the file COPYING.LIB.  If not, write to
70    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
71    Boston, MA 02110-1301, USA.
72*/
73EOF
74
75# Default constructor
76sub new
77{
78    my $object = shift;
79    my $reference = { };
80
81    $codeGenerator = shift;
82    shift; # $useLayerOnTop
83    shift; # $preprocessor
84    $writeDependencies = shift;
85
86    bless($reference, $object);
87    return $reference;
88}
89
90sub GenerateInterface
91{
92    my $object = shift;
93    my $interface = shift;
94    my $defines = shift;
95
96    $codeGenerator->LinkOverloadedFunctions($interface);
97
98    # Start actual generation
99    if ($interface->isCallback) {
100        $object->GenerateCallbackHeader($interface);
101        $object->GenerateCallbackImplementation($interface);
102    } else {
103        $object->GenerateHeader($interface);
104        $object->GenerateImplementation($interface);
105    }
106}
107
108sub GenerateAttributeEventListenerCall
109{
110    my $className = shift;
111    my $implSetterFunctionName = shift;
112    my $windowEventListener = shift;
113
114    my $wrapperObject = $windowEventListener ? "globalObject" : "thisObject";
115    my @GenerateEventListenerImpl = ();
116
117    if ($className eq "JSSVGElementInstance") {
118        # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement
119        $wrapperObject = "asObject(correspondingElementWrapper)";
120
121        push(@GenerateEventListenerImpl, <<END);
122    JSValue correspondingElementWrapper = toJS(exec, castedThis->globalObject(), impl->correspondingElement());
123    if (correspondingElementWrapper.isObject())
124END
125
126        # Add leading whitespace to format the impl->set... line correctly
127        push(@GenerateEventListenerImpl, "    ");
128    }
129
130    push(@GenerateEventListenerImpl, "    impl->set$implSetterFunctionName(createJSAttributeEventListener(exec, value, $wrapperObject));\n");
131    return @GenerateEventListenerImpl;
132}
133
134sub GenerateEventListenerCall
135{
136    my $className = shift;
137    my $functionName = shift;
138    my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
139
140    $implIncludes{"JSEventListener.h"} = 1;
141
142    my @GenerateEventListenerImpl = ();
143    my $wrapperObject = "castedThis";
144    if ($className eq "JSSVGElementInstance") {
145        # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement
146        $wrapperObject = "asObject(correspondingElementWrapper)";
147
148        push(@GenerateEventListenerImpl, <<END);
149    JSValue correspondingElementWrapper = toJS(exec, castedThis->globalObject(), impl->correspondingElement());
150    if (!correspondingElementWrapper.isObject())
151        return JSValue::encode(jsUndefined());
152END
153    }
154
155    push(@GenerateEventListenerImpl, <<END);
156    JSValue listener = exec->argument(1);
157    if (!listener.isObject())
158        return JSValue::encode(jsUndefined());
159    impl->${functionName}EventListener(exec->argument(0).toString(exec)->value(exec), JSEventListener::create(asObject(listener), $wrapperObject, false, currentWorld(exec))$passRefPtrHandling, exec->argument(2).toBoolean(exec));
160    return JSValue::encode(jsUndefined());
161END
162    return @GenerateEventListenerImpl;
163}
164
165sub GetParentClassName
166{
167    my $interface = shift;
168
169    return $interface->extendedAttributes->{"JSLegacyParent"} if $interface->extendedAttributes->{"JSLegacyParent"};
170    return "JSDOMWrapper" if (@{$interface->parents} eq 0);
171    return "JS" . $interface->parents(0);
172}
173
174sub GetCallbackClassName
175{
176    my $className = shift;
177
178    return "JS$className";
179}
180
181sub IndexGetterReturnsStrings
182{
183    my $type = shift;
184
185    return 1 if $type eq "CSSStyleDeclaration" or $type eq "MediaList" or $type eq "DOMStringList" or $type eq "DOMTokenList" or $type eq "DOMSettableTokenList";
186    return 0;
187}
188
189sub AddIncludesForTypeInImpl
190{
191    my $type = shift;
192    my $isCallback = @_ ? shift : 0;
193
194    AddIncludesForType($type, $isCallback, \%implIncludes);
195}
196
197sub AddIncludesForTypeInHeader
198{
199    my $type = shift;
200    my $isCallback = @_ ? shift : 0;
201
202    AddIncludesForType($type, $isCallback, \%headerIncludes);
203}
204
205my %typesWithoutHeader = (
206    "Array" => 1,
207    "DOMString" => 1,
208    "DOMTimeStamp" => 1,
209    "any" => 1
210);
211
212sub SkipIncludeHeader
213{
214    my $type = shift;
215
216    return 1 if $codeGenerator->SkipIncludeHeader($type);
217    return 1 if $codeGenerator->GetSequenceType($type) or $codeGenerator->GetArrayType($type);
218    return $typesWithoutHeader{$type};
219}
220
221sub AddIncludesForType
222{
223    my $type = shift;
224    my $isCallback = shift;
225    my $includesRef = shift;
226
227    return if SkipIncludeHeader($type);
228
229    # When we're finished with the one-file-per-class
230    # reorganization, we won't need these special cases.
231    if ($type =~ /SVGPathSeg/) {
232        my $joinedName = $type;
233        $joinedName =~ s/Abs|Rel//;
234        $includesRef->{"${joinedName}.h"} = 1;
235    } elsif ($type eq "XPathNSResolver") {
236        $includesRef->{"JSXPathNSResolver.h"} = 1;
237        $includesRef->{"JSCustomXPathNSResolver.h"} = 1;
238    } elsif ($isCallback && $codeGenerator->IsWrapperType($type)) {
239        $includesRef->{"JS${type}.h"} = 1;
240    } elsif ($codeGenerator->IsTypedArrayType($type)) {
241        $includesRef->{"<wtf/${type}.h>"} = 1;
242    } else {
243        # default, include the same named file
244        $includesRef->{"${type}.h"} = 1;
245    }
246}
247
248sub AddToImplIncludes
249{
250    my $header = shift;
251    my $conditional = shift;
252
253    if (not $conditional) {
254        $implIncludes{$header} = 1;
255    } elsif (not exists($implIncludes{$header})) {
256        $implIncludes{$header} = $conditional;
257    } else {
258        my $oldValue = $implIncludes{$header};
259        if ($oldValue ne 1) {
260            my %newValue = ();
261            $newValue{$conditional} = 1;
262            foreach my $condition (split(/\|/, $oldValue)) {
263                $newValue{$condition} = 1;
264            }
265            $implIncludes{$header} = join("|", sort keys %newValue);
266        }
267    }
268}
269
270sub IsScriptProfileType
271{
272    my $type = shift;
273    return 1 if ($type eq "ScriptProfileNode");
274    return 0;
275}
276
277sub IsReadonly
278{
279    my $attribute = shift;
280    return $attribute->isReadOnly && !$attribute->signature->extendedAttributes->{"Replaceable"};
281}
282
283sub AddTypedefForScriptProfileType
284{
285    my $type = shift;
286    (my $jscType = $type) =~ s/Script//;
287
288    push(@headerContent, "typedef JSC::$jscType $type;\n\n");
289}
290
291sub AddClassForwardIfNeeded
292{
293    my $interfaceName = shift;
294
295    # SVGAnimatedLength/Number/etc. are typedefs to SVGAnimatedTemplate, so don't use class forwards for them!
296    unless ($codeGenerator->IsSVGAnimatedType($interfaceName) or IsScriptProfileType($interfaceName) or $codeGenerator->IsTypedArrayType($interfaceName)) {
297        push(@headerContent, "class $interfaceName;\n\n");
298    # ScriptProfile and ScriptProfileNode are typedefs to JSC::Profile and JSC::ProfileNode.
299    } elsif (IsScriptProfileType($interfaceName)) {
300        $headerIncludes{"<profiler/ProfileNode.h>"} = 1;
301        AddTypedefForScriptProfileType($interfaceName);
302    }
303}
304
305sub hashTableAccessor
306{
307    my $noStaticTables = shift;
308    my $className = shift;
309    if ($noStaticTables) {
310        return "get${className}Table(exec)";
311    } else {
312        return "&${className}Table";
313    }
314}
315
316sub prototypeHashTableAccessor
317{
318    my $noStaticTables = shift;
319    my $className = shift;
320    if ($noStaticTables) {
321        return "get${className}PrototypeTable(exec)";
322    } else {
323        return "&${className}PrototypeTable";
324    }
325}
326
327sub constructorHashTableAccessor
328{
329    my $noStaticTables = shift;
330    my $constructorClassName = shift;
331    if ($noStaticTables) {
332        return "get${constructorClassName}Table(exec)";
333    } else {
334        return "&${constructorClassName}Table";
335    }
336}
337
338sub GetGenerateIsReachable
339{
340    my $interface = shift;
341    return $interface->extendedAttributes->{"GenerateIsReachable"};
342}
343
344sub GetCustomIsReachable
345{
346    my $interface = shift;
347    return $interface->extendedAttributes->{"CustomIsReachable"};
348}
349
350sub GenerateGetOwnPropertySlotBody
351{
352    my ($interface, $interfaceName, $className, $hasAttributes, $inlined) = @_;
353
354    my $namespaceMaybe = ($inlined ? "JSC::" : "");
355    my $namedGetterFunction = GetNamedGetterFunction($interface);
356    my $indexedGetterFunction = GetIndexedGetterFunction($interface);
357    my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
358
359    my @getOwnPropertySlotImpl = ();
360
361    if ($interfaceName eq "NamedNodeMap" or $interfaceName =~ /^HTML\w*Collection$/) {
362        push(@getOwnPropertySlotImpl, "    ${namespaceMaybe}JSValue proto = thisObject->prototype();\n");
363        push(@getOwnPropertySlotImpl, "    if (proto.isObject() && jsCast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n");
364        push(@getOwnPropertySlotImpl, "        return false;\n\n");
365    }
366
367    my $manualLookupGetterGeneration = sub {
368        my $requiresManualLookup = ($indexedGetterFunction && !$hasNumericIndexedGetter) || $namedGetterFunction;
369        if ($requiresManualLookup) {
370            push(@getOwnPropertySlotImpl, "    const ${namespaceMaybe}HashEntry* entry = getStaticValueSlotEntryWithoutCaching<$className>(exec, propertyName);\n");
371            push(@getOwnPropertySlotImpl, "    if (entry) {\n");
372            push(@getOwnPropertySlotImpl, "        slot.setCustom(thisObject, entry->propertyGetter());\n");
373            push(@getOwnPropertySlotImpl, "        return true;\n");
374            push(@getOwnPropertySlotImpl, "    }\n");
375        }
376    };
377
378    if (!$interface->extendedAttributes->{"CustomNamedGetter"}) {
379        &$manualLookupGetterGeneration();
380    }
381
382    if ($indexedGetterFunction) {
383        push(@getOwnPropertySlotImpl, "    unsigned index = propertyName.asIndex();\n");
384
385        # If the item function returns a string then we let the TreatReturnedNullStringAs handle the cases
386        # where the index is out of range.
387        if (IndexGetterReturnsStrings($interfaceName)) {
388            push(@getOwnPropertySlotImpl, "    if (index != PropertyName::NotAnIndex) {\n");
389        } else {
390            push(@getOwnPropertySlotImpl, "    if (index != PropertyName::NotAnIndex && index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n");
391        }
392        if ($hasNumericIndexedGetter) {
393            push(@getOwnPropertySlotImpl, "        slot.setValue(thisObject->getByIndex(exec, index));\n");
394        } else {
395            push(@getOwnPropertySlotImpl, "        slot.setCustomIndex(thisObject, index, indexGetter);\n");
396        }
397        push(@getOwnPropertySlotImpl, "        return true;\n");
398        push(@getOwnPropertySlotImpl, "    }\n");
399    }
400
401    if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
402        push(@getOwnPropertySlotImpl, "    if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n");
403        push(@getOwnPropertySlotImpl, "        slot.setCustom(thisObject, thisObject->nameGetter);\n");
404        push(@getOwnPropertySlotImpl, "        return true;\n");
405        push(@getOwnPropertySlotImpl, "    }\n");
406        if ($inlined) {
407            $headerIncludes{"wtf/text/AtomicString.h"} = 1;
408        } else {
409            $implIncludes{"wtf/text/AtomicString.h"} = 1;
410        }
411    }
412
413    if ($interface->extendedAttributes->{"CustomNamedGetter"}) {
414        &$manualLookupGetterGeneration();
415    }
416
417    if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
418        push(@getOwnPropertySlotImpl, "    if (thisObject->getOwnPropertySlotDelegate(exec, propertyName, slot))\n");
419        push(@getOwnPropertySlotImpl, "        return true;\n");
420    }
421
422    if ($hasAttributes) {
423        if ($inlined) {
424            die "Cannot inline if NoStaticTables is set." if ($interface->extendedAttributes->{"JSNoStaticTables"});
425            push(@getOwnPropertySlotImpl, "    return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, s_info.staticPropHashTable, thisObject, propertyName, slot);\n");
426        } else {
427            push(@getOwnPropertySlotImpl, "    return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, " . hashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
428        }
429    } else {
430        push(@getOwnPropertySlotImpl, "    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");
431    }
432
433    return @getOwnPropertySlotImpl;
434}
435
436sub GenerateGetOwnPropertyDescriptorBody
437{
438    my ($interface, $interfaceName, $className, $hasAttributes, $inlined) = @_;
439
440    my $namespaceMaybe = ($inlined ? "JSC::" : "");
441    my $namedGetterFunction = GetNamedGetterFunction($interface);
442    my $indexedGetterFunction = GetIndexedGetterFunction($interface);
443    my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
444
445
446    my @getOwnPropertyDescriptorImpl = ();
447    if ($interface->extendedAttributes->{"CheckSecurity"}) {
448        if ($interfaceName eq "DOMWindow") {
449            $implIncludes{"BindingSecurity.h"} = 1;
450            push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, jsCast<$className*>(thisObject)->impl()))\n");
451        } else {
452            push(@implContent, "    if (!shouldAllowAccessToFrame(exec, thisObject->impl()->frame()))\n");
453        }
454        push(@implContent, "        return false;\n");
455    }
456
457    if ($interfaceName eq "NamedNodeMap" or $interfaceName =~ /^HTML\w*Collection$/) {
458        push(@getOwnPropertyDescriptorImpl, "    ${namespaceMaybe}JSValue proto = thisObject->prototype();\n");
459        push(@getOwnPropertyDescriptorImpl, "    if (proto.isObject() && jsCast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n");
460        push(@getOwnPropertyDescriptorImpl, "        return false;\n\n");
461    }
462
463    my $manualLookupGetterGeneration = sub {
464        my $requiresManualLookup = ($indexedGetterFunction && !$hasNumericIndexedGetter) || $namedGetterFunction;
465        if ($requiresManualLookup) {
466            push(@getOwnPropertyDescriptorImpl, "    const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n");
467            push(@getOwnPropertyDescriptorImpl, "    if (entry) {\n");
468            push(@getOwnPropertyDescriptorImpl, "        PropertySlot slot;\n");
469            push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(thisObject, entry->propertyGetter());\n");
470            push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());\n");
471            push(@getOwnPropertyDescriptorImpl, "        return true;\n");
472            push(@getOwnPropertyDescriptorImpl, "    }\n");
473        }
474    };
475
476    if (!$interface->extendedAttributes->{"CustomNamedGetter"}) {
477        &$manualLookupGetterGeneration();
478    }
479
480    if ($indexedGetterFunction) {
481        push(@getOwnPropertyDescriptorImpl, "    unsigned index = propertyName.asIndex();\n");
482        push(@getOwnPropertyDescriptorImpl, "    if (index != PropertyName::NotAnIndex && index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n");
483        if ($hasNumericIndexedGetter) {
484            # Assume that if there's a setter, the index will be writable
485            if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
486                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(thisObject->getByIndex(exec, index), ${namespaceMaybe}DontDelete);\n");
487            } else {
488                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(thisObject->getByIndex(exec, index), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n");
489            }
490        } else {
491            push(@getOwnPropertyDescriptorImpl, "        ${namespaceMaybe}PropertySlot slot;\n");
492            push(@getOwnPropertyDescriptorImpl, "        slot.setCustomIndex(thisObject, index, indexGetter);\n");
493            # Assume that if there's a setter, the index will be writable
494            if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
495                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete);\n");
496            } else {
497                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n");
498            }
499        }
500        push(@getOwnPropertyDescriptorImpl, "        return true;\n");
501        push(@getOwnPropertyDescriptorImpl, "    }\n");
502    }
503
504    if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
505        push(@getOwnPropertyDescriptorImpl, "    if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n");
506        push(@getOwnPropertyDescriptorImpl, "        ${namespaceMaybe}PropertySlot slot;\n");
507        push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(thisObject, nameGetter);\n");
508        push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);\n");
509        push(@getOwnPropertyDescriptorImpl, "        return true;\n");
510        push(@getOwnPropertyDescriptorImpl, "    }\n");
511        if ($inlined) {
512            $headerIncludes{"wtf/text/AtomicString.h"} = 1;
513        } else {
514            $implIncludes{"wtf/text/AtomicString.h"} = 1;
515        }
516    }
517
518    if ($interface->extendedAttributes->{"CustomNamedGetter"}) {
519        &$manualLookupGetterGeneration();
520    }
521
522    if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
523        push(@getOwnPropertyDescriptorImpl, "    if (thisObject->getOwnPropertyDescriptorDelegate(exec, propertyName, descriptor))\n");
524        push(@getOwnPropertyDescriptorImpl, "        return true;\n");
525    }
526
527    if ($hasAttributes) {
528        if ($inlined) {
529            die "Cannot inline if NoStaticTables is set." if ($interface->extendedAttributes->{"JSNoStaticTables"});
530            push(@getOwnPropertyDescriptorImpl, "    return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, s_info.staticPropHashTable, thisObject, propertyName, descriptor);\n");
531        } else {
532            push(@getOwnPropertyDescriptorImpl, "    return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, " . hashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n");
533        }
534    } else {
535        push(@getOwnPropertyDescriptorImpl, "    return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);\n");
536    }
537
538    return @getOwnPropertyDescriptorImpl;
539}
540
541sub GenerateHeaderContentHeader
542{
543    my $interface = shift;
544    my $className = "JS" . $interface->name;
545
546    my @headerContentHeader = split("\r", $headerTemplate);
547
548    # - Add header protection
549    push(@headerContentHeader, "\n#ifndef $className" . "_h");
550    push(@headerContentHeader, "\n#define $className" . "_h\n\n");
551
552    my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
553    push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
554    return @headerContentHeader;
555}
556
557sub GenerateImplementationContentHeader
558{
559    my $interface = shift;
560    my $className = "JS" . $interface->name;
561
562    my @implContentHeader = split("\r", $headerTemplate);
563
564    push(@implContentHeader, "\n#include \"config.h\"\n");
565    my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
566    push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;
567    push(@implContentHeader, "#include \"$className.h\"\n\n");
568    return @implContentHeader;
569}
570
571my %usesToJSNewlyCreated = (
572    "CDATASection" => 1,
573    "Element" => 1,
574    "Node" => 1,
575    "Text" => 1,
576    "Touch" => 1,
577    "TouchList" => 1
578);
579
580sub ShouldGenerateToJSDeclaration
581{
582    my ($hasParent, $interface) = @_;
583    return 0 if ($interface->extendedAttributes->{"SuppressToJSObject"});
584    return 1 if (!$hasParent or $interface->extendedAttributes->{"JSGenerateToJSObject"} or $interface->extendedAttributes->{"CustomToJSObject"});
585    return 0;
586}
587
588sub ShouldGenerateToJSImplementation
589{
590    my ($hasParent, $interface) = @_;
591    return 0 if ($interface->extendedAttributes->{"SuppressToJSObject"});
592    return 1 if ((!$hasParent or $interface->extendedAttributes->{"JSGenerateToJSObject"}) and !$interface->extendedAttributes->{"CustomToJSObject"});
593    return 0;
594}
595
596sub GetAttributeGetterName
597{
598    my ($interfaceName, $className, $attribute) = @_;
599    if ($attribute->isStatic) {
600        return $codeGenerator->WK_lcfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name);
601    }
602    return "js" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
603}
604
605sub GetAttributeSetterName
606{
607    my ($interfaceName, $className, $attribute) = @_;
608    if ($attribute->isStatic) {
609        return "set" . $codeGenerator->WK_ucfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name);
610    }
611    return "setJS" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
612}
613
614sub GetFunctionName
615{
616    my ($className, $function) = @_;
617    my $kind = $function->isStatic ? "Constructor" : "Prototype";
618    return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($function->signature->name);
619}
620
621sub GetSpecialAccessorFunctionForType
622{
623    my $interface = shift;
624    my $special = shift;
625    my $firstParameterType = shift;
626    my $numberOfParameters = shift;
627
628    foreach my $function (@{$interface->functions}, @{$interface->anonymousFunctions}) {
629        my $specials = $function->signature->specials;
630        my $specialExists = grep { $_ eq $special } @$specials;
631        my $parameters = $function->parameters;
632        if ($specialExists and scalar(@$parameters) == $numberOfParameters and $parameters->[0]->type eq $firstParameterType) {
633            return $function;
634        }
635    }
636
637    return 0;
638}
639
640sub GetIndexedGetterFunction
641{
642    my $interface = shift;
643    return GetSpecialAccessorFunctionForType($interface, "getter", "unsigned long", 1);
644}
645
646sub GetNamedGetterFunction
647{
648    my $interface = shift;
649    return GetSpecialAccessorFunctionForType($interface, "getter", "DOMString", 1);
650}
651
652sub GenerateHeader
653{
654    my $object = shift;
655    my $interface = shift;
656
657    my $interfaceName = $interface->name;
658    my $className = "JS$interfaceName";
659    my @ancestorInterfaceNames = ();
660    my %structureFlags = ();
661
662    # We only support multiple parents with SVG (for now).
663    if (@{$interface->parents} > 1) {
664        die "A class can't have more than one parent" unless $interfaceName =~ /SVG/;
665        $codeGenerator->AddMethodsConstantsAndAttributesFromParentInterfaces($interface, \@ancestorInterfaceNames);
666    }
667
668    my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
669    my $hasRealParent = @{$interface->parents} > 0;
670    my $hasParent = $hasLegacyParent || $hasRealParent;
671    my $parentClassName = GetParentClassName($interface);
672    my $needsMarkChildren = $interface->extendedAttributes->{"JSCustomMarkFunction"} || $interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget";
673
674    # - Add default header template and header protection
675    push(@headerContentHeader, GenerateHeaderContentHeader($interface));
676
677    if ($hasParent) {
678        $headerIncludes{"$parentClassName.h"} = 1;
679    } else {
680        $headerIncludes{"JSDOMBinding.h"} = 1;
681        $headerIncludes{"<runtime/JSGlobalObject.h>"} = 1;
682        if ($interface->isException) {
683            $headerIncludes{"<runtime/ErrorPrototype.h>"} = 1;
684        } else {
685            $headerIncludes{"<runtime/ObjectPrototype.h>"} = 1;
686        }
687    }
688
689    if ($interface->extendedAttributes->{"CustomCall"}) {
690        $headerIncludes{"<runtime/CallData.h>"} = 1;
691    }
692
693    if ($interface->extendedAttributes->{"JSInlineGetOwnPropertySlot"}) {
694        $headerIncludes{"<runtime/Lookup.h>"} = 1;
695    }
696
697    if ($hasParent && $interface->extendedAttributes->{"JSGenerateToNativeObject"}) {
698        if ($codeGenerator->IsTypedArrayType($interfaceName)) {
699            $headerIncludes{"<wtf/$interfaceName.h>"} = 1;
700        } else {
701            $headerIncludes{"$interfaceName.h"} = 1;
702        }
703    }
704
705    $headerIncludes{"<runtime/JSObject.h>"} = 1;
706    $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
707
708    my $implType = $interfaceName;
709    my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
710    $implType = $svgNativeType if $svgNativeType;
711
712    my $svgPropertyOrListPropertyType;
713    $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
714    $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
715
716    my $numConstants = @{$interface->constants};
717    my $numAttributes = @{$interface->attributes};
718    my $numFunctions = @{$interface->functions};
719
720    push(@headerContent, "\nnamespace WebCore {\n\n");
721
722    if ($codeGenerator->IsSVGAnimatedType($interfaceName)) {
723        $headerIncludes{"$interfaceName.h"} = 1;
724    } else {
725        # Implementation class forward declaration
726        if ($interfaceName eq "DOMWindow" || $interface->extendedAttributes->{"IsWorkerContext"}) {
727            AddClassForwardIfNeeded($interfaceName) unless $svgPropertyOrListPropertyType;
728        }
729    }
730
731    AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow";
732    AddClassForwardIfNeeded("JSDictionary") if $codeGenerator->IsConstructorTemplate($interface, "Event");
733
734    # Class declaration
735    push(@headerContent, "class $className : public $parentClassName {\n");
736
737    # Static create methods
738    push(@headerContent, "public:\n");
739    push(@headerContent, "    typedef $parentClassName Base;\n");
740    if ($interfaceName eq "DOMWindow") {
741        push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* windowShell)\n");
742        push(@headerContent, "    {\n");
743        push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, impl, windowShell);\n");
744        push(@headerContent, "        ptr->finishCreation(vm, windowShell);\n");
745        push(@headerContent, "        vm.heap.addFinalizer(ptr, destroy);\n");
746        push(@headerContent, "        return ptr;\n");
747        push(@headerContent, "    }\n\n");
748    } elsif ($interface->extendedAttributes->{"IsWorkerContext"}) {
749        push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, PassRefPtr<$implType> impl)\n");
750        push(@headerContent, "    {\n");
751        push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, impl);\n");
752        push(@headerContent, "        ptr->finishCreation(vm);\n");
753        push(@headerContent, "        vm.heap.addFinalizer(ptr, destroy);\n");
754        push(@headerContent, "        return ptr;\n");
755        push(@headerContent, "    }\n\n");
756    } elsif ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
757        AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
758        push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
759        push(@headerContent, "    {\n");
760        push(@headerContent, "        globalObject->masqueradesAsUndefinedWatchpoint()->notifyWrite();\n");
761        push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, globalObject, impl);\n");
762        push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
763        push(@headerContent, "        return ptr;\n");
764        push(@headerContent, "    }\n\n");
765    } else {
766        AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
767        push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
768        push(@headerContent, "    {\n");
769        push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, globalObject, impl);\n");
770        push(@headerContent, "        ptr->finishCreation(globalObject->vm());\n");
771        push(@headerContent, "        return ptr;\n");
772        push(@headerContent, "    }\n\n");
773    }
774
775    if ($interfaceName eq "DOMWindow" || $interface->extendedAttributes->{"IsWorkerContext"}) {
776        push(@headerContent, "    static const bool needsDestruction = false;\n\n");
777    }
778
779    # Prototype
780    push(@headerContent, "    static JSC::JSObject* createPrototype(JSC::ExecState*, JSC::JSGlobalObject*);\n") unless ($interface->extendedAttributes->{"ExtendsDOMGlobalObject"});
781
782    $headerTrailingIncludes{"${className}Custom.h"} = 1 if $interface->extendedAttributes->{"JSCustomHeader"};
783
784    $implIncludes{"${className}Custom.h"} = 1 if !$interface->extendedAttributes->{"JSCustomHeader"} && ($interface->extendedAttributes->{"CustomPutFunction"} || $interface->extendedAttributes->{"CustomNamedSetter"});
785
786    my $namedGetterFunction = GetNamedGetterFunction($interface);
787    my $indexedGetterFunction = GetIndexedGetterFunction($interface);
788    my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
789
790    my $hasImpureNamedGetter =
791        $namedGetterFunction
792        || $interface->extendedAttributes->{"CustomNamedGetter"}
793        || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"};
794
795    my $hasComplexGetter =
796        $indexedGetterFunction
797        || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
798        || $hasImpureNamedGetter;
799
800    my $hasGetter = $numAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"} || $hasComplexGetter;
801
802    if ($hasImpureNamedGetter) {
803        $structureFlags{"JSC::HasImpureGetOwnPropertySlot"} = 1;
804    }
805
806    # Getters
807    if ($hasGetter) {
808        push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
809        push(@headerContent, "    static bool getOwnPropertyDescriptor(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&);\n");
810        push(@headerContent, "    static bool getOwnPropertySlotByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n") if ($hasComplexGetter);
811        push(@headerContent, "    bool getOwnPropertySlotDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n") if $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"};
812        push(@headerContent, "    bool getOwnPropertyDescriptorDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&);\n") if $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"};
813        $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
814        $structureFlags{"JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero"} = 1;
815    }
816
817    # Check if we have any writable properties
818    my $hasReadWriteProperties = 0;
819    foreach (@{$interface->attributes}) {
820        if (!IsReadonly($_) && !$_->isStatic) {
821            $hasReadWriteProperties = 1;
822        }
823    }
824
825    my $hasComplexSetter =
826        $interface->extendedAttributes->{"CustomPutFunction"}
827        || $interface->extendedAttributes->{"CustomNamedSetter"}
828        || $interface->extendedAttributes->{"CustomIndexedSetter"};
829
830    my $hasSetter = $hasReadWriteProperties || $hasComplexSetter;
831
832    # Getters
833    if ($hasSetter) {
834        push(@headerContent, "    static void put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
835        push(@headerContent, "    static void putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n") if ($hasComplexSetter);
836        push(@headerContent, "    bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n") if $interface->extendedAttributes->{"CustomNamedSetter"};
837    }
838
839    if (!$hasParent) {
840        push(@headerContent, "    static void destroy(JSC::JSCell*);\n");
841        push(@headerContent, "    ~${className}();\n");
842    }
843
844    # Class info
845    if ($interfaceName eq "Node") {
846        push(@headerContent, "    static WEBKIT_EXPORTDATA const JSC::ClassInfo s_info;\n\n");
847    } else {
848        push(@headerContent, "    static const JSC::ClassInfo s_info;\n\n");
849    }
850    # Structure ID
851    if ($interfaceName eq "DOMWindow") {
852        $structureFlags{"JSC::ImplementsHasInstance"} = 1;
853    }
854    push(@headerContent, "    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
855    push(@headerContent, "    {\n");
856    if ($interfaceName eq "DOMWindow" || $interface->extendedAttributes->{"IsWorkerContext"}) {
857        push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), &s_info);\n");
858    } else {
859        push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);\n");
860    }
861    push(@headerContent, "    }\n\n");
862
863    # Custom pushEventHandlerScope function
864    push(@headerContent, "    JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{"JSCustomPushEventHandlerScope"};
865
866    # Custom call functions
867    push(@headerContent, "    static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $interface->extendedAttributes->{"CustomCall"};
868
869    # Custom deleteProperty function
870    push(@headerContent, "    static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
871    push(@headerContent, "    static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
872
873    # Custom getPropertyNames function exists on DOMWindow
874    if ($interfaceName eq "DOMWindow") {
875        push(@headerContent, "    static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
876        $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
877    }
878
879    # Custom getOwnPropertyNames function
880    if ($interface->extendedAttributes->{"CustomEnumerateProperty"} || $indexedGetterFunction) {
881        push(@headerContent, "    static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
882        $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
883    }
884
885    # Custom defineOwnProperty function
886    push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnProperty"};
887
888    # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
889    if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
890        $structureFlags{"JSC::MasqueradesAsUndefined"} = 1;
891    }
892
893    # Constructor object getter
894    unless ($interface->extendedAttributes->{"NoInterfaceObject"}) {
895        push(@headerContent, "    static JSC::JSValue getConstructor(JSC::ExecState*, JSC::JSGlobalObject*);\n");
896        push(@headerContent, "    static JSC::JSValue getNamedConstructor(JSC::ExecState*, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{"NamedConstructor"};
897    }
898
899    my $numCustomFunctions = 0;
900    my $numCustomAttributes = 0;
901
902    # Attribute and function enums
903    if ($numAttributes > 0) {
904        foreach (@{$interface->attributes}) {
905            my $attribute = $_;
906            $numCustomAttributes++ if HasCustomGetter($attribute->signature->extendedAttributes);
907            $numCustomAttributes++ if HasCustomSetter($attribute->signature->extendedAttributes);
908            if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
909                my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
910                push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
911                push(@headerContent, "    JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->signature->name . ";\n");
912                $numCachedAttributes++;
913                $needsMarkChildren = 1;
914                push(@headerContent, "#endif\n") if $conditionalString;
915            }
916        }
917    }
918
919    # visit function
920    if ($needsMarkChildren) {
921        push(@headerContent, "    static void visitChildren(JSCell*, JSC::SlotVisitor&);\n\n");
922        $structureFlags{"JSC::OverridesVisitChildren"} = 1;
923    }
924
925    if ($numCustomAttributes > 0) {
926        push(@headerContent, "\n    // Custom attributes\n");
927
928        foreach my $attribute (@{$interface->attributes}) {
929            my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
930            if (HasCustomGetter($attribute->signature->extendedAttributes)) {
931                push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
932                my $methodName = $codeGenerator->WK_lcfirst($attribute->signature->name);
933                push(@headerContent, "    JSC::JSValue " . $methodName . "(JSC::ExecState*) const;\n");
934                push(@headerContent, "#endif\n") if $conditionalString;
935            }
936            if (HasCustomSetter($attribute->signature->extendedAttributes) && !IsReadonly($attribute)) {
937                push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
938                push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue);\n");
939                push(@headerContent, "#endif\n") if $conditionalString;
940            }
941        }
942    }
943
944    foreach my $function (@{$interface->functions}) {
945        $numCustomFunctions++ if HasCustomMethod($function->signature->extendedAttributes);
946    }
947
948    if ($numCustomFunctions > 0) {
949        push(@headerContent, "\n    // Custom functions\n");
950        foreach my $function (@{$interface->functions}) {
951            next unless HasCustomMethod($function->signature->extendedAttributes);
952            next if $function->{overloads} && $function->{overloadIndex} != 1;
953            my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
954            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
955            my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
956            push(@headerContent, "    " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState*);\n");
957            push(@headerContent, "#endif\n") if $conditionalString;
958        }
959    }
960
961    if (!$hasParent) {
962        push(@headerContent, "    $implType* impl() const { return m_impl; }\n");
963        push(@headerContent, "    void releaseImpl() { m_impl->deref(); m_impl = 0; }\n\n");
964        push(@headerContent, "    void releaseImplIfNotNull()\n");
965        push(@headerContent, "    {\n");
966        push(@headerContent, "        if (m_impl) {\n");
967        push(@headerContent, "            m_impl->deref();\n");
968        push(@headerContent, "            m_impl = 0;\n");
969        push(@headerContent, "        }\n");
970        push(@headerContent, "    }\n\n");
971        push(@headerContent, "private:\n");
972        push(@headerContent, "    $implType* m_impl;\n");
973    } elsif ($interface->extendedAttributes->{"JSGenerateToNativeObject"}) {
974        push(@headerContent, "    $interfaceName* impl() const\n");
975        push(@headerContent, "    {\n");
976        push(@headerContent, "        return static_cast<$interfaceName*>(Base::impl());\n");
977        push(@headerContent, "    }\n");
978    }
979
980    if ($codeGenerator->IsTypedArrayType($implType) and ($implType ne "ArrayBufferView") and ($implType ne "ArrayBuffer")) {
981        push(@headerContent, "    static const JSC::TypedArrayType TypedArrayStorageType = JSC::");
982        push(@headerContent, "TypedArrayInt8") if $implType eq "Int8Array";
983        push(@headerContent, "TypedArrayInt16") if $implType eq "Int16Array";
984        push(@headerContent, "TypedArrayInt32") if $implType eq "Int32Array";
985        push(@headerContent, "TypedArrayUint8") if $implType eq "Uint8Array";
986        push(@headerContent, "TypedArrayUint8Clamped") if $implType eq "Uint8ClampedArray";
987        push(@headerContent, "TypedArrayUint16") if $implType eq "Uint16Array";
988        push(@headerContent, "TypedArrayUint32") if $implType eq "Uint32Array";
989        push(@headerContent, "TypedArrayFloat32") if $implType eq "Float32Array";
990        push(@headerContent, "TypedArrayFloat64") if $implType eq "Float64Array";
991        push(@headerContent, ";\n");
992        push(@headerContent, "    intptr_t m_storageLength;\n");
993        push(@headerContent, "    void* m_storage;\n");
994    }
995
996    push(@headerContent, "protected:\n");
997    # Constructor
998    if ($interfaceName eq "DOMWindow") {
999        push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, PassRefPtr<$implType>, JSDOMWindowShell*);\n");
1000    } elsif ($interface->extendedAttributes->{"IsWorkerContext"}) {
1001        push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, PassRefPtr<$implType>);\n");
1002    } else {
1003        push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject*, PassRefPtr<$implType>);\n");
1004        push(@headerContent, "    void finishCreation(JSC::VM&);\n");
1005    }
1006
1007    # structure flags
1008    push(@headerContent, "    static const unsigned StructureFlags = ");
1009    foreach my $structureFlag (keys %structureFlags) {
1010        push(@headerContent, $structureFlag . " | ");
1011    }
1012    push(@headerContent, "Base::StructureFlags;\n");
1013
1014    # Index getter
1015    if ($indexedGetterFunction) {
1016        if ($hasNumericIndexedGetter) {
1017            push(@headerContent, "    JSC::JSValue getByIndex(JSC::ExecState*, unsigned index);\n");
1018        } else {
1019            push(@headerContent, "    static JSC::JSValue indexGetter(JSC::ExecState*, JSC::JSValue, unsigned);\n");
1020        }
1021    }
1022
1023    # Index setter
1024    if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
1025        push(@headerContent, "    void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
1026    }
1027    # Name getter
1028    if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
1029        push(@headerContent, "private:\n");
1030        push(@headerContent, "    static bool canGetItemsForName(JSC::ExecState*, $interfaceName*, JSC::PropertyName);\n");
1031        push(@headerContent, "    static JSC::JSValue nameGetter(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);\n");
1032    }
1033
1034    push(@headerContent, "};\n\n");
1035
1036    if ($interface->extendedAttributes->{"JSInlineGetOwnPropertySlot"} && !$interface->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
1037        push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertySlot(JSC::JSCell* cell, JSC::ExecState* exec, JSC::PropertyName propertyName, JSC::PropertySlot& slot)\n");
1038        push(@headerContent, "{\n");
1039        push(@headerContent, "    ${className}* thisObject = JSC::jsCast<${className}*>(cell);\n");
1040        push(@headerContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1041        push(@headerContent, GenerateGetOwnPropertySlotBody($interface, $interfaceName, $className, $numAttributes > 0, 1));
1042        push(@headerContent, "}\n\n");
1043        push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertyDescriptor(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, JSC::PropertyDescriptor& descriptor)\n");
1044        push(@headerContent, "{\n");
1045        push(@headerContent, "    ${className}* thisObject = JSC::jsCast<${className}*>(object);\n");
1046        push(@headerContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1047        push(@headerContent, GenerateGetOwnPropertyDescriptorBody($interface, $interfaceName, $className, $numAttributes > 0, 1));
1048        push(@headerContent, "}\n\n");
1049    }
1050
1051    if (!$hasParent ||
1052        GetGenerateIsReachable($interface) ||
1053        GetCustomIsReachable($interface) ||
1054        $interface->extendedAttributes->{"JSCustomFinalize"} ||
1055        $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
1056        if ($interfaceName ne "Node" && $codeGenerator->InheritsInterface($interface, "Node")) {
1057            $headerIncludes{"JSNode.h"} = 1;
1058            push(@headerContent, "class JS${interfaceName}Owner : public JSNodeOwner {\n");
1059        } else {
1060            push(@headerContent, "class JS${interfaceName}Owner : public JSC::WeakHandleOwner {\n");
1061        }
1062        push(@headerContent, "public:\n");
1063        push(@headerContent, "    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
1064        push(@headerContent, "    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
1065        push(@headerContent, "};\n");
1066        push(@headerContent, "\n");
1067        push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, $implType*)\n");
1068        push(@headerContent, "{\n");
1069        push(@headerContent, "    DEFINE_STATIC_LOCAL(JS${interfaceName}Owner, js${interfaceName}Owner, ());\n");
1070        push(@headerContent, "    return &js${interfaceName}Owner;\n");
1071        push(@headerContent, "}\n");
1072        push(@headerContent, "\n");
1073        push(@headerContent, "inline void* wrapperContext(DOMWrapperWorld* world, $implType*)\n");
1074        push(@headerContent, "{\n");
1075        push(@headerContent, "    return world;\n");
1076        push(@headerContent, "}\n");
1077        push(@headerContent, "\n");
1078    }
1079    if (ShouldGenerateToJSDeclaration($hasParent, $interface)) {
1080        push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
1081    }
1082    if (!$hasParent || $interface->extendedAttributes->{"JSGenerateToNativeObject"}) {
1083        if ($interfaceName eq "NodeFilter") {
1084            push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::VM&, JSC::JSValue);\n");
1085        } elsif ($interfaceName eq "DOMStringList") {
1086            push(@headerContent, "PassRefPtr<DOMStringList> toDOMStringList(JSC::ExecState*, JSC::JSValue);\n");
1087        } else {
1088            push(@headerContent, "$implType* to${interfaceName}(JSC::JSValue);\n");
1089        }
1090    }
1091    if ($usesToJSNewlyCreated{$interfaceName}) {
1092        push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, $interfaceName*);\n");
1093    }
1094
1095    push(@headerContent, "\n");
1096
1097    # Add prototype declaration.
1098    %structureFlags = ();
1099    push(@headerContent, "class ${className}Prototype : public JSC::JSNonFinalObject {\n");
1100    push(@headerContent, "public:\n");
1101    push(@headerContent, "    typedef JSC::JSNonFinalObject Base;\n");
1102    if ($interfaceName ne "DOMWindow" && !$interface->extendedAttributes->{"IsWorkerContext"}) {
1103        push(@headerContent, "    static JSC::JSObject* self(JSC::ExecState*, JSC::JSGlobalObject*);\n");
1104    }
1105
1106    push(@headerContent, "    static ${className}Prototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)\n");
1107    push(@headerContent, "    {\n");
1108    push(@headerContent, "        ${className}Prototype* ptr = new (NotNull, JSC::allocateCell<${className}Prototype>(vm.heap)) ${className}Prototype(vm, globalObject, structure);\n");
1109    push(@headerContent, "        ptr->finishCreation(vm);\n");
1110    push(@headerContent, "        return ptr;\n");
1111    push(@headerContent, "    }\n\n");
1112
1113    push(@headerContent, "    static const JSC::ClassInfo s_info;\n");
1114    if ($numFunctions > 0 || $numConstants > 0) {
1115        push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
1116        push(@headerContent, "    static bool getOwnPropertyDescriptor(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&);\n");
1117        $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
1118    }
1119    if ($interface->extendedAttributes->{"JSCustomMarkFunction"} or $needsMarkChildren) {
1120        $structureFlags{"JSC::OverridesVisitChildren"} = 1;
1121    }
1122    push(@headerContent,
1123        "    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n" .
1124        "    {\n" .
1125        "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);\n" .
1126        "    }\n");
1127    if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {
1128        push(@headerContent, "    static void put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1129        push(@headerContent, "    bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1130    }
1131
1132    # Custom defineOwnProperty function
1133    push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnPropertyOnPrototype"};
1134
1135    push(@headerContent, "\nprivate:\n");
1136    push(@headerContent, "    ${className}Prototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) : JSC::JSNonFinalObject(vm, structure) { }\n");
1137
1138    # structure flags
1139    push(@headerContent, "protected:\n");
1140    push(@headerContent, "    static const unsigned StructureFlags = ");
1141    foreach my $structureFlag (keys %structureFlags) {
1142        push(@headerContent, $structureFlag . " | ");
1143    }
1144    push(@headerContent, "Base::StructureFlags;\n");
1145
1146    push(@headerContent, "};\n\n");
1147
1148    if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
1149        $headerIncludes{"JSDOMBinding.h"} = 1;
1150        GenerateConstructorDeclaration(\@headerContent, $className, $interface, $interfaceName);
1151    }
1152
1153    if ($numFunctions > 0) {
1154        push(@headerContent,"// Functions\n\n");
1155        foreach my $function (@{$interface->functions}) {
1156            next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1157            my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1158            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1159            my $functionName = GetFunctionName($className, $function);
1160            push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
1161            push(@headerContent, "#endif\n") if $conditionalString;
1162        }
1163    }
1164
1165    if ($numAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"}) {
1166        push(@headerContent,"// Attributes\n\n");
1167        foreach my $attribute (@{$interface->attributes}) {
1168            my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1169            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1170            my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
1171            push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);\n");
1172            if (!IsReadonly($attribute)) {
1173                my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
1174                push(@headerContent, "void ${setter}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);\n");
1175            }
1176            push(@headerContent, "#endif\n") if $conditionalString;
1177        }
1178
1179        if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
1180            my $getter = "js" . $interfaceName . "Constructor";
1181            push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);\n");
1182        }
1183
1184        if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
1185            my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
1186            push(@headerContent, "void ${constructorFunctionName}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);\n");
1187        }
1188    }
1189
1190    if ($numConstants > 0) {
1191        push(@headerContent,"// Constants\n\n");
1192        foreach my $constant (@{$interface->constants}) {
1193            my $conditionalString = $codeGenerator->GenerateConditionalString($constant);
1194            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
1195            my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
1196            push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);\n");
1197            push(@headerContent, "#endif\n") if $conditionalString;
1198        }
1199    }
1200
1201    my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
1202    push(@headerContent, "\n} // namespace WebCore\n\n");
1203    push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
1204    push(@headerContent, "#endif\n");
1205
1206    # - Generate dependencies.
1207    if ($writeDependencies && @ancestorInterfaceNames) {
1208        push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestorInterfaceNames), "\n");
1209        push(@depsContent, map { "$_.idl :\n" } @ancestorInterfaceNames);
1210    }
1211}
1212
1213sub GenerateAttributesHashTable($$)
1214{
1215    my ($object, $interface) = @_;
1216
1217    # FIXME: These should be functions on $interface.
1218    my $interfaceName = $interface->name;
1219    my $className = "JS$interfaceName";
1220
1221    # - Add all attributes in a hashtable definition
1222    my $numAttributes = @{$interface->attributes};
1223    $numAttributes++ if !$interface->extendedAttributes->{"NoInterfaceObject"};
1224
1225    return 0  if !$numAttributes;
1226
1227    my $hashSize = $numAttributes;
1228    my $hashName = $className . "Table";
1229
1230    my @hashKeys = ();
1231    my @hashSpecials = ();
1232    my @hashValue1 = ();
1233    my @hashValue2 = ();
1234    my %conditionals = ();
1235
1236    my @entries = ();
1237
1238    foreach my $attribute (@{$interface->attributes}) {
1239        next if ($attribute->isStatic);
1240        my $name = $attribute->signature->name;
1241        push(@hashKeys, $name);
1242
1243        my @specials = ();
1244        # As per Web IDL specification, constructor properties on the ECMAScript global object should be
1245        # configurable and should not be enumerable.
1246        my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
1247        push(@specials, "DontDelete") unless ($attribute->signature->extendedAttributes->{"Deletable"} || $is_global_constructor);
1248        push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor);
1249        push(@specials, "ReadOnly") if IsReadonly($attribute);
1250        my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1251        push(@hashSpecials, $special);
1252
1253        my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
1254        push(@hashValue1, $getter);
1255
1256        if (IsReadonly($attribute)) {
1257            push(@hashValue2, "0");
1258        } else {
1259            my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
1260            push(@hashValue2, $setter);
1261        }
1262
1263        my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
1264        if ($conditional) {
1265            $conditionals{$name} = $conditional;
1266        }
1267    }
1268
1269    if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
1270        push(@hashKeys, "constructor");
1271        my $getter = "js" . $interfaceName . "Constructor";
1272        push(@hashValue1, $getter);
1273        if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
1274            my $setter = "setJS" . $interfaceName . "Constructor";
1275            push(@hashValue2, $setter);
1276            push(@hashSpecials, "DontEnum | DontDelete");
1277        } else {
1278            push(@hashValue2, "0");
1279            push(@hashSpecials, "DontEnum | ReadOnly");
1280        }
1281    }
1282
1283    $object->GenerateHashTable($hashName, $hashSize,
1284                               \@hashKeys, \@hashSpecials,
1285                               \@hashValue1, \@hashValue2,
1286                               \%conditionals);
1287    return $numAttributes;
1288}
1289
1290sub GenerateParametersCheckExpression
1291{
1292    my $numParameters = shift;
1293    my $function = shift;
1294
1295    my @andExpression = ();
1296    push(@andExpression, "argsCount == $numParameters");
1297    my $parameterIndex = 0;
1298    my %usedArguments = ();
1299    foreach my $parameter (@{$function->parameters}) {
1300        last if $parameterIndex >= $numParameters;
1301        my $value = "arg$parameterIndex";
1302        my $type = $parameter->type;
1303
1304        # Only DOMString or wrapper types are checked.
1305        # For DOMString with StrictTypeChecking only Null, Undefined and Object
1306        # are accepted for compatibility. Otherwise, no restrictions are made to
1307        # match the non-overloaded behavior.
1308        # FIXME: Implement WebIDL overload resolution algorithm.
1309        if ($codeGenerator->IsStringType($type)) {
1310            if ($parameter->extendedAttributes->{"StrictTypeChecking"}) {
1311                push(@andExpression, "(${value}.isUndefinedOrNull() || ${value}.isString() || ${value}.isObject())");
1312                $usedArguments{$parameterIndex} = 1;
1313            }
1314        } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) {
1315            # For Callbacks only checks if the value is null or object.
1316            push(@andExpression, "(${value}.isNull() || ${value}.isFunction())");
1317            $usedArguments{$parameterIndex} = 1;
1318        } elsif ($codeGenerator->GetArrayType($type) || $codeGenerator->GetSequenceType($type)) {
1319            # FIXME: Add proper support for T[], T[]?, sequence<T>
1320            if ($parameter->isNullable) {
1321                push(@andExpression, "(${value}.isNull() || (${value}.isObject() && isJSArray(${value})))");
1322            } else {
1323                push(@andExpression, "(${value}.isObject() && isJSArray(${value}))");
1324            }
1325            $usedArguments{$parameterIndex} = 1;
1326        } elsif (!IsNativeType($type)) {
1327            if ($parameter->isNullable) {
1328                push(@andExpression, "(${value}.isNull() || (${value}.isObject() && asObject(${value})->inherits(&JS${type}::s_info)))");
1329            } else {
1330                push(@andExpression, "(${value}.isObject() && asObject(${value})->inherits(&JS${type}::s_info))");
1331            }
1332            $usedArguments{$parameterIndex} = 1;
1333        }
1334        $parameterIndex++;
1335    }
1336    my $res = join(" && ", @andExpression);
1337    $res = "($res)" if @andExpression > 1;
1338    return ($res, keys %usedArguments);
1339}
1340
1341# As per Web IDL specification, the length of a function Object is
1342# its number of mandatory parameters.
1343sub GetFunctionLength
1344{
1345  my $function = shift;
1346
1347  my $numMandatoryParams = 0;
1348  foreach my $parameter (@{$function->parameters}) {
1349    # Abort as soon as we find the first optional parameter as no mandatory
1350    # parameter can follow an optional one.
1351    last if $parameter->isOptional;
1352    $numMandatoryParams++;
1353  }
1354  return $numMandatoryParams;
1355}
1356
1357sub GenerateFunctionParametersCheck
1358{
1359    my $function = shift;
1360
1361    my @orExpression = ();
1362    my $numParameters = 0;
1363    my @neededArguments = ();
1364    my $hasVariadic = 0;
1365    my $numMandatoryParams = @{$function->parameters};
1366
1367    foreach my $parameter (@{$function->parameters}) {
1368        if ($parameter->isOptional) {
1369            my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1370            push(@orExpression, $expression);
1371            push(@neededArguments, @usedArguments);
1372            $numMandatoryParams--;
1373        }
1374        if ($parameter->isVariadic) {
1375            $hasVariadic = 1;
1376            last;
1377        }
1378        $numParameters++;
1379    }
1380    if (!$hasVariadic) {
1381        my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1382        push(@orExpression, $expression);
1383        push(@neededArguments, @usedArguments);
1384    }
1385    return ($numMandatoryParams, join(" || ", @orExpression), @neededArguments);
1386}
1387
1388sub GenerateOverloadedFunction
1389{
1390    my $function = shift;
1391    my $interface = shift;
1392    my $interfaceName = shift;
1393
1394    # Generate code for choosing the correct overload to call. Overloads are
1395    # chosen based on the total number of arguments passed and the type of
1396    # values passed in non-primitive argument slots. When more than a single
1397    # overload is applicable, precedence is given according to the order of
1398    # declaration in the IDL.
1399
1400    my $kind = $function->isStatic ? "Constructor" : "Prototype";
1401    my $functionName = "js${interfaceName}${kind}Function" . $codeGenerator->WK_ucfirst($function->signature->name);
1402
1403    push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
1404    push(@implContent, <<END);
1405{
1406    size_t argsCount = exec->argumentCount();
1407END
1408
1409    my %fetchedArguments = ();
1410    my $leastNumMandatoryParams = 255;
1411
1412    foreach my $overload (@{$function->{overloads}}) {
1413        my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload);
1414        $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams);
1415
1416        foreach my $parameterIndex (@neededArguments) {
1417            next if exists $fetchedArguments{$parameterIndex};
1418            push(@implContent, "    JSValue arg$parameterIndex(exec->argument($parameterIndex));\n");
1419            $fetchedArguments{$parameterIndex} = 1;
1420        }
1421
1422        push(@implContent, "    if ($parametersCheck)\n");
1423        push(@implContent, "        return ${functionName}$overload->{overloadIndex}(exec);\n");
1424    }
1425    if ($leastNumMandatoryParams >= 1) {
1426        push(@implContent, "    if (argsCount < $leastNumMandatoryParams)\n");
1427        push(@implContent, "        return throwVMError(exec, createNotEnoughArgumentsError(exec));\n");
1428    }
1429    push(@implContent, <<END);
1430    return throwVMTypeError(exec);
1431}
1432
1433END
1434}
1435
1436sub GetNativeTypeForConversions
1437{
1438    my $interface = shift;
1439    my $interfaceName = $interface->name;
1440    $interfaceName = $codeGenerator->GetSVGTypeNeedingTearOff($interfaceName) if $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName);
1441    return $interfaceName;
1442}
1443
1444# See http://refspecs.linux-foundation.org/cxxabi-1.83.html.
1445sub GetGnuVTableRefForInterface
1446{
1447    my $interface = shift;
1448    my $vtableName = GetGnuVTableNameForInterface($interface);
1449    if (!$vtableName) {
1450        return "0";
1451    }
1452    my $typename = GetNativeTypeForConversions($interface);
1453    my $offset = GetGnuVTableOffsetForType($typename);
1454    return "&" . $vtableName . "[" . $offset . "]";
1455}
1456
1457sub GetGnuVTableNameForInterface
1458{
1459    my $interface = shift;
1460    my $typename = GetNativeTypeForConversions($interface);
1461    my $templatePosition = index($typename, "<");
1462    return "" if $templatePosition != -1;
1463    return "" if GetImplementationLacksVTableForInterface($interface);
1464    return "" if GetSkipVTableValidationForInterface($interface);
1465    return "_ZTV" . GetGnuMangledNameForInterface($interface);
1466}
1467
1468sub GetGnuMangledNameForInterface
1469{
1470    my $interface = shift;
1471    my $typename = GetNativeTypeForConversions($interface);
1472    my $templatePosition = index($typename, "<");
1473    if ($templatePosition != -1) {
1474        return "";
1475    }
1476    my $mangledType = length($typename) . $typename;
1477    my $namespace = GetNamespaceForInterface($interface);
1478    my $mangledNamespace =  "N" . length($namespace) . $namespace;
1479    return $mangledNamespace . $mangledType . "E";
1480}
1481
1482sub GetGnuVTableOffsetForType
1483{
1484    my $typename = shift;
1485    if ($typename eq "SVGAElement"
1486        || $typename eq "SVGCircleElement"
1487        || $typename eq "SVGClipPathElement"
1488        || $typename eq "SVGDefsElement"
1489        || $typename eq "SVGEllipseElement"
1490        || $typename eq "SVGForeignObjectElement"
1491        || $typename eq "SVGGElement"
1492        || $typename eq "SVGImageElement"
1493        || $typename eq "SVGLineElement"
1494        || $typename eq "SVGPathElement"
1495        || $typename eq "SVGPolyElement"
1496        || $typename eq "SVGPolygonElement"
1497        || $typename eq "SVGPolylineElement"
1498        || $typename eq "SVGRectElement"
1499        || $typename eq "SVGSVGElement"
1500        || $typename eq "SVGStyledLocatableElement"
1501        || $typename eq "SVGStyledTransformableElement"
1502        || $typename eq "SVGSwitchElement"
1503        || $typename eq "SVGTextElement"
1504        || $typename eq "SVGTransformable"
1505        || $typename eq "SVGUseElement") {
1506        return "3";
1507    }
1508    return "2";
1509}
1510
1511# See http://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B_Name_Mangling.
1512sub GetWinVTableRefForInterface
1513{
1514    my $interface = shift;
1515    my $vtableName = GetWinVTableNameForInterface($interface);
1516    return 0 if !$vtableName;
1517    return "__identifier(\"" . $vtableName . "\")";
1518}
1519
1520sub GetWinVTableNameForInterface
1521{
1522    my $interface = shift;
1523    my $typename = GetNativeTypeForConversions($interface);
1524    my $templatePosition = index($typename, "<");
1525    return "" if $templatePosition != -1;
1526    return "" if GetImplementationLacksVTableForInterface($interface);
1527    return "" if GetSkipVTableValidationForInterface($interface);
1528    return "??_7" . GetWinMangledNameForInterface($interface) . "6B@";
1529}
1530
1531sub GetWinMangledNameForInterface
1532{
1533    my $interface = shift;
1534    my $typename = GetNativeTypeForConversions($interface);
1535    my $namespace = GetNamespaceForInterface($interface);
1536    return $typename . "@" . $namespace . "@@";
1537}
1538
1539sub GetNamespaceForInterface
1540{
1541    my $interface = shift;
1542    return $interface->extendedAttributes->{"ImplementationNamespace"} || "WebCore";
1543}
1544
1545sub GetImplementationLacksVTableForInterface
1546{
1547    my $interface = shift;
1548    return $interface->extendedAttributes->{"ImplementationLacksVTable"};
1549}
1550
1551sub GetSkipVTableValidationForInterface
1552{
1553    my $interface = shift;
1554    return $interface->extendedAttributes->{"SkipVTableValidation"};
1555}
1556
1557# URL becomes url, but SetURL becomes setURL.
1558sub ToMethodName
1559{
1560    my $param = shift;
1561    my $ret = lcfirst($param);
1562    $ret =~ s/hTML/html/ if $ret =~ /^hTML/;
1563    $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
1564    $ret =~ s/jS/js/ if $ret =~ /^jS/;
1565    $ret =~ s/xML/xml/ if $ret =~ /^xML/;
1566    $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
1567    $ret =~ s/cSS/css/ if $ret =~ /^cSS/;
1568
1569    # For HTML5 FileSystem API Flags attributes.
1570    # (create is widely used to instantiate an object and must be avoided.)
1571    $ret =~ s/^create/isCreate/ if $ret =~ /^create$/;
1572    $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/;
1573
1574    return $ret;
1575}
1576
1577# Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
1578sub GetRuntimeEnableFunctionName
1579{
1580    my $signature = shift;
1581
1582    # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method.
1583    return "RuntimeEnabledFeatures::" . ToMethodName($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "VALUE_IS_MISSING");
1584
1585    # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled().
1586    return "RuntimeEnabledFeatures::" . ToMethodName($signature->name) . "Enabled";
1587}
1588
1589sub GenerateImplementation
1590{
1591    my ($object, $interface) = @_;
1592
1593    my $interfaceName = $interface->name;
1594    my $className = "JS$interfaceName";
1595
1596    my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
1597    my $hasRealParent = @{$interface->parents} > 0;
1598    my $hasParent = $hasLegacyParent || $hasRealParent;
1599    my $parentClassName = GetParentClassName($interface);
1600    my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
1601    my $eventTarget = $interface->extendedAttributes->{"EventTarget"} || ($codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->name ne "EventTarget");
1602    my $needsMarkChildren = $interface->extendedAttributes->{"JSCustomMarkFunction"} || $interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget";
1603
1604    my $namedGetterFunction = GetNamedGetterFunction($interface);
1605    my $indexedGetterFunction = GetIndexedGetterFunction($interface);
1606    my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
1607
1608    # - Add default header template
1609    push(@implContentHeader, GenerateImplementationContentHeader($interface));
1610
1611    $implIncludes{"<wtf/GetPtr.h>"} = 1;
1612    $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $indexedGetterFunction;
1613
1614    AddIncludesForTypeInImpl($interfaceName);
1615
1616    @implContent = ();
1617
1618    push(@implContent, "\nusing namespace JSC;\n\n");
1619    push(@implContent, "namespace WebCore {\n\n");
1620
1621    my $numAttributes = GenerateAttributesHashTable($object, $interface);
1622
1623    my $numConstants = @{$interface->constants};
1624    my $numFunctions = @{$interface->functions};
1625
1626    # - Add all constants
1627    if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
1628        my $hashSize = $numConstants;
1629        my $hashName = $className . "ConstructorTable";
1630
1631        my @hashKeys = ();
1632        my @hashValue1 = ();
1633        my @hashValue2 = ();
1634        my @hashSpecials = ();
1635        my %conditionals = ();
1636
1637        # FIXME: we should not need a function for every constant.
1638        foreach my $constant (@{$interface->constants}) {
1639            my $name = $constant->name;
1640            push(@hashKeys, $name);
1641            my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name);
1642            push(@hashValue1, $getter);
1643            push(@hashValue2, "0");
1644            push(@hashSpecials, "DontDelete | ReadOnly");
1645
1646            my $implementedBy = $constant->extendedAttributes->{"ImplementedBy"};
1647            if ($implementedBy) {
1648                $implIncludes{"${implementedBy}.h"} = 1;
1649            }
1650            my $conditional = $constant->extendedAttributes->{"Conditional"};
1651            if ($conditional) {
1652                $conditionals{$name} = $conditional;
1653            }
1654        }
1655
1656        foreach my $attribute (@{$interface->attributes}) {
1657            next unless ($attribute->isStatic);
1658            my $name = $attribute->signature->name;
1659            push(@hashKeys, $name);
1660
1661            my @specials = ();
1662            push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
1663            push(@specials, "ReadOnly") if IsReadonly($attribute);
1664            my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1665            push(@hashSpecials, $special);
1666
1667            my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
1668            push(@hashValue1, $getter);
1669
1670            if (IsReadonly($attribute)) {
1671                push(@hashValue2, "0");
1672            } else {
1673                my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
1674                push(@hashValue2, $setter);
1675            }
1676
1677            my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
1678            if ($conditional) {
1679                $conditionals{$name} = $conditional;
1680            }
1681        }
1682
1683        foreach my $function (@{$interface->functions}) {
1684            next unless ($function->isStatic);
1685            next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1686            my $name = $function->signature->name;
1687            push(@hashKeys, $name);
1688
1689            my $functionName = GetFunctionName($className, $function);
1690            push(@hashValue1, $functionName);
1691
1692            my $functionLength = GetFunctionLength($function);
1693            push(@hashValue2, $functionLength);
1694
1695            my @specials = ();
1696            push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"};
1697            push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"};
1698            push(@specials, "JSC::Function");
1699            my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1700            push(@hashSpecials, $special);
1701
1702            my $conditional = $function->signature->extendedAttributes->{"Conditional"};
1703            if ($conditional) {
1704                $conditionals{$name} = $conditional;
1705            }
1706        }
1707
1708        $object->GenerateHashTable($hashName, $hashSize,
1709                                   \@hashKeys, \@hashSpecials,
1710                                   \@hashValue1, \@hashValue2,
1711                                   \%conditionals);
1712
1713        push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($interface));
1714
1715        my $protoClassName = "${className}Prototype";
1716        GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface);
1717        if ($interface->extendedAttributes->{"NamedConstructor"}) {
1718            GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interfaceName, $interface->extendedAttributes->{"NamedConstructor"}, $interface, "GeneratingNamedConstructor");
1719        }
1720    }
1721
1722    # - Add functions and constants to a hashtable definition
1723    my $hashSize = $numFunctions + $numConstants;
1724    my $hashName = $className . "PrototypeTable";
1725
1726    my @hashKeys = ();
1727    my @hashValue1 = ();
1728    my @hashValue2 = ();
1729    my @hashSpecials = ();
1730    my %conditionals = ();
1731
1732    # FIXME: we should not need a function for every constant.
1733    foreach my $constant (@{$interface->constants}) {
1734        my $name = $constant->name;
1735        push(@hashKeys, $name);
1736        my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name);
1737        push(@hashValue1, $getter);
1738        push(@hashValue2, "0");
1739        push(@hashSpecials, "DontDelete | ReadOnly");
1740
1741        my $conditional = $constant->extendedAttributes->{"Conditional"};
1742        if ($conditional) {
1743            $conditionals{$name} = $conditional;
1744        }
1745    }
1746
1747    foreach my $function (@{$interface->functions}) {
1748        next if ($function->isStatic);
1749        next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1750        my $name = $function->signature->name;
1751        push(@hashKeys, $name);
1752
1753        my $functionName = GetFunctionName($className, $function);
1754        push(@hashValue1, $functionName);
1755
1756        my $functionLength = GetFunctionLength($function);
1757        push(@hashValue2, $functionLength);
1758
1759        my @specials = ();
1760        push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"};
1761        push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"};
1762        push(@specials, "JSC::Function");
1763        my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1764        push(@hashSpecials, $special);
1765
1766        my $conditional = $function->signature->extendedAttributes->{"Conditional"};
1767        if ($conditional) {
1768            $conditionals{$name} = $conditional;
1769        }
1770    }
1771
1772    $object->GenerateHashTable($hashName, $hashSize,
1773                               \@hashKeys, \@hashSpecials,
1774                               \@hashValue1, \@hashValue2,
1775                               \%conditionals);
1776
1777    if ($interface->extendedAttributes->{"JSNoStaticTables"}) {
1778        push(@implContent, "static const HashTable* get${className}PrototypeTable(ExecState* exec)\n");
1779        push(@implContent, "{\n");
1780        push(@implContent, "    return getHashTableForGlobalData(exec->vm(), &${className}PrototypeTable);\n");
1781        push(@implContent, "}\n\n");
1782        push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, 0, get${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
1783    } else {
1784        push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, &${className}PrototypeTable, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
1785    }
1786    if ($interfaceName ne "DOMWindow" && !$interface->extendedAttributes->{"IsWorkerContext"}) {
1787        push(@implContent, "JSObject* ${className}Prototype::self(ExecState* exec, JSGlobalObject* globalObject)\n");
1788        push(@implContent, "{\n");
1789        push(@implContent, "    return getDOMPrototype<${className}>(exec, globalObject);\n");
1790        push(@implContent, "}\n\n");
1791    }
1792
1793    if ($numConstants > 0 || $numFunctions > 0) {
1794        push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
1795        push(@implContent, "{\n");
1796        push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(cell);\n");
1797
1798        if ($numConstants eq 0 && $numFunctions eq 0) {
1799            push(@implContent, "    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");
1800        } elsif ($numConstants eq 0) {
1801            push(@implContent, "    return getStaticFunctionSlot<JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1802        } elsif ($numFunctions eq 0) {
1803            push(@implContent, "    return getStaticValueSlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1804        } else {
1805            push(@implContent, "    return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1806        }
1807        push(@implContent, "}\n\n");
1808
1809        push(@implContent, "bool ${className}Prototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)\n");
1810        push(@implContent, "{\n");
1811        push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(object);\n");
1812
1813        if ($numConstants eq 0 && $numFunctions eq 0) {
1814            push(@implContent, "    return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);\n");
1815        } elsif ($numConstants eq 0) {
1816            push(@implContent, "    return getStaticFunctionDescriptor<JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n");
1817        } elsif ($numFunctions eq 0) {
1818            push(@implContent, "    return getStaticValueDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n");
1819        } else {
1820            push(@implContent, "    return getStaticPropertyDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n");
1821        }
1822        push(@implContent, "}\n\n");
1823    }
1824
1825    if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {
1826        push(@implContent, "void ${className}Prototype::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
1827        push(@implContent, "{\n");
1828        push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(cell);\n");
1829        push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
1830        push(@implContent, "        return;\n");
1831        push(@implContent, "    Base::put(thisObject, exec, propertyName, value, slot);\n");
1832        push(@implContent, "}\n\n");
1833    }
1834
1835    # - Initialize static ClassInfo object
1836    if ($numAttributes > 0 && $interface->extendedAttributes->{"JSNoStaticTables"}) {
1837        push(@implContent, "static const HashTable* get${className}Table(ExecState* exec)\n");
1838        push(@implContent, "{\n");
1839        push(@implContent, "    return getHashTableForGlobalData(exec->vm(), &${className}Table);\n");
1840        push(@implContent, "}\n\n");
1841    }
1842
1843    push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleInterfaceName}\", &Base::s_info, ");
1844
1845    if ($numAttributes > 0 && !$interface->extendedAttributes->{"JSNoStaticTables"}) {
1846        push(@implContent, "&${className}Table");
1847    } else {
1848        push(@implContent, "0");
1849    }
1850    if ($numAttributes > 0 && $interface->extendedAttributes->{"JSNoStaticTables"}) {
1851        push(@implContent, ", get${className}Table ");
1852    } else {
1853        push(@implContent, ", 0 ");
1854    }
1855    push(@implContent, ", CREATE_METHOD_TABLE($className) };\n\n");
1856
1857    my $implType = $interfaceName;
1858    my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
1859    $implType = $svgNativeType if $svgNativeType;
1860
1861    my $svgPropertyOrListPropertyType;
1862    $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
1863    $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
1864
1865    # Constructor
1866    if ($interfaceName eq "DOMWindow") {
1867        AddIncludesForTypeInImpl("JSDOMWindowShell");
1868        push(@implContent, "${className}::$className(VM& vm, Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n");
1869        push(@implContent, "    : $parentClassName(vm, structure, impl, shell)\n");
1870        push(@implContent, "{\n");
1871        push(@implContent, "}\n\n");
1872    } elsif ($interface->extendedAttributes->{"IsWorkerContext"}) {
1873        AddIncludesForTypeInImpl($interfaceName);
1874        push(@implContent, "${className}::$className(VM& vm, Structure* structure, PassRefPtr<$implType> impl)\n");
1875        push(@implContent, "    : $parentClassName(vm, structure, impl)\n");
1876        push(@implContent, "{\n");
1877        push(@implContent, "}\n\n");
1878    } else {
1879        push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
1880        if ($hasParent) {
1881            push(@implContent, "    : $parentClassName(structure, globalObject, impl)\n");
1882        } else {
1883            push(@implContent, "    : $parentClassName(structure, globalObject)\n");
1884            push(@implContent, "    , m_impl(impl.leakRef())\n");
1885        }
1886        push(@implContent, "{\n");
1887        push(@implContent, "}\n\n");
1888
1889        push(@implContent, "void ${className}::finishCreation(VM& vm)\n");
1890        push(@implContent, "{\n");
1891        push(@implContent, "    Base::finishCreation(vm);\n");
1892        if ($codeGenerator->IsTypedArrayType($implType) and ($implType ne "ArrayBufferView") and ($implType ne "ArrayBuffer")) {
1893            push(@implContent, "    TypedArrayDescriptor descriptor(&${className}::s_info, OBJECT_OFFSETOF(${className}, m_storage), OBJECT_OFFSETOF(${className}, m_storageLength));\n");
1894            push(@implContent, "    vm.registerTypedArrayDescriptor(impl(), descriptor);\n");
1895            push(@implContent, "    m_storage = impl()->data();\n");
1896            push(@implContent, "    m_storageLength = impl()->length();\n");
1897        }
1898        push(@implContent, "    ASSERT(inherits(&s_info));\n");
1899        push(@implContent, "}\n\n");
1900    }
1901
1902    if (!$interface->extendedAttributes->{"ExtendsDOMGlobalObject"}) {
1903        push(@implContent, "JSObject* ${className}::createPrototype(ExecState* exec, JSGlobalObject* globalObject)\n");
1904        push(@implContent, "{\n");
1905        if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") {
1906            push(@implContent, "    return ${className}Prototype::create(exec->vm(), globalObject, ${className}Prototype::createStructure(exec->vm(), globalObject, ${parentClassName}Prototype::self(exec, globalObject)));\n");
1907        } else {
1908            my $prototype = $interface->isException ? "errorPrototype" : "objectPrototype";
1909            push(@implContent, "    return ${className}Prototype::create(exec->vm(), globalObject, ${className}Prototype::createStructure(globalObject->vm(), globalObject, globalObject->${prototype}()));\n");
1910        }
1911        push(@implContent, "}\n\n");
1912    }
1913
1914    if (!$hasParent) {
1915        # FIXME: This destroy function should not be necessary, as
1916        # a finalizer should be called for each DOM object wrapper.
1917        # However, that seems not to be the case, so this has been
1918        # added back to avoid leaking while we figure out why the
1919        # finalizers are not always getting called. The work tracking
1920        # the finalizer issue is being tracked in http://webkit.org/b/75451
1921        push(@implContent, "void ${className}::destroy(JSC::JSCell* cell)\n");
1922        push(@implContent, "{\n");
1923        push(@implContent, "    ${className}* thisObject = static_cast<${className}*>(cell);\n");
1924        push(@implContent, "    thisObject->${className}::~${className}();\n");
1925        push(@implContent, "}\n\n");
1926
1927        # We also need a destructor for the allocateCell to work properly with the destructor-free part of the heap.
1928        # Otherwise, these destroy functions/destructors won't get called.
1929        push(@implContent, "${className}::~${className}()\n");
1930        push(@implContent, "{\n");
1931        push(@implContent, "    releaseImplIfNotNull();\n");
1932        push(@implContent, "}\n\n");
1933    }
1934
1935    my $hasGetter = $numAttributes > 0
1936                 || !$interface->extendedAttributes->{"NoInterfaceObject"}
1937                 || $indexedGetterFunction
1938                 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
1939                 || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
1940                 || $namedGetterFunction
1941                 || $interface->extendedAttributes->{"CustomNamedGetter"};
1942
1943    # Attributes
1944    if ($hasGetter) {
1945        if (!$interface->extendedAttributes->{"JSInlineGetOwnPropertySlot"} && !$interface->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
1946            push(@implContent, "bool ${className}::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
1947            push(@implContent, "{\n");
1948            push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
1949            push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1950            push(@implContent, GenerateGetOwnPropertySlotBody($interface, $interfaceName, $className, $numAttributes > 0, 0));
1951            push(@implContent, "}\n\n");
1952            push(@implContent, "bool ${className}::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)\n");
1953            push(@implContent, "{\n");
1954            push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(object);\n");
1955            push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1956            push(@implContent, GenerateGetOwnPropertyDescriptorBody($interface, $interfaceName, $className, $numAttributes > 0, 0));
1957            push(@implContent, "}\n\n");
1958        }
1959
1960        if ($indexedGetterFunction || $namedGetterFunction
1961                || $interface->extendedAttributes->{"CustomNamedGetter"}
1962                || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
1963            push(@implContent, "bool ${className}::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned index, PropertySlot& slot)\n");
1964            push(@implContent, "{\n");
1965            push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
1966            push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1967
1968            # Sink the int-to-string conversion that happens when we create a PropertyName
1969            # to the point where we actually need it.
1970            my $generatedPropertyName = 0;
1971            my $propertyNameGeneration = sub {
1972                if ($generatedPropertyName) {
1973                    return;
1974                }
1975                push(@implContent, "    PropertyName propertyName = Identifier::from(exec, index);\n");
1976                $generatedPropertyName = 1;
1977            };
1978
1979            if ($indexedGetterFunction) {
1980                if (IndexGetterReturnsStrings($interfaceName)) {
1981                    push(@implContent, "    if (index <= MAX_ARRAY_INDEX) {\n");
1982                } else {
1983                    push(@implContent, "    if (index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n");
1984                }
1985                if ($hasNumericIndexedGetter) {
1986                    push(@implContent, "        slot.setValue(thisObject->getByIndex(exec, index));\n");
1987                } else {
1988                    push(@implContent, "        slot.setCustomIndex(thisObject, index, thisObject->indexGetter);\n");
1989                }
1990                push(@implContent, "        return true;\n");
1991                push(@implContent, "    }\n");
1992            }
1993
1994            if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
1995                &$propertyNameGeneration();
1996                push(@implContent, "    if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n");
1997                push(@implContent, "        slot.setCustom(thisObject, thisObject->nameGetter);\n");
1998                push(@implContent, "        return true;\n");
1999                push(@implContent, "    }\n");
2000                $implIncludes{"wtf/text/AtomicString.h"} = 1;
2001            }
2002
2003            if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
2004                &$propertyNameGeneration();
2005                push(@implContent, "    if (thisObject->getOwnPropertySlotDelegate(exec, propertyName, slot))\n");
2006                push(@implContent, "        return true;\n");
2007            }
2008
2009            push(@implContent, "    return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot);\n");
2010            push(@implContent, "}\n\n");
2011        }
2012
2013        if ($numAttributes > 0) {
2014            foreach my $attribute (@{$interface->attributes}) {
2015                my $name = $attribute->signature->name;
2016                my $type = $attribute->signature->type;
2017                my $isNullable = $attribute->signature->isNullable;
2018                $codeGenerator->AssertNotSequenceType($type);
2019                my $getFunctionName = GetAttributeGetterName($interfaceName, $className, $attribute);
2020                my $implGetterFunctionName = $codeGenerator->WK_lcfirst($name);
2021
2022                my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2023                push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2024
2025                push(@implContent, "JSValue ${getFunctionName}(ExecState* exec, JSValue slotBase, PropertyName)\n");
2026                push(@implContent, "{\n");
2027
2028                if (!$attribute->isStatic || $attribute->signature->type =~ /Constructor$/) {
2029                    push(@implContent, "    ${className}* castedThis = jsCast<$className*>(asObject(slotBase));\n");
2030                } else {
2031                    push(@implContent, "    UNUSED_PARAM(slotBase);\n");
2032                }
2033
2034                # Global constructors can be disabled at runtime.
2035                if ($attribute->signature->type =~ /Constructor$/) {
2036                    if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
2037                        AddToImplIncludes("RuntimeEnabledFeatures.h");
2038                        my $enable_function = GetRuntimeEnableFunctionName($attribute->signature);
2039                        push(@implContent, "    if (!${enable_function}())\n");
2040                        push(@implContent, "        return jsUndefined();\n");
2041                    } elsif ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) {
2042                        AddToImplIncludes("Frame.h");
2043                        AddToImplIncludes("Settings.h");
2044                        my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{"EnabledBySetting"}) . "Enabled";
2045                        push(@implContent, "    Settings* settings = castedThis->impl()->frame() ? castedThis->impl()->frame()->settings() : 0;\n");
2046                        push(@implContent, "    if (!settings || !settings->$enable_function())\n");
2047                        push(@implContent, "        return jsUndefined();\n");
2048                    }
2049                }
2050
2051                if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2052                    $needsMarkChildren = 1;
2053                }
2054
2055                if ($interface->extendedAttributes->{"CheckSecurity"} &&
2056                    !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"} &&
2057                    !$attribute->signature->extendedAttributes->{"DoNotCheckSecurityOnGetter"}) {
2058                    $implIncludes{"BindingSecurity.h"} = 1;
2059                    push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2060                    push(@implContent, "        return jsUndefined();\n");
2061                }
2062
2063                if (HasCustomGetter($attribute->signature->extendedAttributes)) {
2064                    push(@implContent, "    return castedThis->$implGetterFunctionName(exec);\n");
2065                } elsif ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
2066                    $implIncludes{"JSDOMBinding.h"} = 1;
2067                    push(@implContent, "    $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n");
2068                    push(@implContent, "    return shouldAllowAccessToNode(exec, impl->" . $attribute->signature->name . "()) ? " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl->$implGetterFunctionName()", "castedThis") . " : jsNull();\n");
2069                } elsif ($type eq "EventListener") {
2070                    $implIncludes{"EventListener.h"} = 1;
2071                    push(@implContent, "    UNUSED_PARAM(exec);\n");
2072                    push(@implContent, "    $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n");
2073                    push(@implContent, "    if (EventListener* listener = impl->$implGetterFunctionName()) {\n");
2074                    push(@implContent, "        if (const JSEventListener* jsListener = JSEventListener::cast(listener)) {\n");
2075                    if ($interfaceName eq "Document" || $interfaceName eq "WorkerContext" || $interfaceName eq "SharedWorkerContext" || $interfaceName eq "DedicatedWorkerContext") {
2076                        push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(impl))\n");
2077                    } else {
2078                        push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(impl->scriptExecutionContext()))\n");
2079                    }
2080                    push(@implContent, "                return jsFunction;\n");
2081                    push(@implContent, "        }\n");
2082                    push(@implContent, "    }\n");
2083                    push(@implContent, "    return jsNull();\n");
2084                } elsif ($attribute->signature->type =~ /Constructor$/) {
2085                    my $constructorType = $attribute->signature->type;
2086                    $constructorType =~ s/Constructor$//;
2087                    # When Constructor attribute is used by DOMWindow.idl, it's correct to pass castedThis as the global object
2088                    # When JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject()
2089                    if ($interfaceName eq "DOMWindow") {
2090                        my $named = ($constructorType =~ /Named$/) ? "Named" : "";
2091                        $constructorType =~ s/Named$//;
2092                        push(@implContent, "    return JS" . $constructorType . "::get${named}Constructor(exec, castedThis);\n");
2093                    } else {
2094                       AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2095                       push(@implContent, "    return JS" . $constructorType . "::getConstructor(exec, castedThis->globalObject());\n");
2096                    }
2097                } elsif (!$attribute->signature->extendedAttributes->{"GetterRaisesException"}) {
2098                    push(@implContent, "    UNUSED_PARAM(exec);\n") if !$attribute->signature->extendedAttributes->{"CallWith"};
2099                    push(@implContent, "    bool isNull = false;\n") if $isNullable;
2100
2101                    my $cacheIndex = 0;
2102                    if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2103                        $cacheIndex = $currentCachedAttribute;
2104                        $currentCachedAttribute++;
2105                        push(@implContent, "    if (JSValue cachedValue = castedThis->m_" . $attribute->signature->name . ".get())\n");
2106                        push(@implContent, "        return cachedValue;\n");
2107                    }
2108
2109                    my @callWithArgs = GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "jsUndefined()");
2110
2111                    if ($svgListPropertyType) {
2112                        push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $interfaceName, "castedThis->impl()->$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
2113                    } elsif ($svgPropertyOrListPropertyType) {
2114                        push(@implContent, "    $svgPropertyOrListPropertyType& impl = castedThis->impl()->propertyReference();\n");
2115                        if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
2116                            push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl", "castedThis") . ";\n");
2117                        } else {
2118                            push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
2119
2120                        }
2121                    } else {
2122                        my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
2123                        push(@arguments, "isNull") if $isNullable;
2124                        if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
2125                            my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
2126                            $implIncludes{"${implementedBy}.h"} = 1;
2127                            $functionName = "${implementedBy}::${functionName}";
2128                            unshift(@arguments, "impl") if !$attribute->isStatic;
2129                        } elsif ($attribute->isStatic) {
2130                            $functionName = "${interfaceName}::${functionName}";
2131                        } else {
2132                            $functionName = "impl->${functionName}";
2133                        }
2134
2135                        unshift(@arguments, @callWithArgs);
2136                        my $jsType = NativeToJSValue($attribute->signature, 0, $interfaceName, "${functionName}(" . join(", ", @arguments) . ")", "castedThis");
2137                        push(@implContent, "    $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n") if !$attribute->isStatic;
2138                        if ($codeGenerator->IsSVGAnimatedType($type)) {
2139                            push(@implContent, "    RefPtr<$type> obj = $jsType;\n");
2140                            push(@implContent, "    JSValue result =  toJS(exec, castedThis->globalObject(), obj.get());\n");
2141                        } else {
2142                            push(@implContent, "    JSValue result = $jsType;\n");
2143                        }
2144
2145                        if ($isNullable) {
2146                            push(@implContent, "    if (isNull)\n");
2147                            push(@implContent, "        return jsNull();\n");
2148                        }
2149                    }
2150
2151                    push(@implContent, "    castedThis->m_" . $attribute->signature->name . ".set(exec->vm(), castedThis, result);\n") if ($attribute->signature->extendedAttributes->{"CachedAttribute"});
2152                    push(@implContent, "    return result;\n");
2153
2154                } else {
2155                    my @arguments = ("ec");
2156                    push(@implContent, "    ExceptionCode ec = 0;\n");
2157
2158                    if ($isNullable) {
2159                        push(@implContent, "    bool isNull = false;\n");
2160                        unshift(@arguments, "isNull");
2161                    }
2162
2163                    unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "jsUndefined()"));
2164
2165                    if ($svgPropertyOrListPropertyType) {
2166                        push(@implContent, "    $svgPropertyOrListPropertyType impl(*castedThis->impl());\n");
2167                        push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
2168                    } else {
2169                        push(@implContent, "    $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n");
2170                        push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl->$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
2171                    }
2172
2173                    if ($isNullable) {
2174                        push(@implContent, "    if (isNull)\n");
2175                        push(@implContent, "        return jsNull();\n");
2176                    }
2177
2178                    push(@implContent, "    setDOMException(exec, ec);\n");
2179                    push(@implContent, "    return result;\n");
2180                }
2181
2182                push(@implContent, "}\n\n");
2183
2184                push(@implContent, "#endif\n") if $attributeConditionalString;
2185
2186                push(@implContent, "\n");
2187            }
2188
2189            if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
2190                my $constructorFunctionName = "js" . $interfaceName . "Constructor";
2191
2192                push(@implContent, "JSValue ${constructorFunctionName}(ExecState* exec, JSValue slotBase, PropertyName)\n");
2193                push(@implContent, "{\n");
2194                push(@implContent, "    ${className}* domObject = jsCast<$className*>(asObject(slotBase));\n");
2195
2196                if ($interface->extendedAttributes->{"CheckSecurity"}) {
2197                    $implIncludes{"BindingSecurity.h"} = 1;
2198                    push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, domObject->impl()))\n");
2199                    push(@implContent, "        return jsUndefined();\n");
2200                }
2201
2202                push(@implContent, "    return ${className}::getConstructor(exec, domObject->globalObject());\n");
2203                push(@implContent, "}\n\n");
2204            }
2205        }
2206
2207        # Check if we have any writable attributes
2208        my $hasReadWriteProperties = 0;
2209        foreach my $attribute (@{$interface->attributes}) {
2210            $hasReadWriteProperties = 1 if !IsReadonly($attribute) && !$attribute->isStatic;
2211        }
2212
2213        my $hasSetter = $hasReadWriteProperties
2214                     || $interface->extendedAttributes->{"CustomNamedSetter"}
2215                     || $interface->extendedAttributes->{"CustomIndexedSetter"};
2216
2217        if ($hasSetter) {
2218            if (!$interface->extendedAttributes->{"CustomPutFunction"}) {
2219                push(@implContent, "void ${className}::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
2220                push(@implContent, "{\n");
2221                push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
2222                push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
2223                if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2224                    push(@implContent, "    unsigned index = propertyName.asIndex();\n");
2225                    push(@implContent, "    if (index != PropertyName::NotAnIndex) {\n");
2226                    push(@implContent, "        thisObject->indexSetter(exec, index, value);\n");
2227                    push(@implContent, "        return;\n");
2228                    push(@implContent, "    }\n");
2229                }
2230                if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2231                    push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
2232                    push(@implContent, "        return;\n");
2233                }
2234
2235                if ($hasReadWriteProperties) {
2236                    push(@implContent, "    lookupPut<$className, Base>(exec, propertyName, value, " . hashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, slot);\n");
2237                } else {
2238                    push(@implContent, "    Base::put(thisObject, exec, propertyName, value, slot);\n");
2239                }
2240                push(@implContent, "}\n\n");
2241
2242                if ($interface->extendedAttributes->{"CustomIndexedSetter"} || $interface->extendedAttributes->{"CustomNamedSetter"}) {
2243                    push(@implContent, "void ${className}::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)\n");
2244                    push(@implContent, "{\n");
2245                    push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
2246                    push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
2247                    if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
2248                        push(@implContent, "    if (index <= MAX_ARRAY_INDEX) {\n");
2249                        push(@implContent, "        UNUSED_PARAM(shouldThrow);\n");
2250                        push(@implContent, "        thisObject->indexSetter(exec, index, value);\n");
2251                        push(@implContent, "        return;\n");
2252                        push(@implContent, "    }\n");
2253                    }
2254
2255                    if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
2256                        push(@implContent, "    PropertyName propertyName = Identifier::from(exec, index);\n");
2257                        push(@implContent, "    PutPropertySlot slot(shouldThrow);\n");
2258                        push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
2259                        push(@implContent, "        return;\n");
2260                    }
2261
2262                    push(@implContent, "    Base::putByIndex(cell, exec, index, value, shouldThrow);\n");
2263                    push(@implContent, "}\n\n");
2264                }
2265            }
2266
2267            if ($hasReadWriteProperties) {
2268                foreach my $attribute (@{$interface->attributes}) {
2269                    if (!IsReadonly($attribute)) {
2270                        my $name = $attribute->signature->name;
2271                        my $type = $attribute->signature->type;
2272                        my $putFunctionName = GetAttributeSetterName($interfaceName, $className, $attribute);
2273                        my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
2274                        my $setterRaisesException = $attribute->signature->extendedAttributes->{"SetterRaisesException"};
2275
2276                        my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2277                        push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
2278
2279                        push(@implContent, "void ${putFunctionName}(ExecState* exec, JSObject*");
2280                        push(@implContent, " thisObject") if !$attribute->isStatic;
2281                        push(@implContent, ", JSValue value)\n");
2282                        push(@implContent, "{\n");
2283
2284                            push(@implContent, "    UNUSED_PARAM(exec);\n");
2285
2286                            if ($interface->extendedAttributes->{"CheckSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2287                                if ($interfaceName eq "DOMWindow") {
2288                                    $implIncludes{"BindingSecurity.h"} = 1;
2289                                    push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, jsCast<$className*>(thisObject)->impl()))\n");
2290                                } else {
2291                                    push(@implContent, "    if (!shouldAllowAccessToFrame(exec, jsCast<$className*>(thisObject)->impl()->frame()))\n");
2292                                }
2293                                push(@implContent, "        return;\n");
2294                            }
2295
2296                            if (HasCustomSetter($attribute->signature->extendedAttributes)) {
2297                                push(@implContent, "    jsCast<$className*>(thisObject)->set$implSetterFunctionName(exec, value);\n");
2298                            } elsif ($type eq "EventListener") {
2299                                $implIncludes{"JSEventListener.h"} = 1;
2300                                push(@implContent, "    UNUSED_PARAM(exec);\n");
2301                                push(@implContent, "    ${className}* castedThis = jsCast<${className}*>(thisObject);\n");
2302                                my $windowEventListener = $attribute->signature->extendedAttributes->{"JSWindowEventListener"};
2303                                if ($windowEventListener) {
2304                                    push(@implContent, "    JSDOMGlobalObject* globalObject = castedThis->globalObject();\n");
2305                                }
2306                                push(@implContent, "    $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n");
2307                                if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerContext")) and $name eq "onerror") {
2308                                    $implIncludes{"JSErrorHandler.h"} = 1;
2309                                    push(@implContent, "    impl->set$implSetterFunctionName(createJSErrorHandler(exec, value, thisObject));\n");
2310                                } else {
2311                                    push(@implContent, GenerateAttributeEventListenerCall($className, $implSetterFunctionName, $windowEventListener));
2312                                }
2313                            } elsif ($attribute->signature->type =~ /Constructor$/) {
2314                                my $constructorType = $attribute->signature->type;
2315                                $constructorType =~ s/Constructor$//;
2316                                # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
2317                                # We do not generate the header file for NamedConstructor of class XXXX,
2318                                # since we generate the NamedConstructor declaration into the header file of class XXXX.
2319                                if ($constructorType ne "any" and $constructorType !~ /Named$/) {
2320                                    AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
2321                                }
2322                                push(@implContent, "    // Shadowing a built-in constructor\n");
2323                                if ($interfaceName eq "DOMWindow" && $className eq "JSblah") {
2324                                    # FIXME: This branch never executes and should be removed.
2325                                    push(@implContent, "    jsCast<$className*>(thisObject)->putDirect(exec->vm(), exec->propertyNames().constructor, value);\n");
2326                                } else {
2327                                    push(@implContent, "    jsCast<$className*>(thisObject)->putDirect(exec->vm(), Identifier(exec, \"$name\"), value);\n");
2328                                }
2329                            } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
2330                                push(@implContent, "    // Shadowing a built-in object\n");
2331                                push(@implContent, "    jsCast<$className*>(thisObject)->putDirect(exec->vm(), Identifier(exec, \"$name\"), value);\n");
2332                            } else {
2333                                if (!$attribute->isStatic) {
2334                                    push(@implContent, "    $className* castedThis = jsCast<$className*>(thisObject);\n");
2335                                    push(@implContent, "    $implType* impl = static_cast<$implType*>(castedThis->impl());\n");
2336                                }
2337                                push(@implContent, "    ExceptionCode ec = 0;\n") if $setterRaisesException;
2338
2339                                # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
2340                                # interface type, then if the incoming value does not implement that interface, a TypeError
2341                                # is thrown rather than silently passing NULL to the C++ code.
2342                                # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to
2343                                # both strings and numbers, so do not throw TypeError if the attribute is of these types.
2344                                if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
2345                                    $implIncludes{"<runtime/Error.h>"} = 1;
2346
2347                                    my $argType = $attribute->signature->type;
2348                                    if (!IsNativeType($argType)) {
2349                                        push(@implContent, "    if (!value.isUndefinedOrNull() && !value.inherits(&JS${argType}::s_info)) {\n");
2350                                        push(@implContent, "        throwVMTypeError(exec);\n");
2351                                        push(@implContent, "        return;\n");
2352                                        push(@implContent, "    };\n");
2353                                    }
2354                                }
2355
2356                                push(@implContent, "    " . GetNativeTypeFromSignature($attribute->signature) . " nativeValue(" . JSValueToNative($attribute->signature, "value") . ");\n");
2357                                push(@implContent, "    if (exec->hadException())\n");
2358                                push(@implContent, "        return;\n");
2359
2360                                if ($codeGenerator->IsEnumType($type)) {
2361                                    my @enumValues = $codeGenerator->ValidEnumValues($type);
2362                                    my @enumChecks = ();
2363                                    foreach my $enumValue (@enumValues) {
2364                                        push(@enumChecks, "nativeValue != \"$enumValue\"");
2365                                    }
2366                                    push (@implContent, "    if (" . join(" && ", @enumChecks) . ")\n");
2367                                    push (@implContent, "        return;\n");
2368                                }
2369
2370                                if ($svgPropertyOrListPropertyType) {
2371                                    if ($svgPropertyType) {
2372                                        push(@implContent, "    if (impl->isReadOnly()) {\n");
2373                                        push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
2374                                        push(@implContent, "        return;\n");
2375                                        push(@implContent, "    }\n");
2376                                        $implIncludes{"ExceptionCode.h"} = 1;
2377                                    }
2378                                    push(@implContent, "    $svgPropertyOrListPropertyType& podImpl = impl->propertyReference();\n");
2379                                    if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
2380                                        push(@implContent, "    podImpl = nativeValue;\n");
2381                                    } else {
2382                                        push(@implContent, "    podImpl.set$implSetterFunctionName(nativeValue");
2383                                        push(@implContent, ", ec") if $setterRaisesException;
2384                                        push(@implContent, ");\n");
2385                                        push(@implContent, "    setDOMException(exec, ec);\n") if $setterRaisesException;
2386                                    }
2387                                    if ($svgPropertyType) {
2388                                        if ($setterRaisesException) {
2389                                            push(@implContent, "    if (!ec)\n");
2390                                            push(@implContent, "        impl->commitChange();\n");
2391                                        } else {
2392                                            push(@implContent, "    impl->commitChange();\n");
2393                                        }
2394                                    }
2395                                } else {
2396                                    my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
2397                                    push(@arguments, "nativeValue");
2398                                    if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
2399                                        my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
2400                                        $implIncludes{"${implementedBy}.h"} = 1;
2401                                        unshift(@arguments, "impl") if !$attribute->isStatic;
2402                                        $functionName = "${implementedBy}::${functionName}";
2403                                    } elsif ($attribute->isStatic) {
2404                                        $functionName = "${interfaceName}::${functionName}";
2405                                    } else {
2406                                        $functionName = "impl->${functionName}";
2407                                    }
2408
2409                                    unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, ""));
2410
2411                                    push(@arguments, "ec") if $setterRaisesException;
2412                                    push(@implContent, "    ${functionName}(" . join(", ", @arguments) . ");\n");
2413                                    push(@implContent, "    setDOMException(exec, ec);\n") if $setterRaisesException;
2414                                }
2415                            }
2416
2417                        push(@implContent, "}\n\n");
2418                        push(@implContent, "#endif\n") if $attributeConditionalString;
2419                        push(@implContent, "\n");
2420                    }
2421                }
2422            }
2423
2424            if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
2425                my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2426
2427                push(@implContent, "void ${constructorFunctionName}(ExecState* exec, JSObject* thisObject, JSValue value)\n");
2428                push(@implContent, "{\n");
2429                if ($interface->extendedAttributes->{"CheckSecurity"}) {
2430                    if ($interfaceName eq "DOMWindow") {
2431                        $implIncludes{"BindingSecurity.h"} = 1;
2432                        push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, jsCast<$className*>(thisObject)->impl()))\n");
2433                    } else {
2434                        push(@implContent, "    if (!shouldAllowAccessToFrame(exec, jsCast<$className*>(thisObject)->impl()->frame()))\n");
2435                    }
2436                    push(@implContent, "        return;\n");
2437                }
2438
2439                push(@implContent, "    // Shadowing a built-in constructor\n");
2440
2441                if ($interfaceName eq "DOMWindow") {
2442                    push(@implContent, "    jsCast<$className*>(thisObject)->putDirect(exec->vm(), exec->propertyNames().constructor, value);\n");
2443                } else {
2444                    die "No way to handle interface with ReplaceableConstructor extended attribute: $interfaceName";
2445                }
2446                push(@implContent, "}\n\n");
2447            }
2448        }
2449    }
2450
2451    if ($indexedGetterFunction && !$interface->extendedAttributes->{"CustomEnumerateProperty"}) {
2452        push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
2453        push(@implContent, "{\n");
2454        push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(object);\n");
2455        push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
2456        push(@implContent, "    for (unsigned i = 0; i < static_cast<${interfaceName}*>(thisObject->impl())->length(); ++i)\n");
2457        push(@implContent, "        propertyNames.add(Identifier::from(exec, i));\n");
2458        push(@implContent, "     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);\n");
2459        push(@implContent, "}\n\n");
2460    }
2461
2462    if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
2463        push(@implContent, "JSValue ${className}::getConstructor(ExecState* exec, JSGlobalObject* globalObject)\n{\n");
2464        push(@implContent, "    return getDOMConstructor<${className}Constructor>(exec, jsCast<JSDOMGlobalObject*>(globalObject));\n");
2465        push(@implContent, "}\n\n");
2466        if ($interface->extendedAttributes->{"NamedConstructor"}) {
2467            push(@implContent, "JSValue ${className}::getNamedConstructor(ExecState* exec, JSGlobalObject* globalObject)\n{\n");
2468            push(@implContent, "    return getDOMConstructor<${className}NamedConstructor>(exec, jsCast<JSDOMGlobalObject*>(globalObject));\n");
2469            push(@implContent, "}\n\n");
2470        }
2471    }
2472
2473    # Functions
2474    if ($numFunctions > 0) {
2475        foreach my $function (@{$interface->functions}) {
2476            AddIncludesForTypeInImpl($function->signature->type);
2477
2478            my $isCustom = HasCustomMethod($function->signature->extendedAttributes);
2479            my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
2480            my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
2481
2482            next if $isCustom && $isOverloaded && $function->{overloadIndex} > 1;
2483
2484            my $functionName = GetFunctionName($className, $function);
2485
2486            my $conditional = $function->signature->extendedAttributes->{"Conditional"};
2487            if ($conditional) {
2488                my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2489                push(@implContent, "#if ${conditionalString}\n");
2490            }
2491
2492
2493            if (!$isCustom && $isOverloaded) {
2494                # Append a number to an overloaded method's name to make it unique:
2495                $functionName = $functionName . $function->{overloadIndex};
2496                # Make this function static to avoid compiler warnings, since we
2497                # don't generate a prototype for it in the header.
2498                push(@implContent, "static ");
2499            }
2500
2501            my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
2502
2503            push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
2504            push(@implContent, "{\n");
2505
2506            $implIncludes{"<runtime/Error.h>"} = 1;
2507
2508            if ($function->isStatic) {
2509                if ($isCustom) {
2510                    GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2511                    push(@implContent, "    return JSValue::encode(${className}::" . $functionImplementationName . "(exec));\n");
2512                } else {
2513                    GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2514
2515                    push(@implContent, "    ExceptionCode ec = 0;\n") if $raisesException;
2516
2517                    my $numParameters = @{$function->parameters};
2518                    my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
2519                    GenerateImplementationFunctionCall($function, $functionString, "    ", $svgPropertyType, $interfaceName);
2520                }
2521            } else {
2522                if ($interfaceName eq "DOMWindow") {
2523                    push(@implContent, "    $className* castedThis = toJSDOMWindow(exec->hostThisValue().toThisObject(exec));\n");
2524                    push(@implContent, "    if (!castedThis)\n");
2525                    push(@implContent, "        return throwVMTypeError(exec);\n");
2526                } elsif ($interface->extendedAttributes->{"IsWorkerContext"}) {
2527                    push(@implContent, "    $className* castedThis = to${className}(exec->hostThisValue().toThisObject(exec));\n");
2528                    push(@implContent, "    if (!castedThis)\n");
2529                    push(@implContent, "        return throwVMTypeError(exec);\n");
2530                } else {
2531                    push(@implContent, "    JSValue thisValue = exec->hostThisValue();\n");
2532                    push(@implContent, "    if (!thisValue.inherits(&${className}::s_info))\n");
2533                    push(@implContent, "        return throwVMTypeError(exec);\n");
2534                    push(@implContent, "    $className* castedThis = jsCast<$className*>(asObject(thisValue));\n");
2535                }
2536
2537                push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(castedThis, &${className}::s_info);\n");
2538
2539                if ($interface->extendedAttributes->{"CheckSecurity"} and
2540                    !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2541                    $implIncludes{"BindingSecurity.h"} = 1;
2542                    push(@implContent, "    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
2543                    push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2544                }
2545
2546                if ($isCustom) {
2547                    push(@implContent, "    return JSValue::encode(castedThis->" . $functionImplementationName . "(exec));\n");
2548                } else {
2549                    if ($function->signature->name eq "set" and $interface->extendedAttributes->{"TypedArray"}) {
2550                        my $viewType = $interface->extendedAttributes->{"TypedArray"};
2551                        push(@implContent, "    return JSValue::encode(setWebGLArrayHelper<$implType, $viewType>(exec, castedThis->impl()));\n");
2552                        push(@implContent, "}\n\n");
2553                        next;
2554                    }
2555
2556                    push(@implContent, "    $implType* impl = static_cast<$implType*>(castedThis->impl());\n");
2557                    if ($svgPropertyType) {
2558                        push(@implContent, "    if (impl->isReadOnly()) {\n");
2559                        push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
2560                        push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2561                        push(@implContent, "    }\n");
2562                        push(@implContent, "    $svgPropertyType& podImpl = impl->propertyReference();\n");
2563                        $implIncludes{"ExceptionCode.h"} = 1;
2564                    }
2565
2566                    # For compatibility with legacy content, the EventListener calls are generated without GenerateArgumentsCountCheck.
2567                    if ($function->signature->name eq "addEventListener") {
2568                        push(@implContent, GenerateEventListenerCall($className, "add"));
2569                    } elsif ($function->signature->name eq "removeEventListener") {
2570                        push(@implContent, GenerateEventListenerCall($className, "remove"));
2571                    } else {
2572                        GenerateArgumentsCountCheck(\@implContent, $function, $interface);
2573
2574                        push(@implContent, "    ExceptionCode ec = 0;\n") if $raisesException;
2575
2576                        if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) {
2577                            push(@implContent, "    if (!shouldAllowAccessToNode(exec, impl->" . $function->signature->name . "(" . ($raisesException ? "ec" : "") .")))\n");
2578                            push(@implContent, "        return JSValue::encode(jsNull());\n");
2579                            $implIncludes{"JSDOMBinding.h"} = 1;
2580                        }
2581
2582                        my $numParameters = @{$function->parameters};
2583                        my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
2584                        GenerateImplementationFunctionCall($function, $functionString, "    ", $svgPropertyType, $interfaceName);
2585                    }
2586                }
2587            }
2588
2589            push(@implContent, "}\n\n");
2590
2591            if (!$isCustom && $isOverloaded && $function->{overloadIndex} == @{$function->{overloads}}) {
2592                # Generate a function dispatching call to the rest of the overloads.
2593                GenerateOverloadedFunction($function, $interface, $interfaceName);
2594            }
2595
2596            push(@implContent, "#endif\n\n") if $conditional;
2597        }
2598    }
2599
2600    if ($needsMarkChildren && !$interface->extendedAttributes->{"JSCustomMarkFunction"}) {
2601        push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n");
2602        push(@implContent, "{\n");
2603        push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
2604        push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
2605        push(@implContent, "    COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);\n");
2606        push(@implContent, "    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());\n");
2607        push(@implContent, "    Base::visitChildren(thisObject, visitor);\n");
2608        if ($interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget") {
2609            push(@implContent, "    thisObject->impl()->visitJSEventListeners(visitor);\n");
2610        }
2611        if ($numCachedAttributes > 0) {
2612            foreach (@{$interface->attributes}) {
2613                my $attribute = $_;
2614                if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2615                    push(@implContent, "    visitor.append(&thisObject->m_" . $attribute->signature->name . ");\n");
2616                }
2617            }
2618        }
2619        push(@implContent, "}\n\n");
2620    }
2621
2622    # Cached attributes are indeed allowed when there is a custom mark/visitChildren function.
2623    # The custom function must make sure to account for the cached attribute.
2624    # Uncomment the below line to temporarily enforce generated mark functions when cached attributes are present.
2625    # die "Can't generate binding for class with cached attribute and custom mark." if (($numCachedAttributes > 0) and ($interface->extendedAttributes->{"JSCustomMarkFunction"}));
2626
2627    if ($numConstants > 0) {
2628        push(@implContent, "// Constant getters\n\n");
2629
2630        foreach my $constant (@{$interface->constants}) {
2631            my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
2632            my $conditional = $constant->extendedAttributes->{"Conditional"};
2633
2634            if ($conditional) {
2635                my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2636                push(@implContent, "#if ${conditionalString}\n");
2637            }
2638
2639            # FIXME: this casts into int to match our previous behavior which turned 0xFFFFFFFF in -1 for NodeFilter.SHOW_ALL
2640            push(@implContent, "JSValue ${getter}(ExecState* exec, JSValue, PropertyName)\n");
2641            push(@implContent, "{\n");
2642            if ($constant->type eq "DOMString") {
2643                push(@implContent, "    return jsStringOrNull(exec, String(" . $constant->value . "));\n");
2644            } else {
2645                push(@implContent, "    UNUSED_PARAM(exec);\n");
2646                push(@implContent, "    return jsNumber(static_cast<int>(" . $constant->value . "));\n");
2647            }
2648            push(@implContent, "}\n\n");
2649            push(@implContent, "#endif\n") if $conditional;
2650        }
2651    }
2652
2653    if ($indexedGetterFunction && !$hasNumericIndexedGetter) {
2654        push(@implContent, "\nJSValue ${className}::indexGetter(ExecState* exec, JSValue slotBase, unsigned index)\n");
2655        push(@implContent, "{\n");
2656        push(@implContent, "    ${className}* thisObj = jsCast<$className*>(asObject(slotBase));\n");
2657        push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObj, &s_info);\n");
2658        if (IndexGetterReturnsStrings($interfaceName)) {
2659            $implIncludes{"KURL.h"} = 1;
2660            push(@implContent, "    return jsStringOrUndefined(exec, thisObj->impl()->item(index));\n");
2661        } else {
2662            push(@implContent, "    return toJS(exec, thisObj->globalObject(), static_cast<$interfaceName*>(thisObj->impl())->item(index));\n");
2663        }
2664        push(@implContent, "}\n\n");
2665        if ($interfaceName =~ /^HTML\w*Collection$/ or $interfaceName eq "RadioNodeList") {
2666            $implIncludes{"JSNode.h"} = 1;
2667            $implIncludes{"Node.h"} = 1;
2668        }
2669    }
2670
2671    if ($hasNumericIndexedGetter) {
2672        push(@implContent, "\nJSValue ${className}::getByIndex(ExecState*, unsigned index)\n");
2673        push(@implContent, "{\n");
2674        push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(this, &s_info);\n");
2675        push(@implContent, "    double result = static_cast<$interfaceName*>(impl())->item(index);\n");
2676        # jsNumber conversion doesn't suppress signalling NaNs, so enforce that here.
2677        push(@implContent, "    if (std::isnan(result))\n");
2678        push(@implContent, "        return jsNaN();\n");
2679        push(@implContent, "    return JSValue(result);\n");
2680        push(@implContent, "}\n\n");
2681        if ($interfaceName =~ /^HTML\w*Collection$/) {
2682            $implIncludes{"JSNode.h"} = 1;
2683            $implIncludes{"Node.h"} = 1;
2684        }
2685    }
2686
2687    if ($interfaceName eq "HTMLPropertiesCollection" or $interfaceName eq "DOMNamedFlowCollection") {
2688        if ($namedGetterFunction) {
2689            push(@implContent, "bool ${className}::canGetItemsForName(ExecState*, $interfaceName* collection, PropertyName propertyName)\n");
2690            push(@implContent, "{\n");
2691            push(@implContent, "    return collection->hasNamedItem(propertyNameToAtomicString(propertyName));\n");
2692            push(@implContent, "}\n\n");
2693            push(@implContent, "JSValue ${className}::nameGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName)\n");
2694            push(@implContent, "{\n");
2695            push(@implContent, "    ${className}* thisObj = jsCast<$className*>(asObject(slotBase));\n");
2696            if ($interfaceName eq "HTMLPropertiesCollection") {
2697                push(@implContent, "    return toJS(exec, thisObj->globalObject(), WTF::getPtr(static_cast<$interfaceName*>(thisObj->impl())->propertyNodeList(propertyNameToAtomicString(propertyName))));\n");
2698            } else {
2699                push(@implContent, "    return toJS(exec, thisObj->globalObject(), static_cast<$interfaceName*>(thisObj->impl())->namedItem(propertyNameToAtomicString(propertyName)));\n");
2700            }
2701            push(@implContent, "}\n\n");
2702        }
2703    }
2704
2705    if ((!$hasParent && !GetCustomIsReachable($interface))|| GetGenerateIsReachable($interface) || $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
2706        push(@implContent, "static inline bool isObservable(JS${interfaceName}* js${interfaceName})\n");
2707        push(@implContent, "{\n");
2708        push(@implContent, "    if (js${interfaceName}->hasCustomProperties())\n");
2709        push(@implContent, "        return true;\n");
2710        if ($eventTarget) {
2711            push(@implContent, "    if (js${interfaceName}->impl()->hasEventListeners())\n");
2712            push(@implContent, "        return true;\n");
2713        }
2714        push(@implContent, "    return false;\n");
2715        push(@implContent, "}\n\n");
2716
2717        push(@implContent, "bool JS${interfaceName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)\n");
2718        push(@implContent, "{\n");
2719        push(@implContent, "    JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
2720        # All ActiveDOMObjects implement hasPendingActivity(), but not all of them
2721        # increment their C++ reference counts when hasPendingActivity() becomes
2722        # true. As a result, ActiveDOMObjects can be prematurely destroyed before
2723        # their pending activities complete. To wallpaper over this bug, JavaScript
2724        # wrappers unconditionally keep ActiveDOMObjects with pending activity alive.
2725        # FIXME: Fix this lifetime issue in the DOM, and move this hasPendingActivity
2726        # check below the isObservable check.
2727        if ($codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
2728            push(@implContent, "    if (js${interfaceName}->impl()->hasPendingActivity())\n");
2729            push(@implContent, "        return true;\n");
2730        }
2731        if ($codeGenerator->InheritsExtendedAttribute($interface, "EventTarget")) {
2732            push(@implContent, "    if (js${interfaceName}->impl()->isFiringEventListeners())\n");
2733            push(@implContent, "        return true;\n");
2734        }
2735        if ($codeGenerator->InheritsInterface($interface, "Node")) {
2736            push(@implContent, "    if (JSNodeOwner::isReachableFromOpaqueRoots(handle, 0, visitor))\n");
2737            push(@implContent, "        return true;\n");
2738        }
2739        push(@implContent, "    if (!isObservable(js${interfaceName}))\n");
2740        push(@implContent, "        return false;\n");
2741        if (GetGenerateIsReachable($interface)) {
2742            my $rootString;
2743            if (GetGenerateIsReachable($interface) eq "Impl") {
2744                $rootString  = "    ${implType}* root = js${interfaceName}->impl();\n";
2745            } elsif (GetGenerateIsReachable($interface) eq "ImplContext") {
2746                $rootString  = "    WebGLRenderingContext* root = js${interfaceName}->impl()->context();\n";
2747            } elsif (GetGenerateIsReachable($interface) eq "ImplFrame") {
2748                $rootString  = "    Frame* root = js${interfaceName}->impl()->frame();\n";
2749                $rootString .= "    if (!root)\n";
2750                $rootString .= "        return false;\n";
2751            } elsif (GetGenerateIsReachable($interface) eq "ImplDocument") {
2752                $rootString  = "    Document* root = js${interfaceName}->impl()->document();\n";
2753                $rootString .= "    if (!root)\n";
2754                $rootString .= "        return false;\n";
2755            } elsif (GetGenerateIsReachable($interface) eq "ImplElementRoot") {
2756                $implIncludes{"Element.h"} = 1;
2757                $implIncludes{"JSNodeCustom.h"} = 1;
2758                $rootString  = "    Element* element = js${interfaceName}->impl()->element();\n";
2759                $rootString .= "    if (!element)\n";
2760                $rootString .= "        return false;\n";
2761                $rootString .= "    void* root = WebCore::root(element);\n";
2762            } elsif ($interfaceName eq "CanvasRenderingContext") {
2763                $rootString  = "    void* root = WebCore::root(js${interfaceName}->impl()->canvas());\n";
2764            } elsif (GetGenerateIsReachable($interface) eq "ImplOwnerNodeRoot") {
2765                $implIncludes{"Element.h"} = 1;
2766                $implIncludes{"JSNodeCustom.h"} = 1;
2767                $rootString  = "    void* root = WebCore::root(js${interfaceName}->impl()->ownerNode());\n";
2768            } else {
2769                $rootString  = "    void* root = WebCore::root(js${interfaceName}->impl());\n";
2770            }
2771
2772            push(@implContent, $rootString);
2773            push(@implContent, "    return visitor.containsOpaqueRoot(root);\n");
2774        } else {
2775            push(@implContent, "    UNUSED_PARAM(visitor);\n");
2776            push(@implContent, "    return false;\n");
2777        }
2778        push(@implContent, "}\n\n");
2779    }
2780
2781    if (!$interface->extendedAttributes->{"JSCustomFinalize"} &&
2782        (!$hasParent ||
2783         GetGenerateIsReachable($interface) ||
2784         GetCustomIsReachable($interface) ||
2785         $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject"))) {
2786        push(@implContent, "void JS${interfaceName}Owner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)\n");
2787        push(@implContent, "{\n");
2788        push(@implContent, "    JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
2789        push(@implContent, "    DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context);\n");
2790        push(@implContent, "    uncacheWrapper(world, js${interfaceName}->impl(), js${interfaceName});\n");
2791        push(@implContent, "    js${interfaceName}->releaseImpl();\n");
2792        push(@implContent, "}\n\n");
2793    }
2794
2795    if (ShouldGenerateToJSImplementation($hasParent, $interface)) {
2796        my $vtableNameGnu = GetGnuVTableNameForInterface($interface);
2797        my $vtableRefGnu = GetGnuVTableRefForInterface($interface);
2798        my $vtableRefWin = GetWinVTableRefForInterface($interface);
2799
2800        push(@implContent, <<END) if $vtableNameGnu;
2801#if ENABLE(BINDING_INTEGRITY)
2802#if PLATFORM(WIN)
2803#pragma warning(disable: 4483)
2804extern "C" { extern void (*const ${vtableRefWin}[])(); }
2805#else
2806extern "C" { extern void* ${vtableNameGnu}[]; }
2807#endif
2808#endif
2809END
2810
2811        push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n");
2812        push(@implContent, "{\n");
2813        push(@implContent, <<END);
2814    if (!impl)
2815        return jsNull();
2816END
2817
2818        if ($svgPropertyType) {
2819            push(@implContent, "    if (JSValue result = getExistingWrapper<$className, $implType>(exec, impl))\n");
2820            push(@implContent, "        return result;\n");
2821        } else {
2822            push(@implContent, "    if (JSValue result = getExistingWrapper<$className>(exec, impl))\n");
2823            push(@implContent, "        return result;\n");
2824        }
2825        push(@implContent, <<END) if $vtableNameGnu;
2826
2827#if ENABLE(BINDING_INTEGRITY)
2828    void* actualVTablePointer = *(reinterpret_cast<void**>(impl));
2829#if PLATFORM(WIN)
2830    void* expectedVTablePointer = reinterpret_cast<void*>(${vtableRefWin});
2831#else
2832    void* expectedVTablePointer = ${vtableRefGnu};
2833#if COMPILER(CLANG)
2834    // If this fails $implType does not have a vtable, so you need to add the
2835    // ImplementationLacksVTable attribute to the interface definition
2836    COMPILE_ASSERT(__is_polymorphic($implType), ${implType}_is_not_polymorphic);
2837#endif
2838#endif
2839    // If you hit this assertion you either have a use after free bug, or
2840    // $implType has subclasses. If $implType has subclasses that get passed
2841    // to toJS() we currently require $interfaceName you to opt out of binding hardening
2842    // by adding the SkipVTableValidation attribute to the interface IDL definition
2843    RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer);
2844#endif
2845END
2846        push(@implContent, <<END) if $interface->extendedAttributes->{"ImplementationLacksVTable"};
2847#if COMPILER(CLANG)
2848    // If you hit this failure the interface definition has the ImplementationLacksVTable
2849    // attribute. You should remove that attribute. If the class has subclasses
2850    // that may be passed through this toJS() function you should use the SkipVTableValidation
2851    // attribute to $interfaceName.
2852    COMPILE_ASSERT(!__is_polymorphic($implType), ${implType}_is_polymorphic_but_idl_claims_not_to_be);
2853#endif
2854END
2855        push(@implContent, <<END);
2856    ReportMemoryCost<$implType>::reportMemoryCost(exec, impl);
2857END
2858
2859        if ($svgPropertyType) {
2860            push(@implContent, "    return createNewWrapper<$className, $implType>(exec, globalObject, impl);\n");
2861        } else {
2862            push(@implContent, "    return createNewWrapper<$className>(exec, globalObject, impl);\n");
2863        }
2864
2865        push(@implContent, "}\n\n");
2866    }
2867
2868    if ((!$hasParent or $interface->extendedAttributes->{"JSGenerateToNativeObject"}) and !$interface->extendedAttributes->{"JSCustomToNativeObject"}) {
2869        push(@implContent, "$implType* to${interfaceName}(JSC::JSValue value)\n");
2870        push(@implContent, "{\n");
2871        push(@implContent, "    return value.inherits(&${className}::s_info) ? jsCast<$className*>(asObject(value))->impl() : 0");
2872        push(@implContent, ";\n}\n");
2873    }
2874
2875    push(@implContent, "\n}\n");
2876
2877    my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
2878    push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2879}
2880
2881sub GenerateCallWith
2882{
2883    my $callWith = shift;
2884    return () unless $callWith;
2885    my $outputArray = shift;
2886    my $returnValue = shift;
2887    my $function = shift;
2888
2889    my @callWithArgs;
2890    if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
2891        push(@callWithArgs, "exec");
2892    }
2893    if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptExecutionContext")) {
2894        push(@$outputArray, "    ScriptExecutionContext* scriptContext = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();\n");
2895        push(@$outputArray, "    if (!scriptContext)\n");
2896        push(@$outputArray, "        return" . ($returnValue ? " " . $returnValue : "") . ";\n");
2897        push(@callWithArgs, "scriptContext");
2898    }
2899    if ($function and $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments")) {
2900        push(@$outputArray, "    RefPtr<ScriptArguments> scriptArguments(createScriptArguments(exec, " . @{$function->parameters} . "));\n");
2901        $implIncludes{"ScriptArguments.h"} = 1;
2902        $implIncludes{"ScriptCallStackFactory.h"} = 1;
2903        push(@callWithArgs, "scriptArguments.release()");
2904    }
2905    return @callWithArgs;
2906}
2907
2908sub GenerateArgumentsCountCheck
2909{
2910    my $outputArray = shift;
2911    my $function = shift;
2912    my $interface = shift;
2913
2914    my $numMandatoryParams = @{$function->parameters};
2915    foreach my $param (reverse(@{$function->parameters})) {
2916        if ($param->isOptional or $param->isVariadic) {
2917            $numMandatoryParams--;
2918        } else {
2919            last;
2920        }
2921    }
2922    if ($numMandatoryParams >= 1)
2923    {
2924        push(@$outputArray, "    if (exec->argumentCount() < $numMandatoryParams)\n");
2925        push(@$outputArray, "        return throwVMError(exec, createNotEnoughArgumentsError(exec));\n");
2926    }
2927}
2928
2929sub GenerateParametersCheck
2930{
2931    my $outputArray = shift;
2932    my $function = shift;
2933    my $interface = shift;
2934    my $numParameters = shift;
2935    my $interfaceName = shift;
2936    my $functionImplementationName = shift;
2937    my $svgPropertyType = shift;
2938    my $svgPropertyOrListPropertyType = shift;
2939    my $svgListPropertyType = shift;
2940
2941    my $argsIndex = 0;
2942    my $hasOptionalArguments = 0;
2943    my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
2944
2945    my @arguments;
2946    my $functionName;
2947    my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
2948    if ($implementedBy) {
2949        AddToImplIncludes("${implementedBy}.h");
2950        unshift(@arguments, "impl") if !$function->isStatic;
2951        $functionName = "${implementedBy}::${functionImplementationName}";
2952    } elsif ($function->isStatic) {
2953        $functionName = "${interfaceName}::${functionImplementationName}";
2954    } elsif ($svgPropertyOrListPropertyType and !$svgListPropertyType) {
2955        $functionName = "podImpl.${functionImplementationName}";
2956    } else {
2957        $functionName = "impl->${functionImplementationName}";
2958    }
2959
2960    if (!$function->signature->extendedAttributes->{"Constructor"}) {
2961        push(@arguments, GenerateCallWith($function->signature->extendedAttributes->{"CallWith"}, \@$outputArray, "JSValue::encode(jsUndefined())", $function));
2962    }
2963
2964    $implIncludes{"ExceptionCode.h"} = 1;
2965    $implIncludes{"JSDOMBinding.h"} = 1;
2966
2967    foreach my $parameter (@{$function->parameters}) {
2968        my $argType = $parameter->type;
2969
2970        # Optional arguments with [Optional] should generate an early call with fewer arguments.
2971        # Optional arguments with [Optional=...] should not generate the early call.
2972        # Optional Dictionary arguments always considered to have default of empty dictionary.
2973        my $optional = $parameter->isOptional;
2974        my $defaultAttribute = $parameter->extendedAttributes->{"Default"};
2975        if ($optional && !$defaultAttribute && $argType ne "Dictionary" && !$codeGenerator->IsCallbackInterface($parameter->type)) {
2976            # Generate early call if there are enough parameters.
2977            if (!$hasOptionalArguments) {
2978                push(@$outputArray, "\n    size_t argsCount = exec->argumentCount();\n");
2979                $hasOptionalArguments = 1;
2980            }
2981            push(@$outputArray, "    if (argsCount <= $argsIndex) {\n");
2982
2983            my @optionalCallbackArguments = @arguments;
2984            push(@optionalCallbackArguments, "ec") if $raisesException;
2985            my $functionString = "$functionName(" . join(", ", @optionalCallbackArguments) . ")";
2986            GenerateImplementationFunctionCall($function, $functionString, "    " x 2, $svgPropertyType, $interfaceName);
2987            push(@$outputArray, "    }\n\n");
2988        }
2989
2990        my $name = $parameter->name;
2991
2992        if ($argType eq "XPathNSResolver") {
2993            push(@$outputArray, "    RefPtr<XPathNSResolver> customResolver;\n");
2994            push(@$outputArray, "    XPathNSResolver* resolver = toXPathNSResolver(exec->argument($argsIndex));\n");
2995            push(@$outputArray, "    if (!resolver) {\n");
2996            push(@$outputArray, "        customResolver = JSCustomXPathNSResolver::create(exec, exec->argument($argsIndex));\n");
2997            push(@$outputArray, "        if (exec->hadException())\n");
2998            push(@$outputArray, "            return JSValue::encode(jsUndefined());\n");
2999            push(@$outputArray, "        resolver = customResolver.get();\n");
3000            push(@$outputArray, "    }\n");
3001        } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) {
3002            my $callbackClassName = GetCallbackClassName($argType);
3003            $implIncludes{"$callbackClassName.h"} = 1;
3004            if ($optional) {
3005                push(@$outputArray, "    RefPtr<$argType> $name;\n");
3006                push(@$outputArray, "    if (exec->argumentCount() > $argsIndex && !exec->argument($argsIndex).isUndefinedOrNull()) {\n");
3007                push(@$outputArray, "        if (!exec->argument($argsIndex).isFunction())\n");
3008                push(@$outputArray, "            return throwVMTypeError(exec);\n");
3009                if ($function->isStatic) {
3010                    AddToImplIncludes("CallbackFunction.h");
3011                    push(@$outputArray, "        $name = createFunctionOnlyCallback<${callbackClassName}>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument($argsIndex));\n");
3012                } else {
3013                    push(@$outputArray, "        $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n");
3014                }
3015                push(@$outputArray, "    }\n");
3016            } else {
3017                push(@$outputArray, "    if (exec->argumentCount() <= $argsIndex || !exec->argument($argsIndex).isFunction())\n");
3018                push(@$outputArray, "        return throwVMTypeError(exec);\n");
3019                if ($function->isStatic) {
3020                    AddToImplIncludes("CallbackFunction.h");
3021                    push(@$outputArray, "    RefPtr<$argType> $name = createFunctionOnlyCallback<${callbackClassName}>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument($argsIndex));\n");
3022                } else {
3023                    push(@$outputArray, "    RefPtr<$argType> $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n");
3024                }
3025            }
3026        } elsif ($parameter->extendedAttributes->{"Clamp"}) {
3027            my $nativeValue = "${name}NativeValue";
3028            push(@$outputArray, "    $argType $name = 0;\n");
3029            push(@$outputArray, "    double $nativeValue = exec->argument($argsIndex).toNumber(exec);\n");
3030            push(@$outputArray, "    if (exec->hadException())\n");
3031            push(@$outputArray, "        return JSValue::encode(jsUndefined());\n\n");
3032            push(@$outputArray, "    if (!std::isnan($nativeValue))\n");
3033            push(@$outputArray, "        $name = clampTo<$argType>($nativeValue);\n\n");
3034        } elsif ($parameter->isVariadic) {
3035            my $nativeElementType;
3036            if ($argType eq "DOMString") {
3037                $nativeElementType = "String";
3038            } else {
3039                $nativeElementType = GetNativeType($argType);
3040                if ($nativeElementType =~ />$/) {
3041                    $nativeElementType .= " ";
3042                }
3043            }
3044
3045            if (!IsNativeType($argType)) {
3046                push(@$outputArray, "    Vector<$nativeElementType> $name;\n");
3047                push(@$outputArray, "    for (unsigned i = $argsIndex; i < exec->argumentCount(); ++i) {\n");
3048                push(@$outputArray, "        if (!exec->argument(i).inherits(&JS${argType}::s_info))\n");
3049                push(@$outputArray, "            return throwVMTypeError(exec);\n");
3050                push(@$outputArray, "        $name.append(to$argType(exec->argument(i)));\n");
3051                push(@$outputArray, "    }\n")
3052            } else {
3053                push(@$outputArray, "    Vector<$nativeElementType> $name = toNativeArguments<$nativeElementType>(exec, $argsIndex);\n");
3054                # Check if the type conversion succeeded.
3055                push(@$outputArray, "    if (exec->hadException())\n");
3056                push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3057            }
3058
3059        } elsif ($codeGenerator->IsEnumType($argType)) {
3060            $implIncludes{"<runtime/Error.h>"} = 1;
3061
3062            my $argValue = "exec->argument($argsIndex)";
3063            push(@$outputArray, "    const String ${name}(${argValue}.isEmpty() ? String() : ${argValue}.toString(exec)->value(exec));\n");
3064            push(@$outputArray, "    if (exec->hadException())\n");
3065            push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3066
3067            my @enumValues = $codeGenerator->ValidEnumValues($argType);
3068            my @enumChecks = ();
3069            foreach my $enumValue (@enumValues) {
3070                push(@enumChecks, "${name} != \"$enumValue\"");
3071            }
3072            push (@$outputArray, "    if (" . join(" && ", @enumChecks) . ")\n");
3073            push (@$outputArray, "        return throwVMTypeError(exec);\n");
3074        } else {
3075            # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
3076            # interface type, then if the incoming value does not implement that interface, a TypeError
3077            # is thrown rather than silently passing NULL to the C++ code.
3078            # Per the Web IDL and ECMAScript semantics, incoming values can always be converted to both
3079            # strings and numbers, so do not throw TypeError if the argument is of these types.
3080            if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
3081                $implIncludes{"<runtime/Error.h>"} = 1;
3082
3083                my $argValue = "exec->argument($argsIndex)";
3084                if (!IsNativeType($argType)) {
3085                    push(@$outputArray, "    if (exec->argumentCount() > $argsIndex && !${argValue}.isUndefinedOrNull() && !${argValue}.inherits(&JS${argType}::s_info))\n");
3086                    push(@$outputArray, "        return throwVMTypeError(exec);\n");
3087                }
3088            }
3089
3090            push(@$outputArray, "    " . GetNativeTypeFromSignature($parameter) . " $name(" . JSValueToNative($parameter, $optional && $defaultAttribute && $defaultAttribute eq "NullString" ? "argumentOrNull(exec, $argsIndex)" : "exec->argument($argsIndex)") . ");\n");
3091
3092            # If a parameter is "an index" and it's negative it should throw an INDEX_SIZE_ERR exception.
3093            # But this needs to be done in the bindings, because the type is unsigned and the fact that it
3094            # was negative will be lost by the time we're inside the DOM.
3095            if ($parameter->extendedAttributes->{"IsIndex"}) {
3096                push(@$outputArray, "    if ($name < 0) {\n");
3097                push(@$outputArray, "        setDOMException(exec, INDEX_SIZE_ERR);\n");
3098                push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3099                push(@$outputArray, "    }\n");
3100            }
3101
3102            # Check if the type conversion succeeded.
3103            push(@$outputArray, "    if (exec->hadException())\n");
3104            push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3105
3106            if ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $interfaceName =~ /List$/) {
3107                push(@$outputArray, "    if (!$name) {\n");
3108                push(@$outputArray, "        setDOMException(exec, TYPE_MISMATCH_ERR);\n");
3109                push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
3110                push(@$outputArray, "    }\n");
3111            }
3112        }
3113
3114        if ($argType eq "NodeFilter") {
3115            push @arguments, "$name.get()";
3116        } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $interfaceName =~ /List$/) {
3117            push @arguments, "$name->propertyReference()";
3118        } else {
3119            push @arguments, $name;
3120        }
3121        $argsIndex++;
3122    }
3123
3124    push(@arguments, "ec") if $raisesException;
3125
3126    return ("$functionName(" . join(", ", @arguments) . ")", scalar @arguments);
3127}
3128
3129sub GenerateCallbackHeader
3130{
3131    my $object = shift;
3132    my $interface = shift;
3133
3134    my $interfaceName = $interface->name;
3135    my $className = "JS$interfaceName";
3136
3137    # - Add default header template and header protection
3138    push(@headerContentHeader, GenerateHeaderContentHeader($interface));
3139
3140    $headerIncludes{"ActiveDOMCallback.h"} = 1;
3141    $headerIncludes{"$interfaceName.h"} = 1;
3142    $headerIncludes{"JSCallbackData.h"} = 1;
3143    $headerIncludes{"<wtf/Forward.h>"} = 1;
3144
3145    push(@headerContent, "\nnamespace WebCore {\n\n");
3146    push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
3147    push(@headerContent, "public:\n");
3148
3149    # The static create() method.
3150    push(@headerContent, "    static PassRefPtr<$className> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject)\n");
3151    push(@headerContent, "    {\n");
3152    push(@headerContent, "        return adoptRef(new $className(callback, globalObject));\n");
3153    push(@headerContent, "    }\n\n");
3154
3155    # ScriptExecutionContext
3156    push(@headerContent, "    virtual ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); }\n\n");
3157
3158    # Destructor
3159    push(@headerContent, "    virtual ~$className();\n");
3160
3161    # Functions
3162    my $numFunctions = @{$interface->functions};
3163    if ($numFunctions > 0) {
3164        push(@headerContent, "\n    // Functions\n");
3165        foreach my $function (@{$interface->functions}) {
3166            my @params = @{$function->parameters};
3167            if (!$function->signature->extendedAttributes->{"Custom"} &&
3168                !(GetNativeType($function->signature->type) eq "bool")) {
3169                push(@headerContent, "    COMPILE_ASSERT(false)");
3170            }
3171
3172            push(@headerContent, "    virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "(");
3173
3174            my @args = ();
3175            foreach my $param (@params) {
3176                push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
3177            }
3178            push(@headerContent, join(", ", @args));
3179
3180            push(@headerContent, ");\n");
3181        }
3182    }
3183
3184    push(@headerContent, "\nprivate:\n");
3185
3186    # Constructor
3187    push(@headerContent, "    $className(JSC::JSObject* callback, JSDOMGlobalObject*);\n\n");
3188
3189    # Private members
3190    push(@headerContent, "    JSCallbackData* m_data;\n");
3191    push(@headerContent, "};\n\n");
3192
3193    push(@headerContent, "} // namespace WebCore\n\n");
3194    my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
3195    push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
3196    push(@headerContent, "#endif\n");
3197}
3198
3199sub GenerateCallbackImplementation
3200{
3201    my ($object, $interface) = @_;
3202
3203    my $interfaceName = $interface->name;
3204    my $className = "JS$interfaceName";
3205
3206    # - Add default header template
3207    push(@implContentHeader, GenerateImplementationContentHeader($interface));
3208
3209    $implIncludes{"ScriptExecutionContext.h"} = 1;
3210    $implIncludes{"<runtime/JSLock.h>"} = 1;
3211
3212    @implContent = ();
3213
3214    push(@implContent, "\nusing namespace JSC;\n\n");
3215    push(@implContent, "namespace WebCore {\n\n");
3216
3217    # Constructor
3218    push(@implContent, "${className}::${className}(JSObject* callback, JSDOMGlobalObject* globalObject)\n");
3219    push(@implContent, "    : ActiveDOMCallback(globalObject->scriptExecutionContext())\n");
3220    push(@implContent, "    , m_data(new JSCallbackData(callback, globalObject))\n");
3221    push(@implContent, "{\n");
3222    push(@implContent, "}\n\n");
3223
3224    # Destructor
3225    push(@implContent, "${className}::~${className}()\n");
3226    push(@implContent, "{\n");
3227    push(@implContent, "    ScriptExecutionContext* context = scriptExecutionContext();\n");
3228    push(@implContent, "    // When the context is destroyed, all tasks with a reference to a callback\n");
3229    push(@implContent, "    // should be deleted. So if the context is 0, we are on the context thread.\n");
3230    push(@implContent, "    if (!context || context->isContextThread())\n");
3231    push(@implContent, "        delete m_data;\n");
3232    push(@implContent, "    else\n");
3233    push(@implContent, "        context->postTask(DeleteCallbackDataTask::create(m_data));\n");
3234    push(@implContent, "#ifndef NDEBUG\n");
3235    push(@implContent, "    m_data = 0;\n");
3236    push(@implContent, "#endif\n");
3237    push(@implContent, "}\n");
3238
3239    # Functions
3240    my $numFunctions = @{$interface->functions};
3241    if ($numFunctions > 0) {
3242        push(@implContent, "\n// Functions\n");
3243        foreach my $function (@{$interface->functions}) {
3244            my @params = @{$function->parameters};
3245            if ($function->signature->extendedAttributes->{"Custom"} ||
3246                !(GetNativeType($function->signature->type) eq "bool")) {
3247                next;
3248            }
3249
3250            AddIncludesForTypeInImpl($function->signature->type);
3251            push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "(");
3252
3253            my @args = ();
3254            my @argsCheck = ();
3255            my $thisType = $function->signature->extendedAttributes->{"PassThisToCallback"};
3256            foreach my $param (@params) {
3257                my $paramName = $param->name;
3258                AddIncludesForTypeInImpl($param->type, 1);
3259                push(@args, GetNativeTypeForCallbacks($param->type) . " " . $paramName);
3260                if ($thisType and $thisType eq $param->type) {
3261                    push(@argsCheck, <<END);
3262    ASSERT(${paramName});
3263
3264END
3265                }
3266            }
3267            push(@implContent, join(", ", @args));
3268            push(@implContent, ")\n");
3269
3270            push(@implContent, "{\n");
3271            push(@implContent, @argsCheck) if @argsCheck;
3272            push(@implContent, "    if (!canInvokeCallback())\n");
3273            push(@implContent, "        return true;\n\n");
3274            push(@implContent, "    RefPtr<$className> protect(this);\n\n");
3275            push(@implContent, "    JSLockHolder lock(m_data->globalObject()->vm());\n\n");
3276            if (@params) {
3277                push(@implContent, "    ExecState* exec = m_data->globalObject()->globalExec();\n");
3278            }
3279            push(@implContent, "    MarkedArgumentBuffer args;\n");
3280
3281            foreach my $param (@params) {
3282                my $paramName = $param->name;
3283                if ($param->type eq "DOMString") {
3284                    push(@implContent, "    args.append(jsStringWithCache(exec, ${paramName}));\n");
3285                } elsif ($param->type eq "boolean") {
3286                    push(@implContent, "    args.append(jsBoolean(${paramName}));\n");
3287                } elsif ($param->type eq "SerializedScriptValue") {
3288                    push(@implContent, "    args.append($paramName ? $paramName->deserialize(exec, m_data->globalObject(), 0) : jsNull());\n");
3289                } else {
3290                    push(@implContent, "    args.append(toJS(exec, m_data->globalObject(), ${paramName}));\n");
3291                }
3292            }
3293
3294            push(@implContent, "\n    bool raisedException = false;\n");
3295            if ($thisType) {
3296                foreach my $param (@params) {
3297                    next if $param->type ne $thisType;
3298                    my $paramName = $param->name;
3299                    push(@implContent, <<END);
3300    JSValue js${paramName} = toJS(exec, m_data->globalObject(), ${paramName});
3301    m_data->invokeCallback(js${paramName}, args, &raisedException);
3302
3303END
3304                    last;
3305                }
3306            } else {
3307                push(@implContent, "    m_data->invokeCallback(args, &raisedException);\n");
3308            }
3309            push(@implContent, "    return !raisedException;\n");
3310            push(@implContent, "}\n");
3311        }
3312    }
3313
3314    push(@implContent, "\n}\n");
3315    my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
3316    push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
3317}
3318
3319sub GenerateImplementationFunctionCall()
3320{
3321    my $function = shift;
3322    my $functionString = shift;
3323    my $indent = shift;
3324    my $svgPropertyType = shift;
3325    my $interfaceName = shift;
3326
3327    my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
3328
3329    if ($function->signature->type eq "void") {
3330        push(@implContent, $indent . "$functionString;\n");
3331        push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException;
3332
3333        if ($svgPropertyType and !$function->isStatic) {
3334            if ($raisesException) {
3335                push(@implContent, $indent . "if (!ec)\n");
3336                push(@implContent, $indent . "    impl->commitChange();\n");
3337            } else {
3338                push(@implContent, $indent . "impl->commitChange();\n");
3339            }
3340        }
3341
3342        push(@implContent, $indent . "return JSValue::encode(jsUndefined());\n");
3343    } else {
3344        my $thisObject = $function->isStatic ? 0 : "castedThis";
3345        push(@implContent, "\n" . $indent . "JSC::JSValue result = " . NativeToJSValue($function->signature, 1, $interfaceName, $functionString, $thisObject) . ";\n");
3346        push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException;
3347
3348        if ($codeGenerator->ExtendedAttributeContains($function->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
3349            push(@implContent, $indent . "if (exec->hadException())\n");
3350            push(@implContent, $indent . "    return JSValue::encode(jsUndefined());\n");
3351        }
3352
3353        push(@implContent, $indent . "return JSValue::encode(result);\n");
3354    }
3355}
3356
3357sub GetNativeTypeFromSignature
3358{
3359    my $signature = shift;
3360    my $type = $signature->type;
3361
3362    if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
3363        # Special-case index arguments because we need to check that they aren't < 0.
3364        return "int";
3365    }
3366
3367    return GetNativeType($type);
3368}
3369
3370my %nativeType = (
3371    "CompareHow" => "Range::CompareHow",
3372    "DOMString" => "const String&",
3373    "NodeFilter" => "RefPtr<NodeFilter>",
3374    "SerializedScriptValue" => "RefPtr<SerializedScriptValue>",
3375    "Date" => "double",
3376    "Dictionary" => "Dictionary",
3377    "any" => "ScriptValue",
3378    "boolean" => "bool",
3379    "double" => "double",
3380    "float" => "float",
3381    "short" => "short",
3382    "long" => "int",
3383    "unsigned long" => "unsigned",
3384    "unsigned short" => "unsigned short",
3385    "long long" => "long long",
3386    "unsigned long long" => "unsigned long long",
3387    "byte" => "int8_t",
3388    "octet" => "uint8_t",
3389    "MediaQueryListListener" => "RefPtr<MediaQueryListListener>",
3390    "DOMTimeStamp" => "DOMTimeStamp",
3391);
3392
3393sub GetNativeType
3394{
3395    my $type = shift;
3396
3397    my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
3398    return "${svgNativeType}*" if $svgNativeType;
3399    return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
3400    return $nativeType{$type} if exists $nativeType{$type};
3401
3402    my $arrayType = $codeGenerator->GetArrayType($type);
3403    my $sequenceType = $codeGenerator->GetSequenceType($type);
3404    my $arrayOrSequenceType = $arrayType || $sequenceType;
3405
3406    return "Vector<" . GetNativeVectorInnerType($arrayOrSequenceType) . ">" if $arrayOrSequenceType;
3407
3408    if ($codeGenerator->IsEnumType($type)) {
3409        return "const String";
3410    }
3411
3412    # For all other types, the native type is a pointer with same type name as the IDL type.
3413    return "${type}*";
3414}
3415
3416sub GetNativeVectorInnerType
3417{
3418    my $arrayOrSequenceType = shift;
3419
3420    return "String" if $arrayOrSequenceType eq "DOMString";
3421    return $nativeType{$arrayOrSequenceType} if exists $nativeType{$arrayOrSequenceType};
3422    return "RefPtr<${arrayOrSequenceType}> ";
3423}
3424
3425sub GetNativeTypeForCallbacks
3426{
3427    my $type = shift;
3428    return "PassRefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue";
3429    return "PassRefPtr<DOMStringList>" if $type eq "DOMStringList";
3430
3431    return GetNativeType($type);
3432}
3433
3434sub GetSVGPropertyTypes
3435{
3436    my $implType = shift;
3437
3438    my $svgPropertyType;
3439    my $svgListPropertyType;
3440    my $svgNativeType;
3441
3442    return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/;
3443
3444    $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType);
3445    return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType;
3446
3447    # Append space to avoid compilation errors when using  PassRefPtr<$svgNativeType>
3448    $svgNativeType = "$svgNativeType ";
3449
3450    my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType);
3451    if ($svgNativeType =~ /SVGPropertyTearOff/) {
3452        $svgPropertyType = $svgWrappedNativeType;
3453        $headerIncludes{"$svgWrappedNativeType.h"} = 1;
3454        $headerIncludes{"SVGAnimatedPropertyTearOff.h"} = 1;
3455    } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
3456        $svgListPropertyType = $svgWrappedNativeType;
3457        $headerIncludes{"$svgWrappedNativeType.h"} = 1;
3458        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
3459    } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
3460        $svgListPropertyType = $svgWrappedNativeType;
3461        $headerIncludes{"$svgWrappedNativeType.h"} = 1;
3462        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
3463        $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
3464    } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
3465        $svgListPropertyType = $svgWrappedNativeType;
3466        $headerIncludes{"$svgWrappedNativeType.h"} = 1;
3467        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
3468        $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
3469    }
3470
3471    return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
3472}
3473
3474sub IsNativeType
3475{
3476    my $type = shift;
3477    return exists $nativeType{$type};
3478}
3479
3480sub JSValueToNative
3481{
3482    my $signature = shift;
3483    my $value = shift;
3484
3485    my $conditional = $signature->extendedAttributes->{"Conditional"};
3486    my $type = $signature->type;
3487
3488    return "$value.toBoolean(exec)" if $type eq "boolean";
3489    return "$value.toNumber(exec)" if $type eq "double";
3490    return "$value.toFloat(exec)" if $type eq "float";
3491
3492    my $intConversion = $signature->extendedAttributes->{"EnforceRange"} ? "EnforceRange" : "NormalConversion";
3493    return "toInt8(exec, $value, $intConversion)" if $type eq "byte";
3494    return "toUInt8(exec, $value, $intConversion)" if $type eq "octet";
3495    return "toInt32(exec, $value, $intConversion)" if $type eq "long" or $type eq "short";
3496    return "toUInt32(exec, $value, $intConversion)" if $type eq "unsigned long" or $type eq "unsigned short";
3497    return "toInt64(exec, $value, $intConversion)" if $type eq "long long";
3498    return "toUInt64(exec, $value, $intConversion)" if $type eq "unsigned long long";
3499
3500    return "valueToDate(exec, $value)" if $type eq "Date";
3501    return "static_cast<Range::CompareHow>($value.toInt32(exec))" if $type eq "CompareHow";
3502
3503    if ($type eq "DOMString") {
3504        # FIXME: This implements [TreatNullAs=NullString] and [TreatUndefinedAs=NullString],
3505        # but the Web IDL spec requires [TreatNullAs=EmptyString] and [TreatUndefinedAs=EmptyString].
3506        if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") and ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString")) {
3507            return "valueToStringWithUndefinedOrNullCheck(exec, $value)"
3508        }
3509        if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") or $signature->extendedAttributes->{"Reflect"}) {
3510            return "valueToStringWithNullCheck(exec, $value)"
3511        }
3512        # FIXME: Add the case for 'if ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString"))'.
3513        return "$value.isEmpty() ? String() : $value.toString(exec)->value(exec)";
3514    }
3515
3516    if ($type eq "any") {
3517        return "exec->vm(), $value";
3518    }
3519
3520    if ($type eq "NodeFilter") {
3521        AddToImplIncludes("JS$type.h", $conditional);
3522        return "to$type(exec->vm(), $value)";
3523    }
3524
3525    if ($type eq "MediaQueryListListener") {
3526        AddToImplIncludes("MediaQueryListListener.h", $conditional);
3527        return "MediaQueryListListener::create(ScriptValue(exec->vm(), " . $value ."))";
3528    }
3529
3530    if ($type eq "SerializedScriptValue") {
3531        AddToImplIncludes("SerializedScriptValue.h", $conditional);
3532        return "SerializedScriptValue::create(exec, $value, 0, 0)";
3533    }
3534
3535    if ($type eq "Dictionary") {
3536        AddToImplIncludes("Dictionary.h", $conditional);
3537        return "exec, $value";
3538    }
3539
3540    if ($type eq "DOMStringList" ) {
3541        AddToImplIncludes("JSDOMStringList.h", $conditional);
3542        return "toDOMStringList(exec, $value)";
3543    }
3544
3545    AddToImplIncludes("HTMLOptionElement.h", $conditional) if $type eq "HTMLOptionElement";
3546    AddToImplIncludes("Event.h", $conditional) if $type eq "Event";
3547
3548    my $arrayType = $codeGenerator->GetArrayType($type);
3549    my $sequenceType = $codeGenerator->GetSequenceType($type);
3550    my $arrayOrSequenceType = $arrayType || $sequenceType;
3551
3552    if ($arrayOrSequenceType) {
3553        if ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) {
3554            AddToImplIncludes("JS${arrayOrSequenceType}.h");
3555            return "(toRefPtrNativeArray<${arrayOrSequenceType}, JS${arrayOrSequenceType}>(exec, $value, &to${arrayOrSequenceType}))";
3556        }
3557        return "toNativeArray<" . GetNativeVectorInnerType($arrayOrSequenceType) . ">(exec, $value)";
3558    }
3559
3560    if ($codeGenerator->IsEnumType($type)) {
3561        return "$value.isEmpty() ? String() : $value.toString(exec)->value(exec)";
3562    }
3563
3564    # Default, assume autogenerated type conversion routines
3565    AddToImplIncludes("JS$type.h", $conditional);
3566    return "to$type($value)";
3567}
3568
3569sub NativeToJSValue
3570{
3571    my $signature = shift;
3572    my $inFunctionCall = shift;
3573    my $interfaceName = shift;
3574    my $value = shift;
3575    my $thisValue = shift;
3576
3577    my $conditional = $signature->extendedAttributes->{"Conditional"};
3578    my $type = $signature->type;
3579
3580    return "jsBoolean($value)" if $type eq "boolean";
3581
3582    # Need to check Date type before IsPrimitiveType().
3583    if ($type eq "Date") {
3584        return "jsDateOrNull(exec, $value)";
3585    }
3586
3587    if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) {
3588        $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g;
3589        return "jsNumber(std::max(0, " . $value . "))";
3590    }
3591
3592    if ($codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp") {
3593        return "jsNumber($value)";
3594    }
3595
3596    if ($codeGenerator->IsEnumType($type)) {
3597        AddToImplIncludes("<runtime/JSString.h>", $conditional);
3598        return "jsStringWithCache(exec, $value)";
3599    }
3600
3601    if ($codeGenerator->IsStringType($type)) {
3602        AddToImplIncludes("KURL.h", $conditional);
3603        my $conv = $signature->extendedAttributes->{"TreatReturnedNullStringAs"};
3604        if (defined $conv) {
3605            return "jsStringOrNull(exec, $value)" if $conv eq "Null";
3606            return "jsStringOrUndefined(exec, $value)" if $conv eq "Undefined";
3607
3608            die "Unknown value for TreatReturnedNullStringAs extended attribute";
3609        }
3610        AddToImplIncludes("<runtime/JSString.h>", $conditional);
3611        return "jsStringWithCache(exec, $value)";
3612    }
3613
3614    my $globalObject;
3615    if ($thisValue) {
3616        $globalObject = "$thisValue->globalObject()";
3617    }
3618
3619    if ($type eq "CSSStyleDeclaration") {
3620        AddToImplIncludes("StylePropertySet.h", $conditional);
3621    }
3622
3623    if ($type eq "NodeList") {
3624        AddToImplIncludes("NameNodeList.h", $conditional);
3625    }
3626
3627    my $arrayType = $codeGenerator->GetArrayType($type);
3628    my $sequenceType = $codeGenerator->GetSequenceType($type);
3629    my $arrayOrSequenceType = $arrayType || $sequenceType;
3630
3631    if ($arrayOrSequenceType) {
3632        if ($arrayType eq "DOMString") {
3633            AddToImplIncludes("JSDOMStringList.h", $conditional);
3634            AddToImplIncludes("DOMStringList.h", $conditional);
3635
3636        } elsif ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) {
3637            AddToImplIncludes("JS${arrayOrSequenceType}.h", $conditional);
3638            AddToImplIncludes("${arrayOrSequenceType}.h", $conditional);
3639        }
3640        AddToImplIncludes("<runtime/JSArray.h>", $conditional);
3641
3642        return "jsArray(exec, $thisValue->globalObject(), $value)";
3643    }
3644
3645    if ($type eq "any") {
3646        if ($interfaceName eq "Document") {
3647            AddToImplIncludes("JSCanvasRenderingContext2D.h", $conditional);
3648        } else {
3649            return "($value.hasNoValue() ? jsNull() : $value.jsValue())";
3650        }
3651    } elsif ($type =~ /SVGPathSeg/) {
3652        AddToImplIncludes("JS$type.h", $conditional);
3653        my $joinedName = $type;
3654        $joinedName =~ s/Abs|Rel//;
3655        AddToImplIncludes("$joinedName.h", $conditional);
3656    } elsif ($type eq "SerializedScriptValue" or $type eq "any") {
3657        AddToImplIncludes("SerializedScriptValue.h", $conditional);
3658        return "$value ? $value->deserialize(exec, castedThis->globalObject(), 0) : jsNull()";
3659    } else {
3660        # Default, include header with same name.
3661        AddToImplIncludes("JS$type.h", $conditional);
3662        if ($codeGenerator->IsTypedArrayType($type)) {
3663            AddToImplIncludes("<wtf/$type.h>", $conditional) if not $codeGenerator->SkipIncludeHeader($type);
3664        } else {
3665            AddToImplIncludes("$type.h", $conditional) if not $codeGenerator->SkipIncludeHeader($type);
3666        }
3667    }
3668
3669    return $value if $codeGenerator->IsSVGAnimatedType($type);
3670
3671    if ($signature->extendedAttributes->{"ReturnNewObject"}) {
3672        return "toJSNewlyCreated(exec, $globalObject, WTF::getPtr($value))";
3673    }
3674
3675    if ($codeGenerator->IsSVGAnimatedType($interfaceName) or $interfaceName eq "SVGViewSpec") {
3676        # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked.
3677        $value = "static_cast<" . GetNativeType($type) . ">($value)";
3678    } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($type) and not $interfaceName =~ /List$/) {
3679        my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
3680        if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($type) and $inFunctionCall eq 0 and not defined $signature->extendedAttributes->{"Immutable"}) {
3681            my $getter = $value;
3682            $getter =~ s/impl\.//;
3683            $getter =~ s/impl->//;
3684            $getter =~ s/\(\)//;
3685            my $updateMethod = "&${interfaceName}::update" . $codeGenerator->WK_ucfirst($getter);
3686
3687            my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName);
3688            if ($selfIsTearOffType) {
3689                AddToImplIncludes("SVGMatrixTearOff.h", $conditional);
3690                # FIXME: Blink: Don't create a new one everytime we access the matrix property. This means, e.g, === won't work.
3691                $value = "SVGMatrixTearOff::create(castedThis->impl(), $value)";
3692
3693                if ($value =~ /matrix/ and $interfaceName eq "SVGTransform") {
3694                    # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform
3695                    # and a svgMatrix() method returning a SVGMatrix, used for the bindings.
3696                    $value =~ s/matrix/svgMatrix/;
3697                }
3698            } else {
3699                AddToImplIncludes("SVGStaticPropertyTearOff.h", $conditional);
3700                $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$interfaceName, /;
3701                $value = "${tearOffType}::create(impl, $value, $updateMethod)";
3702            }
3703        } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) {
3704            $value = "${tearOffType}::create(impl, $value)";
3705        } elsif (not $tearOffType =~ /SVG(Point|PathSeg)List/) {
3706            $value = "${tearOffType}::create($value)";
3707        }
3708    }
3709    if ($globalObject) {
3710        return "toJS(exec, $globalObject, WTF::getPtr($value))";
3711    } else {
3712        return "toJS(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), WTF::getPtr($value))";
3713    }
3714}
3715
3716sub ceilingToPowerOf2
3717{
3718    my ($size) = @_;
3719
3720    my $powerOf2 = 1;
3721    while ($size > $powerOf2) {
3722        $powerOf2 <<= 1;
3723    }
3724
3725    return $powerOf2;
3726}
3727
3728# Internal Helper
3729sub GenerateHashTable
3730{
3731    my $object = shift;
3732
3733    my $name = shift;
3734    my $size = shift;
3735    my $keys = shift;
3736    my $specials = shift;
3737    my $value1 = shift;
3738    my $value2 = shift;
3739    my $conditionals = shift;
3740
3741    # Generate size data for compact' size hash table
3742
3743    my @table = ();
3744    my @links = ();
3745
3746    my $compactSize = ceilingToPowerOf2($size * 2);
3747
3748    my $maxDepth = 0;
3749    my $collisions = 0;
3750    my $numEntries = $compactSize;
3751
3752    my $i = 0;
3753    foreach (@{$keys}) {
3754        my $depth = 0;
3755        my $h = Hasher::GenerateHashValue($_) % $numEntries;
3756
3757        while (defined($table[$h])) {
3758            if (defined($links[$h])) {
3759                $h = $links[$h];
3760                $depth++;
3761            } else {
3762                $collisions++;
3763                $links[$h] = $compactSize;
3764                $h = $compactSize;
3765                $compactSize++;
3766            }
3767        }
3768
3769        $table[$h] = $i;
3770
3771        $i++;
3772        $maxDepth = $depth if ($depth > $maxDepth);
3773    }
3774
3775    # Start outputing the hashtables
3776    my $nameEntries = "${name}Values";
3777    $nameEntries =~ s/:/_/g;
3778
3779    if (($name =~ /Prototype/) or ($name =~ /Constructor/)) {
3780        my $type = $name;
3781        my $implClass;
3782
3783        if ($name =~ /Prototype/) {
3784            $type =~ s/Prototype.*//;
3785            $implClass = $type; $implClass =~ s/Wrapper$//;
3786            push(@implContent, "/* Hash table for prototype */\n");
3787        } else {
3788            $type =~ s/Constructor.*//;
3789            $implClass = $type; $implClass =~ s/Constructor$//;
3790            push(@implContent, "/* Hash table for constructor */\n");
3791        }
3792    } else {
3793        push(@implContent, "/* Hash table */\n");
3794    }
3795
3796    # Dump the hash table
3797    push(@implContent, "\nstatic const HashTableValue $nameEntries\[\] =\n\{\n");
3798    $i = 0;
3799    foreach my $key (@{$keys}) {
3800        my $conditional;
3801        my $targetType;
3802
3803        if ($conditionals) {
3804            $conditional = $conditionals->{$key};
3805        }
3806        if ($conditional) {
3807            my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
3808            push(@implContent, "#if ${conditionalString}\n");
3809        }
3810
3811        if ("@$specials[$i]" =~ m/Function/) {
3812            $targetType = "static_cast<NativeFunction>";
3813        } else {
3814            $targetType = "static_cast<PropertySlot::GetValueFunc>";
3815        }
3816        push(@implContent, "    { \"$key\", @$specials[$i], (intptr_t)" . $targetType . "(@$value1[$i]), (intptr_t)@$value2[$i], NoIntrinsic },\n");
3817        push(@implContent, "#endif\n") if $conditional;
3818        ++$i;
3819    }
3820    push(@implContent, "    { 0, 0, 0, 0, NoIntrinsic }\n");
3821    push(@implContent, "};\n\n");
3822    my $compactSizeMask = $numEntries - 1;
3823    push(@implContent, "static const HashTable $name = { $compactSize, $compactSizeMask, $nameEntries, 0 };\n");
3824}
3825
3826sub WriteData
3827{
3828    my $object = shift;
3829    my $interface = shift;
3830    my $outputDir = shift;
3831
3832    my $name = $interface->name;
3833    my $prefix = FileNamePrefix;
3834    my $headerFileName = "$outputDir/$prefix$name.h";
3835    my $implFileName = "$outputDir/$prefix$name.cpp";
3836    my $depsFileName = "$outputDir/$prefix$name.dep";
3837
3838    # Update a .cpp file if the contents are changed.
3839    my $contents = join "", @implContentHeader;
3840
3841    my @includes = ();
3842    my %implIncludeConditions = ();
3843    foreach my $include (keys %implIncludes) {
3844        my $condition = $implIncludes{$include};
3845        my $checkType = $include;
3846        $checkType =~ s/\.h//;
3847        next if $codeGenerator->IsSVGAnimatedType($checkType);
3848
3849        $include = "\"$include\"" unless $include =~ /^["<]/; # "
3850
3851        if ($condition eq 1) {
3852            push @includes, $include;
3853        } else {
3854            push @{$implIncludeConditions{$condition}}, $include;
3855        }
3856    }
3857    foreach my $include (sort @includes) {
3858        $contents .= "#include $include\n";
3859    }
3860    foreach my $condition (sort keys %implIncludeConditions) {
3861        $contents .= "\n#if " . $codeGenerator->GenerateConditionalStringFromAttributeValue($condition) . "\n";
3862        foreach my $include (sort @{$implIncludeConditions{$condition}}) {
3863            $contents .= "#include $include\n";
3864        }
3865        $contents .= "#endif\n";
3866    }
3867
3868    $contents .= join "", @implContent;
3869    $codeGenerator->UpdateFile($implFileName, $contents);
3870
3871    @implContentHeader = ();
3872    @implContent = ();
3873    %implIncludes = ();
3874
3875    # Update a .h file if the contents are changed.
3876    $contents = join "", @headerContentHeader;
3877
3878    @includes = ();
3879    foreach my $include (keys %headerIncludes) {
3880        $include = "\"$include\"" unless $include =~ /^["<]/; # "
3881        push @includes, $include;
3882    }
3883    foreach my $include (sort @includes) {
3884        # "JSClassName.h" is already included right after config.h.
3885        next if $include eq "\"$prefix$name.h\"";
3886        $contents .= "#include $include\n";
3887    }
3888
3889    $contents .= join "", @headerContent;
3890
3891    @includes = ();
3892    foreach my $include (keys %headerTrailingIncludes) {
3893        $include = "\"$include\"" unless $include =~ /^["<]/; # "
3894        push @includes, $include;
3895    }
3896    foreach my $include (sort @includes) {
3897        $contents .= "#include $include\n";
3898    }
3899    $codeGenerator->UpdateFile($headerFileName, $contents);
3900
3901    @headerContentHeader = ();
3902    @headerContent = ();
3903    %headerIncludes = ();
3904    %headerTrailingIncludes = ();
3905
3906    if (@depsContent) {
3907        # Update a .dep file if the contents are changed.
3908        $contents = join "", @depsContent;
3909        $codeGenerator->UpdateFile($depsFileName, $contents);
3910
3911        @depsContent = ();
3912    }
3913}
3914
3915sub GenerateConstructorDeclaration
3916{
3917    my $outputArray = shift;
3918    my $className = shift;
3919    my $interface = shift;
3920    my $interfaceName = shift;
3921
3922    my $constructorClassName = "${className}Constructor";
3923
3924    push(@$outputArray, "class ${constructorClassName} : public DOMConstructorObject {\n");
3925    push(@$outputArray, "private:\n");
3926    push(@$outputArray, "    ${constructorClassName}(JSC::Structure*, JSDOMGlobalObject*);\n");
3927    push(@$outputArray, "    void finishCreation(JSC::ExecState*, JSDOMGlobalObject*);\n\n");
3928
3929    push(@$outputArray, "public:\n");
3930    push(@$outputArray, "    typedef DOMConstructorObject Base;\n");
3931    push(@$outputArray, "    static $constructorClassName* create(JSC::ExecState* exec, JSC::Structure* structure, JSDOMGlobalObject* globalObject)\n");
3932    push(@$outputArray, "    {\n");
3933    push(@$outputArray, "        $constructorClassName* ptr = new (NotNull, JSC::allocateCell<$constructorClassName>(*exec->heap())) $constructorClassName(structure, globalObject);\n");
3934    push(@$outputArray, "        ptr->finishCreation(exec, globalObject);\n");
3935    push(@$outputArray, "        return ptr;\n");
3936    push(@$outputArray, "    }\n\n");
3937
3938    push(@$outputArray, "    static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
3939    push(@$outputArray, "    static bool getOwnPropertyDescriptor(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&);\n");
3940    push(@$outputArray, "    static const JSC::ClassInfo s_info;\n");
3941
3942    push(@$outputArray, "    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
3943    push(@$outputArray, "    {\n");
3944    push(@$outputArray, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);\n");
3945    push(@$outputArray, "    }\n");
3946
3947    push(@$outputArray, "protected:\n");
3948    push(@$outputArray, "    static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | JSC::ImplementsHasInstance | DOMConstructorObject::StructureFlags;\n");
3949
3950    if (IsConstructable($interface) && !$interface->extendedAttributes->{"NamedConstructor"}) {
3951        push(@$outputArray, "    static JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState*);\n");
3952
3953        if (!HasCustomConstructor($interface)) {
3954            my @constructors = @{$interface->constructors};
3955            if (@constructors > 1) {
3956                foreach my $constructor (@constructors) {
3957                    my $overloadedIndex = "" . $constructor->{overloadedIndex};
3958                    push(@$outputArray, "    static JSC::EncodedJSValue JSC_HOST_CALL construct${className}${overloadedIndex}(JSC::ExecState*);\n");
3959                }
3960            }
3961        }
3962
3963        my $conditionalString = $codeGenerator->GenerateConstructorConditionalString($interface);
3964        push(@$outputArray, "#if $conditionalString\n") if $conditionalString;
3965        push(@$outputArray, "    static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&);\n");
3966        push(@$outputArray, "#endif // $conditionalString\n") if $conditionalString;
3967    }
3968    push(@$outputArray, "};\n\n");
3969
3970    if ($codeGenerator->IsConstructorTemplate($interface, "Event")) {
3971        push(@$outputArray, "bool fill${interfaceName}Init(${interfaceName}Init&, JSDictionary&);\n\n");
3972    }
3973
3974    if ($interface->extendedAttributes->{"NamedConstructor"}) {
3975        push(@$outputArray, <<END);
3976class JS${interfaceName}NamedConstructor : public DOMConstructorWithDocument {
3977public:
3978    typedef DOMConstructorWithDocument Base;
3979
3980    static JS${interfaceName}NamedConstructor* create(JSC::ExecState* exec, JSC::Structure* structure, JSDOMGlobalObject* globalObject)
3981    {
3982        JS${interfaceName}NamedConstructor* constructor = new (NotNull, JSC::allocateCell<JS${interfaceName}NamedConstructor>(*exec->heap())) JS${interfaceName}NamedConstructor(structure, globalObject);
3983        constructor->finishCreation(exec, globalObject);
3984        return constructor;
3985    }
3986
3987    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
3988    {
3989        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);
3990    }
3991
3992    static const JSC::ClassInfo s_info;
3993
3994private:
3995    JS${interfaceName}NamedConstructor(JSC::Structure*, JSDOMGlobalObject*);
3996    static JSC::EncodedJSValue JSC_HOST_CALL constructJS${interfaceName}(JSC::ExecState*);
3997    static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&);
3998    void finishCreation(JSC::ExecState*, JSDOMGlobalObject*);
3999};
4000
4001END
4002    }
4003}
4004
4005sub GenerateConstructorDefinitions
4006{
4007    my $outputArray = shift;
4008    my $className = shift;
4009    my $protoClassName = shift;
4010    my $interfaceName = shift;
4011    my $visibleInterfaceName = shift;
4012    my $interface = shift;
4013    my $generatingNamedConstructor = shift;
4014
4015    if (IsConstructable($interface)) {
4016        my @constructors = @{$interface->constructors};
4017        if (@constructors > 1) {
4018            foreach my $constructor (@constructors) {
4019                GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $constructor);
4020            }
4021            GenerateOverloadedConstructorDefinition($outputArray, $className, $interface);
4022        } elsif (@constructors == 1) {
4023            GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $constructors[0]);
4024        } else {
4025            GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor);
4026        }
4027    }
4028
4029    GenerateConstructorHelperMethods($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor);
4030}
4031
4032sub GenerateOverloadedConstructorDefinition
4033{
4034    my $outputArray = shift;
4035    my $className = shift;
4036    my $interface = shift;
4037
4038    my $functionName = "${className}Constructor::construct${className}";
4039    push(@$outputArray, <<END);
4040EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)
4041{
4042    size_t argsCount = exec->argumentCount();
4043END
4044
4045    my %fetchedArguments = ();
4046    my $leastNumMandatoryParams = 255;
4047
4048    my @constructors = @{$interface->constructors};
4049    foreach my $overload (@constructors) {
4050        my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload);
4051        $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams);
4052
4053        foreach my $parameterIndex (@neededArguments) {
4054            next if exists $fetchedArguments{$parameterIndex};
4055            push(@$outputArray, "    JSValue arg$parameterIndex(exec->argument($parameterIndex));\n");
4056            $fetchedArguments{$parameterIndex} = 1;
4057        }
4058
4059        push(@$outputArray, "    if ($parametersCheck)\n");
4060        push(@$outputArray, "        return ${functionName}$overload->{overloadedIndex}(exec);\n");
4061    }
4062
4063    if ($leastNumMandatoryParams >= 1) {
4064        push(@$outputArray, "    if (argsCount < $leastNumMandatoryParams)\n");
4065        push(@$outputArray, "        return throwVMError(exec, createNotEnoughArgumentsError(exec));\n");
4066    }
4067    push(@$outputArray, <<END);
4068    return throwVMTypeError(exec);
4069}
4070
4071END
4072}
4073
4074sub GenerateConstructorDefinition
4075{
4076    my $outputArray = shift;
4077    my $className = shift;
4078    my $protoClassName = shift;
4079    my $interfaceName = shift;
4080    my $visibleInterfaceName = shift;
4081    my $interface = shift;
4082    my $generatingNamedConstructor = shift;
4083    my $function = shift;
4084
4085    my $constructorClassName = $generatingNamedConstructor ? "${className}NamedConstructor" : "${className}Constructor";
4086
4087    if (IsConstructable($interface)) {
4088        if ($codeGenerator->IsConstructorTemplate($interface, "Event")) {
4089            $implIncludes{"JSDictionary.h"} = 1;
4090            $implIncludes{"<runtime/Error.h>"} = 1;
4091
4092            push(@$outputArray, <<END);
4093EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}(ExecState* exec)
4094{
4095    ${constructorClassName}* jsConstructor = jsCast<${constructorClassName}*>(exec->callee());
4096
4097    ScriptExecutionContext* executionContext = jsConstructor->scriptExecutionContext();
4098    if (!executionContext)
4099        return throwVMError(exec, createReferenceError(exec, "Constructor associated execution context is unavailable"));
4100
4101    AtomicString eventType = exec->argument(0).toString(exec)->value(exec);
4102    if (exec->hadException())
4103        return JSValue::encode(jsUndefined());
4104
4105    ${interfaceName}Init eventInit;
4106
4107    JSValue initializerValue = exec->argument(1);
4108    if (!initializerValue.isUndefinedOrNull()) {
4109        // Given the above test, this will always yield an object.
4110        JSObject* initializerObject = initializerValue.toObject(exec);
4111
4112        // Create the dictionary wrapper from the initializer object.
4113        JSDictionary dictionary(exec, initializerObject);
4114
4115        // Attempt to fill in the EventInit.
4116        if (!fill${interfaceName}Init(eventInit, dictionary))
4117            return JSValue::encode(jsUndefined());
4118    }
4119
4120    RefPtr<${interfaceName}> event = ${interfaceName}::create(eventType, eventInit);
4121    return JSValue::encode(toJS(exec, jsConstructor->globalObject(), event.get()));
4122}
4123
4124bool fill${interfaceName}Init(${interfaceName}Init& eventInit, JSDictionary& dictionary)
4125{
4126END
4127
4128            foreach my $interfaceBase (@{$interface->parents}) {
4129                push(@implContent, <<END);
4130    if (!fill${interfaceBase}Init(eventInit, dictionary))
4131        return false;
4132
4133END
4134            }
4135
4136            for (my $index = 0; $index < @{$interface->attributes}; $index++) {
4137                my $attribute = @{$interface->attributes}[$index];
4138                if ($attribute->signature->extendedAttributes->{"InitializedByEventConstructor"}) {
4139                    my $attributeName = $attribute->signature->name;
4140                    push(@implContent, <<END);
4141    if (!dictionary.tryGetProperty("${attributeName}", eventInit.${attributeName}))
4142        return false;
4143END
4144                }
4145            }
4146
4147            push(@$outputArray, <<END);
4148    return true;
4149}
4150
4151END
4152        } elsif ($codeGenerator->IsConstructorTemplate($interface, "TypedArray")) {
4153            $implIncludes{"JSArrayBufferViewHelper.h"} = 1;
4154            my $viewType = $interface->extendedAttributes->{"TypedArray"};
4155            push(@$outputArray, "EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}(ExecState* exec)\n");
4156            push(@$outputArray, "{\n");
4157            push(@$outputArray, "    ${constructorClassName}* jsConstructor = jsCast<${constructorClassName}*>(exec->callee());\n");
4158            push(@$outputArray, "    RefPtr<$interfaceName> array = constructArrayBufferView<$interfaceName, $viewType>(exec);\n");
4159            push(@$outputArray, "    if (!array.get())\n");
4160            push(@$outputArray, "        // Exception has already been thrown.\n");
4161            push(@$outputArray, "        return JSValue::encode(JSValue());\n");
4162            push(@$outputArray, "    return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), array.get())));\n");
4163            push(@$outputArray, "}\n\n");
4164
4165            push(@$outputArray, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, ${interfaceName}* object)\n");
4166            push(@$outputArray, "{\n");
4167            push(@$outputArray, "    return toJSArrayBufferView<${className}>(exec, globalObject, object);\n");
4168            push(@$outputArray, "}\n\n");
4169
4170            if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
4171                push(@$outputArray, "void ${className}::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value)\n");
4172                push(@$outputArray, "{\n");
4173                push(@$outputArray, "    impl()->set(index, value.toNumber(exec));\n");
4174                push(@$outputArray, "}\n\n");
4175            }
4176        } elsif (!HasCustomConstructor($interface) && (!$interface->extendedAttributes->{"NamedConstructor"} || $generatingNamedConstructor)) {
4177            my $overloadedIndexString = "";
4178            if ($function->{overloadedIndex} && $function->{overloadedIndex} > 0) {
4179                $overloadedIndexString .= $function->{overloadedIndex};
4180            }
4181
4182            push(@$outputArray, "EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}${overloadedIndexString}(ExecState* exec)\n");
4183            push(@$outputArray, "{\n");
4184            push(@$outputArray, "    ${constructorClassName}* castedThis = jsCast<${constructorClassName}*>(exec->callee());\n");
4185
4186            my @constructorArgList;
4187
4188            $implIncludes{"<runtime/Error.h>"} = 1;
4189
4190            GenerateArgumentsCountCheck($outputArray, $function, $interface);
4191
4192            if ($function->signature->extendedAttributes->{"RaisesException"} || $interface->extendedAttributes->{"ConstructorRaisesException"}) {
4193                $implIncludes{"ExceptionCode.h"} = 1;
4194                push(@$outputArray, "    ExceptionCode ec = 0;\n");
4195            }
4196
4197            # FIXME: For now, we do not support SVG constructors.
4198            # FIXME: Currently [Constructor(...)] does not yet support optional arguments without [Default=...]
4199            my $numParameters = @{$function->parameters};
4200            my ($dummy, $paramIndex) = GenerateParametersCheck($outputArray, $function, $interface, $numParameters, $interfaceName, "constructorCallback", undef, undef, undef);
4201
4202            if ($codeGenerator->ExtendedAttributeContains($interface->extendedAttributes->{"ConstructorCallWith"}, "ScriptExecutionContext")) {
4203                push(@constructorArgList, "context");
4204                push(@$outputArray, "    ScriptExecutionContext* context = castedThis->scriptExecutionContext();\n");
4205                push(@$outputArray, "    if (!context)\n");
4206                push(@$outputArray, "        return throwVMError(exec, createReferenceError(exec, \"${interfaceName} constructor associated document is unavailable\"));\n");
4207            }
4208            if ($generatingNamedConstructor) {
4209                push(@constructorArgList, "castedThis->document()");
4210            }
4211
4212            my $index = 0;
4213            foreach my $parameter (@{$function->parameters}) {
4214                last if $index eq $paramIndex;
4215                push(@constructorArgList, $parameter->name);
4216                $index++;
4217            }
4218
4219            if ($interface->extendedAttributes->{"ConstructorRaisesException"}) {
4220                push(@constructorArgList, "ec");
4221            }
4222            my $constructorArg = join(", ", @constructorArgList);
4223            if ($generatingNamedConstructor) {
4224                push(@$outputArray, "    RefPtr<${interfaceName}> object = ${interfaceName}::createForJSConstructor(${constructorArg});\n");
4225            } else {
4226                push(@$outputArray, "    RefPtr<${interfaceName}> object = ${interfaceName}::create(${constructorArg});\n");
4227            }
4228
4229            if ($interface->extendedAttributes->{"ConstructorRaisesException"}) {
4230                push(@$outputArray, "    if (ec) {\n");
4231                push(@$outputArray, "        setDOMException(exec, ec);\n");
4232                push(@$outputArray, "        return JSValue::encode(JSValue());\n");
4233                push(@$outputArray, "    }\n");
4234            }
4235
4236            push(@$outputArray, "    return JSValue::encode(asObject(toJS(exec, castedThis->globalObject(), object.get())));\n");
4237            push(@$outputArray, "}\n\n");
4238        }
4239    }
4240}
4241
4242sub GenerateConstructorHelperMethods
4243{
4244    my $outputArray = shift;
4245    my $className = shift;
4246    my $protoClassName = shift;
4247    my $interfaceName = shift;
4248    my $visibleInterfaceName = shift;
4249    my $interface = shift;
4250    my $generatingNamedConstructor = shift;
4251
4252    my $constructorClassName = $generatingNamedConstructor ? "${className}NamedConstructor" : "${className}Constructor";
4253    my $leastConstructorLength = 0;
4254    if ($codeGenerator->IsConstructorTemplate($interface, "Event") || $codeGenerator->IsConstructorTemplate($interface, "TypedArray")) {
4255        $leastConstructorLength = 1;
4256    } elsif ($interface->extendedAttributes->{"Constructor"} || $interface->extendedAttributes->{"CustomConstructor"}) {
4257        my @constructors = @{$interface->constructors};
4258        my @customConstructors = @{$interface->customConstructors};
4259        $leastConstructorLength = 255;
4260        foreach my $constructor (@constructors, @customConstructors) {
4261            my $constructorLength = GetFunctionLength($constructor);
4262            $leastConstructorLength = $constructorLength if ($constructorLength < $leastConstructorLength);
4263        }
4264    } else {
4265        $leastConstructorLength = 0;
4266    }
4267
4268    if ($generatingNamedConstructor) {
4269        push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, 0, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
4270        push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n");
4271        push(@$outputArray, "    : DOMConstructorWithDocument(structure, globalObject)\n");
4272        push(@$outputArray, "{\n");
4273        push(@$outputArray, "}\n\n");
4274    } else {
4275        if ($interface->extendedAttributes->{"JSNoStaticTables"}) {
4276            push(@$outputArray, "static const HashTable* get${constructorClassName}Table(ExecState* exec)\n");
4277            push(@$outputArray, "{\n");
4278            push(@$outputArray, "    return getHashTableForGlobalData(exec->vm(), &${constructorClassName}Table);\n");
4279            push(@$outputArray, "}\n\n");
4280            push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, 0, get${constructorClassName}Table, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
4281        } else {
4282            push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, &${constructorClassName}Table, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
4283        }
4284
4285        push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n");
4286        push(@$outputArray, "    : DOMConstructorObject(structure, globalObject)\n");
4287        push(@$outputArray, "{\n}\n\n");
4288    }
4289
4290    push(@$outputArray, "void ${constructorClassName}::finishCreation(ExecState* exec, JSDOMGlobalObject* globalObject)\n");
4291    push(@$outputArray, "{\n");
4292    if ($interfaceName eq "DOMWindow") {
4293        push(@$outputArray, "    Base::finishCreation(exec->vm());\n");
4294        push(@$outputArray, "    ASSERT(inherits(&s_info));\n");
4295        push(@$outputArray, "    putDirect(exec->vm(), exec->propertyNames().prototype, globalObject->prototype(), DontDelete | ReadOnly);\n");
4296    } elsif ($generatingNamedConstructor) {
4297        push(@$outputArray, "    Base::finishCreation(globalObject);\n");
4298        push(@$outputArray, "    ASSERT(inherits(&s_info));\n");
4299        push(@$outputArray, "    putDirect(exec->vm(), exec->propertyNames().prototype, ${className}Prototype::self(exec, globalObject), None);\n");
4300    } else {
4301        push(@$outputArray, "    Base::finishCreation(exec->vm());\n");
4302        push(@$outputArray, "    ASSERT(inherits(&s_info));\n");
4303        push(@$outputArray, "    putDirect(exec->vm(), exec->propertyNames().prototype, ${protoClassName}::self(exec, globalObject), DontDelete | ReadOnly);\n");
4304    }
4305    push(@$outputArray, "    putDirect(exec->vm(), exec->propertyNames().length, jsNumber(${leastConstructorLength}), ReadOnly | DontDelete | DontEnum);\n") if defined $leastConstructorLength;
4306    push(@$outputArray, "}\n\n");
4307
4308    if (!$generatingNamedConstructor) {
4309        my $hasStaticFunctions = 0;
4310        foreach my $function (@{$interface->functions}) {
4311            if ($function->isStatic) {
4312                $hasStaticFunctions = 1;
4313                last;
4314            }
4315        }
4316
4317        my $kind = $hasStaticFunctions ? "Property" : "Value";
4318
4319        push(@$outputArray, "bool ${constructorClassName}::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
4320        push(@$outputArray, "{\n");
4321        push(@$outputArray, "    return getStatic${kind}Slot<${constructorClassName}, JSDOMWrapper>(exec, " . constructorHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $constructorClassName) . ", jsCast<${constructorClassName}*>(cell), propertyName, slot);\n");
4322        push(@$outputArray, "}\n\n");
4323
4324        push(@$outputArray, "bool ${constructorClassName}::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)\n");
4325        push(@$outputArray, "{\n");
4326        push(@$outputArray, "    return getStatic${kind}Descriptor<${constructorClassName}, JSDOMWrapper>(exec, " . constructorHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $constructorClassName) . ", jsCast<${constructorClassName}*>(object), propertyName, descriptor);\n");
4327        push(@$outputArray, "}\n\n");
4328    }
4329
4330    if (IsConstructable($interface)) {
4331        if (!$interface->extendedAttributes->{"NamedConstructor"} || $generatingNamedConstructor) {
4332            my $conditionalString = $codeGenerator->GenerateConstructorConditionalString($interface);
4333            push(@$outputArray, "#if $conditionalString\n") if $conditionalString;
4334            push(@$outputArray, "ConstructType ${constructorClassName}::getConstructData(JSCell*, ConstructData& constructData)\n");
4335            push(@$outputArray, "{\n");
4336            push(@$outputArray, "    constructData.native.function = construct${className};\n");
4337            push(@$outputArray, "    return ConstructTypeHost;\n");
4338            push(@$outputArray, "}\n");
4339            push(@$outputArray, "#endif // $conditionalString\n") if $conditionalString;
4340            push(@$outputArray, "\n");
4341        }
4342    }
4343}
4344
4345sub HasCustomConstructor
4346{
4347    my $interface = shift;
4348
4349    return $interface->extendedAttributes->{"CustomConstructor"};
4350}
4351
4352sub HasCustomGetter
4353{
4354    my $attrExt = shift;
4355    return $attrExt->{"Custom"} || $attrExt->{"CustomGetter"} ;
4356}
4357
4358sub HasCustomSetter
4359{
4360    my $attrExt = shift;
4361    return $attrExt->{"Custom"} || $attrExt->{"CustomSetter"};
4362}
4363
4364sub HasCustomMethod
4365{
4366    my $attrExt = shift;
4367    return $attrExt->{"Custom"};
4368}
4369
4370sub IsConstructable
4371{
4372    my $interface = shift;
4373
4374    return HasCustomConstructor($interface) || $interface->extendedAttributes->{"Constructor"} || $interface->extendedAttributes->{"NamedConstructor"} || $interface->extendedAttributes->{"ConstructorTemplate"};
4375}
4376
43771;
4378