d31b0436121c79c6fd0845ee1361b3ec4b36c35a
[WebKit-https.git] / Source / WebCore / bindings / scripts / CodeGeneratorV8.pm
1 # Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
2 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
3 # Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
4 # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
5 # Copyright (C) 2006 Apple Computer, Inc.
6 # Copyright (C) 2007, 2008, 2009, 2012 Google Inc.
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 #
11 # This library is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU Library General Public
13 # License as published by the Free Software Foundation; either
14 # version 2 of the License, or (at your option) any later version.
15 #
16 # This library is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 # Library General Public License for more details.
20 #
21 # You should have received a copy of the GNU Library General Public License
22 # along with this library; see the file COPYING.LIB.  If not, write to
23 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 # Boston, MA 02111-1307, USA.
25 #
26
27 package CodeGeneratorV8;
28
29 use strict;
30
31 use Digest::MD5;
32
33 use constant FileNamePrefix => "V8";
34
35 my $codeGenerator;
36
37 my $module = "";
38 my $outputDir = "";
39 my $outputHeadersDir = "";
40
41 my @headerContent = ();
42 my @implContentHeader = ();
43 my @implFixedHeader = ();
44 my @implContent = ();
45 my @implContentDecls = ();
46 my %implIncludes = ();
47 my %headerIncludes = ();
48
49 my @allParents = ();
50
51 # Default .h template
52 my $headerTemplate = << "EOF";
53 /*
54     This file is part of the WebKit open source project.
55     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
56
57     This library is free software; you can redistribute it and/or
58     modify it under the terms of the GNU Library General Public
59     License as published by the Free Software Foundation; either
60     version 2 of the License, or (at your option) any later version.
61
62     This library is distributed in the hope that it will be useful,
63     but WITHOUT ANY WARRANTY; without even the implied warranty of
64     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
65     Library General Public License for more details.
66
67     You should have received a copy of the GNU Library General Public License
68     along with this library; see the file COPYING.LIB.  If not, write to
69     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
70     Boston, MA 02111-1307, USA.
71 */
72 EOF
73
74 # Default constructor
75 sub new
76 {
77     my $object = shift;
78     my $reference = { };
79
80     $codeGenerator = shift;
81     $outputDir = shift;
82     $outputHeadersDir = shift;
83
84     bless($reference, $object);
85     return $reference;
86 }
87
88 # Params: 'domClass' struct
89 sub GenerateInterface
90 {
91     my $object = shift;
92     my $dataNode = shift;
93     my $defines = shift;
94
95     # Start actual generation
96     if ($dataNode->extendedAttributes->{"Callback"}) {
97         $object->GenerateCallbackHeader($dataNode);
98         $object->GenerateCallbackImplementation($dataNode);
99     } else {
100         $object->GenerateHeader($dataNode);
101         $object->GenerateImplementation($dataNode);
102     }
103
104     $object->WriteData($dataNode);
105 }
106
107 # Params: 'idlDocument' struct
108 sub GenerateModule
109 {
110     my $object = shift;
111     my $dataNode = shift;
112
113     $module = $dataNode->module;
114 }
115
116 sub AddToImplIncludes
117 {
118     my $header = shift;
119     my $conditional = shift;
120
121     if (not $conditional) {
122         $implIncludes{$header} = 1;
123     } elsif (not exists($implIncludes{$header})) {
124         $implIncludes{$header} = $conditional;
125     } else {
126         my $oldValue = $implIncludes{$header};
127         if ($oldValue ne 1) {
128             my %newValue = ();
129             $newValue{$conditional} = 1;
130             foreach my $condition (split(/\|/, $oldValue)) {
131                 $newValue{$condition} = 1;
132             }
133             $implIncludes{$header} = join("|", sort keys %newValue);
134         }
135     }
136 }
137
138 sub AddIncludesForType
139 {
140     my $type = $codeGenerator->StripModule(shift);
141
142     # When we're finished with the one-file-per-class
143     # reorganization, we won't need these special cases.
144     if (IsTypedArrayType($type)) {
145         AddToImplIncludes("wtf/${type}.h");
146     }
147     if (!$codeGenerator->IsPrimitiveType($type) and !$codeGenerator->IsStringType($type) and !$codeGenerator->SkipIncludeHeader($type) and $type ne "Date") {
148         # default, include the same named file
149         AddToImplIncludes(GetV8HeaderName(${type}));
150
151         if ($type =~ /SVGPathSeg/) {
152             my $joinedName = $type;
153             $joinedName =~ s/Abs|Rel//;
154             AddToImplIncludes("${joinedName}.h");
155         }
156     }
157
158     # additional includes (things needed to compile the bindings but not the header)
159
160     if ($type eq "CanvasRenderingContext2D") {
161         AddToImplIncludes("CanvasGradient.h");
162         AddToImplIncludes("CanvasPattern.h");
163         AddToImplIncludes("CanvasStyle.h");
164     }
165
166     if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
167         AddToImplIncludes("PlatformString.h");
168     }
169
170     if ($type eq "CSSStyleSheet" or $type eq "StyleSheet") {
171         AddToImplIncludes("CSSImportRule.h");
172     }
173
174     if ($type eq "CSSStyleDeclaration") {
175         AddToImplIncludes("StylePropertySet.h");
176     }
177
178     if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") {
179         # So we can get String -> AtomicString conversion for namedItem().
180         AddToImplIncludes("wtf/text/AtomicString.h");
181     }
182 }
183
184 sub GetSVGPropertyTypes
185 {
186     my $implType = shift;
187
188     my $svgPropertyType;
189     my $svgListPropertyType;
190     my $svgNativeType;
191
192     return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/;
193
194     $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType);
195     return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType;
196
197     # Append space to avoid compilation errors when using  PassRefPtr<$svgNativeType>
198     $svgNativeType = "$svgNativeType ";
199
200     my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType);
201     if ($svgNativeType =~ /SVGPropertyTearOff/) {
202         $svgPropertyType = $svgWrappedNativeType;
203         AddToImplIncludes("SVGAnimatedPropertyTearOff.h");
204     } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
205         $svgListPropertyType = $svgWrappedNativeType;
206         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
207         $headerIncludes{"SVGStaticListPropertyTearOff.h"} = 1;
208     } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
209         $svgListPropertyType = $svgWrappedNativeType;
210         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
211         $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
212     } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
213         $svgListPropertyType = $svgWrappedNativeType;
214         $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
215     }
216
217     if ($svgPropertyType) {
218         $svgPropertyType = "SVGPoint" if $svgPropertyType eq "FloatPoint";
219     }
220
221     return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
222 }
223
224 sub GenerateHeader
225 {
226     my $object = shift;
227     my $dataNode = shift;
228
229     my $interfaceName = $dataNode->name;
230     my $className = "V8$interfaceName";
231     my $implClassName = $interfaceName;
232
233     # Copy contents of parent classes except the first parent or if it is
234     # EventTarget.
235     $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1);
236     $codeGenerator->LinkOverloadedFunctions($dataNode);
237
238     my $hasDependentLifetime = $dataNode->extendedAttributes->{"V8DependentLifetime"} || $dataNode->extendedAttributes->{"ActiveDOMObject"} || $className =~ /SVG/;
239     if (!$hasDependentLifetime) {
240         foreach (@{$dataNode->parents}) {
241             my $parent = $codeGenerator->StripModule($_);
242             next if $parent eq "EventTarget";
243             $headerIncludes{"V8${parent}.h"} = 1;
244         }
245     }
246
247     # - Add default header template
248     push(@headerContent, GenerateHeaderContentHeader($dataNode));
249
250     $headerIncludes{"wtf/text/StringHash.h"} = 1;
251     $headerIncludes{"WrapperTypeInfo.h"} = 1;
252     $headerIncludes{"V8DOMWrapper.h"} = 1;
253     $headerIncludes{"wtf/HashMap.h"} = 1;
254     $headerIncludes{"v8.h"} = 1;
255
256     my $headerClassInclude = GetHeaderClassInclude($implClassName);
257     $headerIncludes{$headerClassInclude} = 1 if $headerClassInclude ne "";
258
259     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);
260
261     foreach my $headerInclude (sort keys(%headerIncludes)) {
262         if ($headerInclude =~ /wtf|v8\.h/) {
263             push(@headerContent, "#include \<${headerInclude}\>\n");
264         } else {
265             push(@headerContent, "#include \"${headerInclude}\"\n");
266         }
267     }
268
269     push(@headerContent, "\nnamespace WebCore {\n");
270     push(@headerContent, "\ntemplate<typename PropertyType> class SVGPropertyTearOff;\n") if $svgPropertyType;
271     if ($svgNativeType) {
272         if ($svgNativeType =~ /SVGStaticListPropertyTearOff/) {
273             push(@headerContent, "\ntemplate<typename PropertyType> class SVGStaticListPropertyTearOff;\n");
274         } else {
275             push(@headerContent, "\ntemplate<typename PropertyType> class SVGListPropertyTearOff;\n");
276         }
277     }
278
279     push(@headerContent, "\n");
280     push(@headerContent, "class FloatRect;\n") if $svgPropertyType && $svgPropertyType eq "FloatRect";
281     push(@headerContent, "class Dictionary;\n") if IsConstructorTemplate($dataNode, "Event");
282
283     my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
284     if ($dataNode->extendedAttributes->{"NamedConstructor"}) {
285         push(@headerContent, <<END);
286 class V8${nativeType}Constructor {
287 public:
288     static v8::Persistent<v8::FunctionTemplate> GetTemplate();
289     static WrapperTypeInfo info;
290 };
291
292 END
293     }
294
295     push(@headerContent, "class $className {\n");
296     push(@headerContent, "public:\n");
297
298     push(@headerContent, "    static const bool hasDependentLifetime = ");
299     if ($hasDependentLifetime) {
300         push(@headerContent, "true;\n");
301     } elsif (@{$dataNode->parents}) {
302         # Even if this type doesn't have the V8DependentLifetime attribute its parents may.
303         # Let the compiler statically determine this for us.
304         my $separator = "";
305         foreach (@{$dataNode->parents}) {
306             my $parent = $codeGenerator->StripModule($_);
307             next if $parent eq "EventTarget";
308             $headerIncludes{"V8${parent}.h"} = 1;
309             push(@headerContent, "${separator}V8${parent}::hasDependentLifetime");
310             $separator = " || ";
311         }
312         push(@headerContent, ";\n");
313     } else {
314         push(@headerContent, "false;\n");
315     }
316
317     my $forceNewObjectParameter = IsDOMNodeType($interfaceName) ? ", bool forceNewObject = false" : "";
318     my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
319     my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
320
321     push(@headerContent, <<END);
322     static bool HasInstance(v8::Handle<v8::Value>);
323     static v8::Persistent<v8::FunctionTemplate> GetRawTemplate();
324     static v8::Persistent<v8::FunctionTemplate> GetTemplate();
325     static ${nativeType}* toNative(v8::Handle<v8::Object> object)
326     {
327         return reinterpret_cast<${nativeType}*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex));
328     }
329     inline static v8::Handle<v8::Object> wrap(${nativeType}*, v8::Isolate* = 0${forceNewObjectParameter});
330     static void derefObject(void*);
331     static WrapperTypeInfo info;
332 END
333     if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
334         push(@headerContent, "    static ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object>);\n");
335     }
336
337     if ($implClassName eq "DOMWindow") {
338         push(@headerContent, <<END);
339     static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate();
340 END
341     }
342
343     if ($implClassName eq "HTMLDocument") {
344       push(@headerContent, <<END);
345   static v8::Local<v8::Object> WrapInShadowObject(v8::Local<v8::Object> wrapper, Node* impl);
346   static v8::Handle<v8::Value> GetNamedProperty(HTMLDocument* htmlDocument, const AtomicString& key, v8::Isolate*);
347 END
348     }
349
350     my @enabledAtRuntime;
351     my @enabledPerContext;
352     foreach my $function (@{$dataNode->functions}) {
353         my $name = $function->signature->name;
354         my $attrExt = $function->signature->extendedAttributes;
355
356         if (($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) && !$attrExt->{"ImplementedBy"} && $function->{overloadIndex} == 1) {
357             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
358             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
359             push(@headerContent, <<END);
360     static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments&);
361 END
362             push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
363         }
364
365         if ($attrExt->{"V8EnabledAtRuntime"}) {
366             push(@enabledAtRuntime, $function);
367         }
368     }
369
370     if (IsConstructable($dataNode)) {
371         push(@headerContent, <<END);
372     static v8::Handle<v8::Value> constructorCallback(const v8::Arguments&);
373 END
374     }
375
376     foreach my $attribute (@{$dataNode->attributes}) {
377         my $name = $attribute->signature->name;
378         my $attrExt = $attribute->signature->extendedAttributes;
379         my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
380         if (($attrExt->{"V8CustomGetter"} || $attrExt->{"CustomGetter"} ||
381              $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) &&
382             !$attrExt->{"ImplementedBy"}) {
383             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
384             push(@headerContent, <<END);
385     static v8::Handle<v8::Value> ${name}AccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);
386 END
387             push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
388         }
389         if (($attrExt->{"V8CustomSetter"} || $attrExt->{"CustomSetter"} ||
390              $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) &&
391             !$attrExt->{"ImplementedBy"}) {
392             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
393             push(@headerContent, <<END);
394     static void ${name}AccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value>, const v8::AccessorInfo&);
395 END
396             push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
397         }
398         if ($attrExt->{"V8EnabledAtRuntime"}) {
399             push(@enabledAtRuntime, $attribute);
400         }
401
402         if ($attrExt->{"V8EnabledPerContext"}) {
403             push(@enabledPerContext, $attribute);
404         }
405     }
406
407     GenerateHeaderNamedAndIndexedPropertyAccessors($dataNode);
408     GenerateHeaderCustomCall($dataNode);
409     GenerateHeaderCustomInternalFieldIndices($dataNode);
410
411     if ($dataNode->extendedAttributes->{"CheckSecurity"}) {
412         push(@headerContent, <<END);
413     static bool namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType, v8::Local<v8::Value> data);
414     static bool indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType, v8::Local<v8::Value> data);
415 END
416     }
417
418     if (@enabledPerContext) {
419         push(@headerContent, <<END);
420     static void installPerContextProperties(v8::Handle<v8::Object>, ${implClassName}*);
421 END
422     }
423
424     my $wrapSlowArgumentType = GetPassRefPtrType($nativeType);
425     push(@headerContent, <<END);
426 private:
427     static v8::Handle<v8::Object> wrapSlow(${wrapSlowArgumentType}, v8::Isolate*);
428 };
429
430 END
431
432     push(@headerContent, <<END);
433 v8::Handle<v8::Object> ${className}::wrap(${nativeType}* impl, v8::Isolate* isolate${forceNewObjectInput})
434 {
435 END
436     push(@headerContent, "    if (!forceNewObject) {\n") if IsDOMNodeType($interfaceName);
437     my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName, "isolate");
438     my $getCachedWrapper = IsNodeSubType($dataNode) ? "V8DOMWrapper::getCachedWrapper(impl)" : "${domMapFunction}.get(impl)";
439     push(@headerContent, <<END);
440         v8::Handle<v8::Object> wrapper = $getCachedWrapper;
441         if (!wrapper.IsEmpty())
442             return wrapper;
443 END
444     push(@headerContent, "    }\n") if IsDOMNodeType($interfaceName);
445     push(@headerContent, <<END);
446     return ${className}::wrapSlow(impl, isolate);
447 }
448 END
449
450     if ($interfaceName eq 'Element') {
451         # Do not generate toV8() for performance optimization.
452     } elsif (!($dataNode->extendedAttributes->{"CustomToJSObject"} or $dataNode->extendedAttributes->{"V8CustomToJSObject"})) {
453         push(@headerContent, <<END);
454
455 inline v8::Handle<v8::Value> toV8(${nativeType}* impl, v8::Isolate* isolate = 0${forceNewObjectParameter})
456 {
457     if (!impl)
458         return v8::Null();
459     return ${className}::wrap(impl, isolate${forceNewObjectCall});
460 }
461 END
462     } elsif ($interfaceName ne 'Node') {
463         push(@headerContent, <<END);
464
465 v8::Handle<v8::Value> toV8(${nativeType}*, v8::Isolate* = 0${forceNewObjectParameter});
466 END
467     } else {
468         push(@headerContent, <<END);
469
470 v8::Handle<v8::Value> toV8Slow(Node*, v8::Isolate*, bool);
471
472 inline v8::Handle<v8::Value> toV8(Node* impl, v8::Isolate* isolate = 0, bool forceNewObject = false)
473 {
474     if (UNLIKELY(!impl))
475         return v8::Null();
476     if (UNLIKELY(forceNewObject))
477         return toV8Slow(impl, isolate, forceNewObject);
478     v8::Handle<v8::Value> wrapper = V8DOMWrapper::getCachedWrapper(impl);
479     if (!wrapper.IsEmpty())
480         return wrapper;
481     return toV8Slow(impl, isolate, false);
482 }
483 END
484     }
485
486     push(@headerContent, <<END);
487 inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl, v8::Isolate* isolate = 0${forceNewObjectParameter})
488 {
489     return toV8(impl.get(), isolate${forceNewObjectCall});
490 }
491 END
492
493     if (IsConstructorTemplate($dataNode, "Event")) {
494         push(@headerContent, "\nbool fill${implClassName}Init(${implClassName}Init&, const Dictionary&);\n");
495     }
496
497     push(@headerContent, "\n}\n\n");
498     push(@headerContent, "#endif // $className" . "_h\n");
499
500     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
501     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
502 }
503
504 sub GetInternalFields
505 {
506     my $dataNode = shift;
507     my $name = $dataNode->name;
508
509     my @customInternalFields = ();
510     # We can't ask whether a parent type has a given extendedAttribute,
511     # so special-case AbstractWorker and WorkerContext to include all sub-types.
512     # Event listeners on DOM nodes are explicitly supported in the GC controller.
513     # FIXME: SVGElementInstance should probably have the EventTarget extended attribute, but doesn't.
514     if (!IsNodeSubType($dataNode)
515         && ($dataNode->extendedAttributes->{"EventTarget"}
516             || $dataNode->extendedAttributes->{"IsWorkerContext"}
517             || IsSubType($dataNode, "AbstractWorker")
518             || $name eq "SVGElementInstance")) {
519         push(@customInternalFields, "eventListenerCacheIndex");
520     }
521
522     if ($name eq "DOMWindow") {
523         push(@customInternalFields, "enteredIsolatedWorldIndex");
524     }
525     return @customInternalFields;
526 }
527
528 sub GetHeaderClassInclude
529 {
530     my $className = shift;
531     if ($className =~ /SVGPathSeg/) {
532         $className =~ s/Abs|Rel//;
533     }
534     return "wtf/${className}.h" if IsTypedArrayType($className);
535     return "" if ($codeGenerator->SkipIncludeHeader($className));
536     return "${className}.h";
537 }
538
539 sub GenerateHeaderCustomInternalFieldIndices
540 {
541     my $dataNode = shift;
542     my @customInternalFields = GetInternalFields($dataNode);
543     my $customFieldCounter = 0;
544     foreach my $customInternalField (@customInternalFields) {
545         push(@headerContent, <<END);
546     static const int ${customInternalField} = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
547 END
548         $customFieldCounter++;
549     }
550     push(@headerContent, <<END);
551     static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
552 END
553 }
554
555 my %indexerSpecialCases = (
556     "Storage" => 1,
557     "HTMLAppletElement" => 1,
558     "HTMLEmbedElement" => 1,
559     "HTMLObjectElement" => 1
560 );
561
562 sub GenerateHeaderNamedAndIndexedPropertyAccessors
563 {
564     my $dataNode = shift;
565     my $interfaceName = $dataNode->name;
566     my $hasCustomIndexedGetter = $dataNode->extendedAttributes->{"IndexedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
567     my $hasCustomIndexedSetter = $dataNode->extendedAttributes->{"CustomIndexedSetter"} && !$dataNode->extendedAttributes->{"NumericIndexedGetter"};
568     my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"NamedGetter"} || $dataNode->extendedAttributes->{"CustomNamedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
569     my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"CustomNamedSetter"};
570     my $hasCustomDeleters = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
571     my $hasCustomEnumerator = $dataNode->extendedAttributes->{"CustomEnumerateProperty"};
572     if ($interfaceName eq "HTMLOptionsCollection") {
573         $interfaceName = "HTMLCollection";
574         $hasCustomIndexedGetter = 1;
575         $hasCustomNamedGetter = 1;
576     }
577     if ($interfaceName eq "DOMWindow") {
578         $hasCustomDeleters = 0;
579         $hasCustomEnumerator = 0;
580     }
581     if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
582         $hasCustomNamedGetter = 1;
583     }
584     if ($interfaceName eq "HTMLDocument") {
585         $hasCustomNamedGetter = 0;
586         $hasCustomIndexedGetter = 0;
587     }
588     my $isIndexerSpecialCase = exists $indexerSpecialCases{$interfaceName};
589
590     if ($hasCustomIndexedGetter || $isIndexerSpecialCase) {
591         push(@headerContent, <<END);
592     static v8::Handle<v8::Value> indexedPropertyGetter(uint32_t, const v8::AccessorInfo&);
593 END
594     }
595
596     if ($isIndexerSpecialCase || $hasCustomIndexedSetter) {
597         push(@headerContent, <<END);
598     static v8::Handle<v8::Value> indexedPropertySetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&);
599 END
600     }
601     if ($hasCustomDeleters) {
602         push(@headerContent, <<END);
603     static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t, const v8::AccessorInfo&);
604 END
605     }
606     if ($hasCustomNamedGetter) {
607         push(@headerContent, <<END);
608     static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String>, const v8::AccessorInfo&);
609 END
610     }
611     if ($hasCustomNamedSetter) {
612         push(@headerContent, <<END);
613     static v8::Handle<v8::Value> namedPropertySetter(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo&);
614 END
615     }
616     if ($hasCustomDeleters) {
617         push(@headerContent, <<END);
618     static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String>, const v8::AccessorInfo&);
619 END
620     }
621     if ($hasCustomEnumerator) {
622         push(@headerContent, <<END);
623     static v8::Handle<v8::Array> namedPropertyEnumerator(const v8::AccessorInfo&);
624     static v8::Handle<v8::Integer> namedPropertyQuery(v8::Local<v8::String>, const v8::AccessorInfo&);
625 END
626     }
627 }
628
629 sub GenerateHeaderCustomCall
630 {
631     my $dataNode = shift;
632
633     if ($dataNode->extendedAttributes->{"CustomCall"}) {
634         push(@headerContent, "    static v8::Handle<v8::Value> callAsFunctionCallback(const v8::Arguments&);\n");
635     }
636     if ($dataNode->name eq "Event") {
637         push(@headerContent, "    static v8::Handle<v8::Value> dataTransferAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
638         push(@headerContent, "    static void valueAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value>, const v8::AccessorInfo&);\n");
639     }
640     if ($dataNode->name eq "Location") {
641         push(@headerContent, "    static v8::Handle<v8::Value> assignAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
642         push(@headerContent, "    static v8::Handle<v8::Value> reloadAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
643         push(@headerContent, "    static v8::Handle<v8::Value> replaceAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
644     }
645 }
646
647 sub GenerateSetDOMException
648 {
649     my $indent = shift;
650     my $getIsolate = shift;
651     my $result = "";
652
653     $result .= $indent . "if (UNLIKELY(ec)) {\n";
654     $result .= $indent . "    V8Proxy::setDOMException(ec, $getIsolate);\n";
655     $result .= $indent . "    return v8::Handle<v8::Value>();\n";
656     $result .= $indent . "}\n";
657
658     return $result;
659 }
660
661 sub IsSubType
662 {
663     my $dataNode = shift;
664     my $parentType = shift;
665     return 1 if ($dataNode->name eq $parentType);
666     foreach (@allParents) {
667         my $parent = $codeGenerator->StripModule($_);
668         return 1 if $parent eq $parentType;
669     }
670     return 0;
671 }
672
673 sub IsNodeSubType
674 {
675     my $dataNode = shift;
676     return IsSubType($dataNode, "Node");
677 }
678
679 sub IsVisibleAcrossOrigins
680 {
681     my $dataNode = shift;
682     return $dataNode->extendedAttributes->{"CheckSecurity"} && !($dataNode->name eq "DOMWindow");
683 }
684
685 sub IsConstructable
686 {
687     my $dataNode = shift;
688
689     return $dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"Constructor"} || $dataNode->extendedAttributes->{"ConstructorTemplate"};
690 }
691
692 sub IsConstructorTemplate
693 {
694     my $dataNode = shift;
695     my $template = shift;
696
697     return $dataNode->extendedAttributes->{"ConstructorTemplate"} && $dataNode->extendedAttributes->{"ConstructorTemplate"} eq $template;
698 }
699
700 sub GenerateDomainSafeFunctionGetter
701 {
702     my $function = shift;
703     my $implClassName = shift;
704
705     my $className = "V8" . $implClassName;
706     my $funcName = $function->signature->name;
707
708     my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())";
709     if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) {
710         $signature = "v8::Local<v8::Signature>()";
711     }
712
713     my $newTemplateString = GenerateNewFunctionTemplate($function, $implClassName, $signature);
714
715     push(@implContentDecls, <<END);
716 static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
717 {
718     INC_STATS(\"DOM.$implClassName.$funcName._get\");
719     static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
720     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(${className}::GetTemplate(), info.This());
721     if (holder.IsEmpty()) {
722         // can only reach here by 'object.__proto__.func', and it should passed
723         // domain security check already
724         return privateTemplate->GetFunction();
725     }
726     ${implClassName}* imp = ${className}::toNative(holder);
727     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) {
728         static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
729         return sharedTemplate->GetFunction();
730     }
731     return privateTemplate->GetFunction();
732 }
733
734 END
735 }
736
737 sub GenerateConstructorGetter
738 {
739     my $dataNode = shift;
740     my $implClassName = shift;
741
742     push(@implContentDecls, <<END);
743 static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
744 {
745     INC_STATS(\"DOM.$implClassName.constructors._get\");
746     v8::Handle<v8::Value> data = info.Data();
747     ASSERT(data->IsExternal() || data->IsNumber());
748     WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data);
749 END
750
751     if ($implClassName eq "DOMWindow") {
752         push(@implContentDecls, <<END);
753     // Get the proxy corresponding to the DOMWindow if possible to
754     // make sure that the constructor function is constructed in the
755     // context of the DOMWindow and not in the context of the caller.
756     return V8DOMWrapper::constructorForType(type, V8DOMWindow::toNative(info.Holder()));
757 END
758     } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
759         push(@implContentDecls, <<END);
760     return V8DOMWrapper::constructorForType(type, V8WorkerContext::toNative(info.Holder()));
761 END
762     } else {
763         push(@implContentDecls, "    return v8::Handle<v8::Value>();");
764     }
765
766     push(@implContentDecls, <<END);
767 }
768
769 END
770 }
771
772 sub GenerateNormalAttrGetter
773 {
774     my $attribute = shift;
775     my $dataNode = shift;
776     my $implClassName = shift;
777     my $interfaceName = shift;
778
779     my $attrExt = $attribute->signature->extendedAttributes;
780     my $attrName = $attribute->signature->name;
781     my $attrType = GetTypeFromSignature($attribute->signature);
782     my $nativeType = GetNativeTypeFromSignature($attribute->signature, -1);
783
784     my $getterStringUsesImp = $implClassName ne "SVGNumber";
785     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
786
787     # Getter
788     my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
789     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
790
791     push(@implContentDecls, <<END);
792 static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
793 {
794     INC_STATS(\"DOM.$implClassName.$attrName._get\");
795 END
796
797     if ($svgNativeType) {
798         my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
799         if ($svgWrappedNativeType =~ /List/) {
800             push(@implContentDecls, <<END);
801     $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
802 END
803         } else {
804             push(@implContentDecls, <<END);
805     $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());
806     $svgWrappedNativeType& impInstance = wrapper->propertyReference();
807 END
808             if ($getterStringUsesImp) {
809                 push(@implContentDecls, <<END);
810     $svgWrappedNativeType* imp = &impInstance;
811 END
812             }
813         }
814     } elsif ($attrExt->{"V8OnProto"} || $attrExt->{"V8Unforgeable"}) {
815         if ($interfaceName eq "DOMWindow") {
816             push(@implContentDecls, <<END);
817     v8::Handle<v8::Object> holder = info.Holder();
818 END
819         } else {
820             # perform lookup first
821             push(@implContentDecls, <<END);
822     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
823     if (holder.IsEmpty())
824         return v8::Handle<v8::Value>();
825 END
826         }
827         push(@implContentDecls, <<END);
828     ${implClassName}* imp = V8${implClassName}::toNative(holder);
829 END
830     } else {
831         my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
832         my $url = $attribute->signature->extendedAttributes->{"URL"};
833         if ($getterStringUsesImp && $reflect && !$url && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
834             # Generate super-compact call for regular attribute getter:
835             my $contentAttributeName = $reflect eq "VALUE_IS_MISSING" ? lc $attrName : $reflect;
836             my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
837             AddToImplIncludes("${namespace}.h");
838             push(@implContentDecls, "    return getElementStringAttr(info, ${namespace}::${contentAttributeName}Attr);\n");
839             push(@implContentDecls, "}\n\n");
840             push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
841             return;
842             # Skip the rest of the function!
843         }
844         if ($attribute->signature->type eq "SerializedScriptValue" && $attrExt->{"CachedAttribute"}) {
845             push(@implContentDecls, <<END);
846     v8::Handle<v8::String> propertyName = v8::String::NewSymbol("${attrName}");
847     v8::Handle<v8::Value> value = info.Holder()->GetHiddenValue(propertyName);
848     if (!value.IsEmpty())
849         return value;
850 END
851         }
852         push(@implContentDecls, <<END);
853     ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
854 END
855     }
856
857     # Generate security checks if necessary
858     if ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
859         push(@implContentDecls, "    if (!V8BindingSecurity::shouldAllowAccessToNode(V8BindingState::Only(), imp->" . $attribute->signature->name . "()))\n        return v8::Handle<v8::Value>(v8::Null());\n\n");
860     }
861
862     my $useExceptions = 1 if @{$attribute->getterExceptions};
863     if ($useExceptions) {
864         AddToImplIncludes("ExceptionCode.h");
865         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
866     }
867
868     my $returnType = GetTypeFromSignature($attribute->signature);
869     my $getterString;
870
871     if ($getterStringUsesImp) {
872         my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
873
874         push(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContentDecls, "    ", 0, 0));
875
876         push(@arguments, "ec") if $useExceptions;
877         if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
878             my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
879             AddToImplIncludes("${implementedBy}.h");
880             unshift(@arguments, "imp");
881             $functionName = "${implementedBy}::${functionName}";
882         } else {
883             $functionName = "imp->${functionName}";
884         }
885         $getterString = "${functionName}(" . join(", ", @arguments) . ")";
886     } else {
887         $getterString = "impInstance";
888     }
889
890     my $result;
891     my $wrapper;
892
893     if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") {
894         push(@implContentDecls, "    if (!imp->document())\n");
895         push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
896     }
897
898     if ($useExceptions) {
899         if ($nativeType =~ /^V8Parameter/) {
900             push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $getterString) . ";\n");
901         } else {
902             push(@implContentDecls, "    $nativeType v = $getterString;\n");
903         }
904         push(@implContentDecls, GenerateSetDOMException("    ", "info.GetIsolate()"));
905
906         if ($codeGenerator->ExtendedAttributeContains($attribute->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
907             push(@implContentDecls, "    if (state.hadException())\n");
908             push(@implContentDecls, "        return throwError(state.exception(), info.GetIsolate());\n");
909         }
910
911         $result = "v";
912         $result .= ".release()" if (IsRefPtrType($returnType));
913     } else {
914         # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
915         $result = $getterString;
916         # Fix amigious conversion problem, by casting to the base type first ($getterString returns a type that inherits from SVGAnimatedEnumeration, not the base class directly).
917         $result = "static_pointer_cast<SVGAnimatedEnumeration>($result)" if $returnType eq "SVGAnimatedEnumeration";
918     }
919  
920     # Special case for readonly or Replaceable attributes (with a few exceptions). This attempts to ensure that JS wrappers don't get
921     # garbage-collected prematurely when their lifetime is strongly tied to their owner. We accomplish this by inserting a reference to
922     # the newly created wrapper into an internal field of the holder object.
923     if (!IsNodeSubType($dataNode) && $attrName ne "self" && (IsWrapperType($returnType) && ($attribute->type =~ /^readonly/ || $attribute->signature->extendedAttributes->{"Replaceable"})
924         && $returnType ne "EventTarget" && $returnType ne "SerializedScriptValue" && $returnType ne "DOMWindow" 
925         && $returnType ne "MessagePortArray"
926         && $returnType !~ /SVG/ && $returnType !~ /HTML/ && !IsDOMNodeType($returnType))) {
927
928         my $arrayType = $codeGenerator->GetArrayType($returnType);
929         if ($arrayType) {
930             if (!$codeGenerator->SkipIncludeHeader($arrayType)) {
931                 AddToImplIncludes("V8$arrayType.h");
932                 AddToImplIncludes("$arrayType.h");
933             }
934             push(@implContentDecls, "    return v8Array(${getterString}, info.GetIsolate());\n");
935             push(@implContentDecls, "}\n\n");
936             return;
937         }
938
939         AddIncludesForType($returnType);
940         # Check for a wrapper in the wrapper cache. If there is one, we know that a hidden reference has already
941         # been created. If we don't find a wrapper, we create both a wrapper and a hidden reference.
942         push(@implContentDecls, "    RefPtr<$returnType> result = ${getterString};\n");
943         my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName, "info.GetIsolate()");
944         push(@implContentDecls, "    v8::Handle<v8::Value> wrapper = result.get() ? ${domMapFunction}.get(result.get()) : v8::Handle<v8::Object>();\n");
945         push(@implContentDecls, "    if (wrapper.IsEmpty()) {\n");
946         push(@implContentDecls, "        wrapper = toV8(result.get(), info.GetIsolate());\n");
947         push(@implContentDecls, "        if (!wrapper.IsEmpty())\n");
948         if ($dataNode->name eq "DOMWindow") {
949             push(@implContentDecls, "            V8DOMWrapper::setNamedHiddenWindowReference(imp->frame(), \"${attrName}\", wrapper);\n");
950         } else {
951             push(@implContentDecls, "            V8DOMWrapper::setNamedHiddenReference(info.Holder(), \"${attrName}\", wrapper);\n");
952         }
953         push(@implContentDecls, "    }\n");
954         push(@implContentDecls, "    return wrapper;\n");
955         push(@implContentDecls, "}\n\n");
956         push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
957         return;
958     }
959
960     if ($codeGenerator->IsSVGAnimatedType($implClassName) and $codeGenerator->IsSVGTypeNeedingTearOff($attrType)) {
961         AddToImplIncludes("V8$attrType.h");
962         my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
963         # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked.
964         push(@implContentDecls, "    return toV8(static_cast<$svgNativeType*>($result), info.GetIsolate());\n");
965     } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($attrType) and not $implClassName =~ /List$/) {
966         AddToImplIncludes("V8$attrType.h");
967         AddToImplIncludes("SVGPropertyTearOff.h");
968         my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
969         if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) {
970             my $getter = $result;
971             $getter =~ s/imp->//;
972             $getter =~ s/\(\)//;
973
974             my $updateMethod = "&${implClassName}::update" . $codeGenerator->WK_ucfirst($getter);
975
976             my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($implClassName);
977             if ($selfIsTearOffType) {
978                 AddToImplIncludes("SVGStaticPropertyWithParentTearOff.h");
979                 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyWithParentTearOff<$implClassName, /;
980
981                 if ($result =~ /matrix/ and $implClassName eq "SVGTransform") {
982                     # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform
983                     # and a svgMatrix() method returning a SVGMatrix, used for the bindings.
984                     $result =~ s/matrix/svgMatrix/;
985                 }
986
987                 push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(wrapper, $result, $updateMethod)), info.GetIsolate());\n");
988             } else {
989                 AddToImplIncludes("SVGStaticPropertyTearOff.h");
990                 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /;
991
992                 push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(imp, $result, $updateMethod)), info.GetIsolate());\n");
993             }
994         } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) {
995             push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(imp, $result)), info.GetIsolate());\n");
996         } elsif ($tearOffType =~ /SVG(Point|PathSeg)List/) {
997             push(@implContentDecls, "    return toV8(WTF::getPtr($result), info.GetIsolate());\n");
998         } else {
999             push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create($result)), info.GetIsolate());\n");
1000         }
1001     } elsif ($attribute->signature->type eq "MessagePortArray") {
1002         AddToImplIncludes("MessagePort.h");
1003         AddToImplIncludes("V8MessagePort.h");
1004         my $getterFunc = $codeGenerator->WK_lcfirst($attribute->signature->name);
1005         push(@implContentDecls, <<END);
1006     MessagePortArray* ports = imp->${getterFunc}();
1007     if (!ports)
1008         return v8::Array::New(0);
1009     MessagePortArray portsCopy(*ports);
1010     v8::Local<v8::Array> portArray = v8::Array::New(portsCopy.size());
1011     for (size_t i = 0; i < portsCopy.size(); ++i)
1012         portArray->Set(v8::Integer::New(i), toV8(portsCopy[i].get(), info.GetIsolate()));
1013     return portArray;
1014 END
1015     } else {
1016         if ($attribute->signature->type eq "SerializedScriptValue" && $attrExt->{"CachedAttribute"}) {
1017             my $getterFunc = $codeGenerator->WK_lcfirst($attribute->signature->name);
1018             push(@implContentDecls, <<END);
1019     SerializedScriptValue* serialized = imp->${getterFunc}();
1020     value = serialized ? serialized->deserialize() : v8::Handle<v8::Value>(v8::Null());
1021     info.Holder()->SetHiddenValue(propertyName, value);
1022     return value;
1023 END
1024         } else {
1025             push(@implContentDecls, "    " . ReturnNativeToJSValue($attribute->signature, $result, "info.GetIsolate()").";\n");
1026         }
1027     }
1028
1029     push(@implContentDecls, "}\n\n");  # end of getter
1030     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1031 }
1032
1033 sub GenerateNormalAttrSetter
1034 {
1035     my $attribute = shift;
1036     my $dataNode = shift;
1037     my $implClassName = shift;
1038     my $interfaceName = shift;
1039
1040     AddToImplIncludes("V8BindingMacros.h");
1041
1042     my $attrName = $attribute->signature->name;
1043     my $attrExt = $attribute->signature->extendedAttributes;
1044
1045     my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1046     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
1047
1048     push(@implContentDecls, "static void ${attrName}AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n");
1049     push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");
1050
1051     # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
1052     # interface type, then if the incoming value does not implement that interface, a TypeError is
1053     # thrown rather than silently passing NULL to the C++ code.
1054     # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to both
1055     # strings and numbers, so do not throw TypeError if the attribute is of these types.
1056     if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
1057         my $argType = GetTypeFromSignature($attribute->signature);
1058         if (IsWrapperType($argType)) {
1059             push(@implContentDecls, "    if (!isUndefinedOrNull(value) && !V8${argType}::HasInstance(value)) {\n");
1060             push(@implContentDecls, "        V8Proxy::throwTypeError();\n");
1061             push(@implContentDecls, "        return;\n");
1062             push(@implContentDecls, "    }\n");
1063         }
1064     }
1065
1066     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
1067     if ($svgNativeType) {
1068         my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
1069         if ($svgWrappedNativeType =~ /List$/) {
1070             push(@implContentDecls, <<END);
1071     $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
1072 END
1073         } else {
1074             AddToImplIncludes("ExceptionCode.h");
1075             push(@implContentDecls, "    $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());\n");
1076             push(@implContentDecls, "    if (wrapper->role() == AnimValRole) {\n");
1077             push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR, info.GetIsolate());\n");
1078             push(@implContentDecls, "        return;\n");
1079             push(@implContentDecls, "    }\n");
1080             push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
1081             push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
1082         }
1083     } elsif ($attrExt->{"V8OnProto"}) {
1084       if ($interfaceName eq "DOMWindow") {
1085         push(@implContentDecls, <<END);
1086     v8::Handle<v8::Object> holder = info.Holder();
1087 END
1088       } else {
1089         # perform lookup first
1090         push(@implContentDecls, <<END);
1091     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
1092     if (holder.IsEmpty())
1093         return;
1094 END
1095       }
1096     push(@implContentDecls, <<END);
1097     ${implClassName}* imp = V8${implClassName}::toNative(holder);
1098 END
1099     } else {
1100         my $attrType = GetTypeFromSignature($attribute->signature);
1101         my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
1102         if ($reflect && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
1103             # Generate super-compact call for regular attribute setter:
1104             my $contentAttributeName = $reflect eq "VALUE_IS_MISSING" ? lc $attrName : $reflect;
1105             my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
1106             AddToImplIncludes("${namespace}.h");
1107             push(@implContentDecls, "    setElementStringAttr(info, ${namespace}::${contentAttributeName}Attr, value);\n");
1108             push(@implContentDecls, "}\n\n");
1109             push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1110             return;
1111             # Skip the rest of the function!
1112         }
1113
1114         push(@implContentDecls, <<END);
1115     ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
1116 END
1117     }
1118
1119     my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
1120     if ($attribute->signature->type eq "EventListener") {
1121         if ($dataNode->name eq "DOMWindow") {
1122             push(@implContentDecls, "    if (!imp->document())\n");
1123             push(@implContentDecls, "        return;\n");
1124         }
1125     } else {
1126         my $value = JSValueToNative($attribute->signature, "value", "info.GetIsolate()");
1127         my $arrayType = $codeGenerator->GetArrayType($nativeType);
1128
1129         if ($nativeType =~ /^V8Parameter/) {
1130             push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $value, "VOID") . "\n");
1131         } elsif ($arrayType) {
1132             push(@implContentDecls, "    Vector<$arrayType> v = $value;\n");
1133         } else {
1134             push(@implContentDecls, "    $nativeType v = $value;\n");
1135         }
1136     }
1137
1138     my $result = "v";
1139     my $returnType = GetTypeFromSignature($attribute->signature);
1140     if (IsRefPtrType($returnType) && !$codeGenerator->GetArrayType($returnType)) {
1141         $result = "WTF::getPtr(" . $result . ")";
1142     }
1143
1144     my $useExceptions = 1 if @{$attribute->setterExceptions};
1145
1146     if ($useExceptions) {
1147         AddToImplIncludes("ExceptionCode.h");
1148         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
1149     }
1150
1151     if ($implClassName eq "SVGNumber") {
1152         push(@implContentDecls, "    *imp = $result;\n");
1153     } else {
1154         if ($attribute->signature->type eq "EventListener") {
1155             my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName);
1156             AddToImplIncludes("V8AbstractEventListener.h");
1157             if (!IsNodeSubType($dataNode)) {
1158                 push(@implContentDecls, "    transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n");
1159             }
1160             if ($interfaceName eq "WorkerContext" and $attribute->signature->name eq "onerror") {
1161                 AddToImplIncludes("V8EventListenerList.h");
1162                 AddToImplIncludes("V8WorkerContextErrorHandler.h");
1163                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WorkerContextErrorHandler>(value, true)");
1164             } elsif ($interfaceName eq "DOMWindow" and $attribute->signature->name eq "onerror") {
1165                 AddToImplIncludes("V8EventListenerList.h");
1166                 AddToImplIncludes("V8WindowErrorHandler.h");
1167                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WindowErrorHandler>(value, true)");
1168             } else {
1169                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)");
1170             }
1171             push(@implContentDecls, ", ec") if $useExceptions;
1172             push(@implContentDecls, ");\n");
1173         } else {
1174             my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
1175
1176             push(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContentDecls, "    ", 1, 0));
1177
1178             push(@arguments, $result);
1179             push(@arguments, "ec") if $useExceptions;
1180             if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
1181                 my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
1182                 AddToImplIncludes("${implementedBy}.h");
1183                 unshift(@arguments, "imp");
1184                 $functionName = "${implementedBy}::${functionName}";
1185             } else {
1186                 $functionName = "imp->${functionName}";
1187             }
1188             push(@implContentDecls, "    ${functionName}(" . join(", ", @arguments) . ");\n");
1189         }
1190     }
1191
1192     if ($useExceptions) {
1193         push(@implContentDecls, "    if (UNLIKELY(ec))\n");
1194         push(@implContentDecls, "        V8Proxy::setDOMException(ec, info.GetIsolate());\n");
1195     }
1196
1197     if ($codeGenerator->ExtendedAttributeContains($attribute->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
1198         push(@implContentDecls, "    if (state.hadException())\n");
1199         push(@implContentDecls, "        throwError(state.exception(), info.GetIsolate());\n");
1200     }
1201
1202     if ($svgNativeType) {
1203         if ($useExceptions) {
1204             push(@implContentDecls, "    if (!ec)\n");
1205             push(@implContentDecls, "        wrapper->commitChange();\n");
1206         } else {
1207             push(@implContentDecls, "    wrapper->commitChange();\n");
1208         }
1209     }
1210
1211     if ($attribute->signature->type eq "SerializedScriptValue" && $attribute->signature->extendedAttributes->{"CachedAttribute"}) {
1212         push(@implContentDecls, <<END);
1213     info.Holder()->DeleteHiddenValue(v8::String::NewSymbol("${attrName}")); // Invalidate the cached value.
1214 END
1215     }
1216
1217     push(@implContentDecls, "    return;\n");
1218     push(@implContentDecls, "}\n\n");  # end of setter
1219     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1220 }
1221
1222 sub GetFunctionTemplateCallbackName
1223 {
1224     my $function = shift;
1225     my $interfaceName = shift;
1226
1227     my $name = $function->signature->name;
1228
1229     if ($function->signature->extendedAttributes->{"Custom"} ||
1230         $function->signature->extendedAttributes->{"V8Custom"}) {
1231         if ($function->signature->extendedAttributes->{"Custom"} &&
1232             $function->signature->extendedAttributes->{"V8Custom"}) {
1233             die "Custom and V8Custom should be mutually exclusive!"
1234         }
1235         return "V8${interfaceName}::${name}Callback";
1236     } else {
1237         return "${interfaceName}V8Internal::${name}Callback";
1238     }
1239 }
1240
1241 sub GenerateNewFunctionTemplate
1242 {
1243     my $function = shift;
1244     my $interfaceName = shift;
1245     my $signature = shift;
1246
1247     my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
1248     return "v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), $signature)";
1249 }
1250
1251 sub GenerateEventListenerCallback
1252 {
1253     my $implClassName = shift;
1254     my $requiresHiddenDependency = shift;
1255     my $functionName = shift;
1256     my $lookupType = ($functionName eq "add") ? "OrCreate" : "Only";
1257     my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
1258     my $hiddenDependencyAction = ($functionName eq "add") ? "create" : "remove";
1259  
1260     push(@implContentDecls, <<END);
1261 static v8::Handle<v8::Value> ${functionName}EventListenerCallback(const v8::Arguments& args)
1262 {
1263     INC_STATS("DOM.${implClassName}.${functionName}EventListener()");
1264     RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFind${lookupType});
1265     if (listener) {
1266         V8${implClassName}::toNative(args.Holder())->${functionName}EventListener(v8ValueToAtomicWebCoreString(args[0]), listener${passRefPtrHandling}, args[2]->BooleanValue());
1267 END
1268     if ($requiresHiddenDependency) {
1269         push(@implContentDecls, <<END);
1270         ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], V8${implClassName}::eventListenerCacheIndex);
1271 END
1272     }
1273     push(@implContentDecls, <<END);
1274     }
1275     return v8::Undefined();
1276 }
1277
1278 END
1279 }
1280
1281 sub GenerateParametersCheckExpression
1282 {
1283     my $numParameters = shift;
1284     my $function = shift;
1285
1286     my @andExpression = ();
1287     push(@andExpression, "args.Length() == $numParameters");
1288     my $parameterIndex = 0;
1289     foreach my $parameter (@{$function->parameters}) {
1290         last if $parameterIndex >= $numParameters;
1291         my $value = "args[$parameterIndex]";
1292         my $type = GetTypeFromSignature($parameter);
1293
1294         # Only DOMString or wrapper types are checked.
1295         # For DOMString, Null, Undefined and any Object are accepted too, as
1296         # these are acceptable values for a DOMString argument (any Object can
1297         # be converted to a string via .toString).
1298         if ($codeGenerator->IsStringType($type)) {
1299             push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())");
1300         } elsif ($parameter->extendedAttributes->{"Callback"}) {
1301             # For Callbacks only checks if the value is null or object.
1302             push(@andExpression, "(${value}->IsNull() || ${value}->IsFunction())");
1303         } elsif (IsArrayType($type)) {
1304             # FIXME: Add proper support for T[], T[]?, sequence<T>.
1305             push(@andExpression, "(${value}->IsNull() || ${value}->IsArray())");
1306         } elsif (IsWrapperType($type)) {
1307             push(@andExpression, "(${value}->IsNull() || V8${type}::HasInstance($value))");
1308         }
1309
1310         $parameterIndex++;
1311     }
1312     my $res = join(" && ", @andExpression);
1313     $res = "($res)" if @andExpression > 1;
1314     return $res;
1315 }
1316
1317 sub GenerateFunctionParametersCheck
1318 {
1319     my $function = shift;
1320
1321     my @orExpression = ();
1322     my $numParameters = 0;
1323     foreach my $parameter (@{$function->parameters}) {
1324         if ($parameter->extendedAttributes->{"Optional"}) {
1325             push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
1326         }
1327         $numParameters++;
1328     }
1329     push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
1330     return join(" || ", @orExpression);
1331 }
1332
1333 sub GenerateOverloadedFunctionCallback
1334 {
1335     my $function = shift;
1336     my $dataNode = shift;
1337     my $implClassName = shift;
1338
1339     # Generate code for choosing the correct overload to call. Overloads are
1340     # chosen based on the total number of arguments passed and the type of
1341     # values passed in non-primitive argument slots. When more than a single
1342     # overload is applicable, precedence is given according to the order of
1343     # declaration in the IDL.
1344
1345     my $name = $function->signature->name;
1346     my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1347     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
1348     push(@implContentDecls, <<END);
1349 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
1350 {
1351     INC_STATS(\"DOM.$implClassName.$name\");
1352 END
1353
1354     foreach my $overload (@{$function->{overloads}}) {
1355         my $parametersCheck = GenerateFunctionParametersCheck($overload);
1356         push(@implContentDecls, "    if ($parametersCheck)\n");
1357         push(@implContentDecls, "        return ${name}$overload->{overloadIndex}Callback(args);\n");
1358     }
1359     push(@implContentDecls, <<END);
1360     V8Proxy::throwTypeError();
1361     return v8::Handle<v8::Value>();
1362 END
1363     push(@implContentDecls, "}\n\n");
1364     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1365 }
1366
1367 sub GenerateFunctionCallback
1368 {
1369     my $function = shift;
1370     my $dataNode = shift;
1371     my $implClassName = shift;
1372
1373     my $interfaceName = $dataNode->name;
1374     my $name = $function->signature->name;
1375
1376     if (@{$function->{overloads}} > 1) {
1377         # Append a number to an overloaded method's name to make it unique:
1378         $name = $name . $function->{overloadIndex};
1379     }
1380
1381     # Adding and removing event listeners are not standard callback behavior,
1382     # but they are extremely consistent across the various classes that take event listeners,
1383     # so we can generate them as a "special case".
1384     if ($name eq "addEventListener") {
1385         GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "add");
1386         return;
1387     } elsif ($name eq "removeEventListener") {
1388         GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "remove");
1389         return;
1390     }
1391
1392     my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1393     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
1394     push(@implContentDecls, <<END);
1395 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
1396 {
1397     INC_STATS(\"DOM.$implClassName.$name\");
1398 END
1399
1400     push(@implContentDecls, GenerateArgumentsCountCheck($function, $dataNode));
1401
1402     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);
1403
1404     if ($svgNativeType) {
1405         my $nativeClassName = GetNativeType($implClassName); 
1406         if ($implClassName =~ /List$/) {
1407             push(@implContentDecls, "    $nativeClassName imp = V8${implClassName}::toNative(args.Holder());\n");
1408         } else {
1409             AddToImplIncludes("ExceptionCode.h");
1410             push(@implContentDecls, "    $nativeClassName wrapper = V8${implClassName}::toNative(args.Holder());\n");
1411             push(@implContentDecls, "    if (wrapper->role() == AnimValRole) {\n");
1412             push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR, args.GetIsolate());\n");
1413             push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
1414             push(@implContentDecls, "    }\n");
1415             my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
1416             push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
1417             push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
1418         }
1419     } elsif (!$function->isStatic) {
1420         push(@implContentDecls, <<END);
1421     ${implClassName}* imp = V8${implClassName}::toNative(args.Holder());
1422 END
1423     }
1424
1425     # Check domain security if needed
1426     if (($dataNode->extendedAttributes->{"CheckSecurity"}
1427        || $interfaceName eq "DOMWindow")
1428        && !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
1429     # We have not find real use cases yet.
1430     push(@implContentDecls, <<END);
1431     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
1432         return v8::Handle<v8::Value>();
1433 END
1434     }
1435
1436     my $raisesExceptions = @{$function->raisesExceptions};
1437     if (!$raisesExceptions) {
1438         foreach my $parameter (@{$function->parameters}) {
1439             if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
1440                 $raisesExceptions = 1;
1441             }
1442         }
1443     }
1444
1445     if ($raisesExceptions) {
1446         AddToImplIncludes("ExceptionCode.h");
1447         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
1448         push(@implContentDecls, "    {\n");
1449         # The brace here is needed to prevent the ensuing 'goto fail's from jumping past constructors
1450         # of objects (like Strings) declared later, causing compile errors. The block scope ends
1451         # right before the label 'fail:'.
1452     }
1453
1454     if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) {
1455         push(@implContentDecls, "    if (!V8BindingSecurity::shouldAllowAccessToNode(V8BindingState::Only(), imp->" . $function->signature->name . "(ec)))\n");
1456         push(@implContentDecls, "        return v8::Handle<v8::Value>(v8::Null());\n");
1457 END
1458     }
1459
1460     my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
1461     push(@implContentDecls, $parameterCheckString);
1462
1463     # Build the function call string.
1464     push(@implContentDecls, GenerateFunctionCallString($function, $paramIndex, "    ", $implClassName, %replacements));
1465
1466     if ($raisesExceptions) {
1467         push(@implContentDecls, "    }\n");
1468         push(@implContentDecls, "    fail:\n");
1469         push(@implContentDecls, "    V8Proxy::setDOMException(ec, args.GetIsolate());\n");
1470         push(@implContentDecls, "    return v8::Handle<v8::Value>();\n");
1471     }
1472
1473     push(@implContentDecls, "}\n\n");
1474     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1475 }
1476
1477 sub GenerateCallWith
1478 {
1479     my $callWith = shift;
1480     return () unless $callWith;
1481     my $outputArray = shift;
1482     my $indent = shift;
1483     my $returnVoid = shift;
1484     my $emptyContext = shift;
1485     my $function = shift;
1486
1487     my @callWithArgs;
1488     if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
1489         if ($emptyContext) {
1490             push(@$outputArray, $indent . "EmptyScriptState state;\n");
1491             push(@callWithArgs, "&state");
1492         } else {
1493             push(@$outputArray, $indent . "ScriptState* state = ScriptState::current();\n");
1494             push(@$outputArray, $indent . "if (!state)\n");
1495             push(@$outputArray, $indent . "    return" . ($returnVoid ? "" : " v8::Undefined()") . ";\n");
1496             push(@callWithArgs, "state");
1497         }
1498     }
1499     if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptExecutionContext")) {
1500         push(@$outputArray, $indent . "ScriptExecutionContext* scriptContext = getScriptExecutionContext();\n");
1501         push(@$outputArray, $indent . "if (!scriptContext)\n");
1502         push(@$outputArray, $indent . "    return" . ($returnVoid ? "" : " v8::Undefined()") . ";\n");
1503         push(@callWithArgs, "scriptContext");
1504     }
1505     if ($function and $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments")) {
1506         push(@$outputArray, $indent . "RefPtr<ScriptArguments> scriptArguments(createScriptArguments(args, " . @{$function->parameters} . "));\n");
1507         push(@callWithArgs, "scriptArguments");
1508         AddToImplIncludes("ScriptArguments.h");
1509     }
1510     if ($codeGenerator->ExtendedAttributeContains($callWith, "CallStack")) {
1511         push(@$outputArray, $indent . "RefPtr<ScriptCallStack> callStack(createScriptCallStackForInspector());\n");
1512         push(@$outputArray, $indent . "if (!callStack)\n");
1513         push(@$outputArray, $indent . "    return v8::Undefined();\n");
1514         push(@callWithArgs, "callStack");
1515         AddToImplIncludes("ScriptCallStack.h");
1516         AddToImplIncludes("ScriptCallStackFactory.h");
1517     }
1518     return @callWithArgs;
1519 }
1520
1521 sub GenerateArgumentsCountCheck
1522 {
1523     my $function = shift;
1524     my $dataNode = shift;
1525
1526     my $numMandatoryParams = 0;
1527     my $optionalSeen = 0;
1528     foreach my $param (@{$function->parameters}) {
1529         if ($param->extendedAttributes->{"Optional"}) {
1530             $optionalSeen = 1;
1531         } else {
1532             die "An argument must not be declared to be optional unless all subsequent arguments to the operation are also optional." if $optionalSeen;
1533             $numMandatoryParams++;
1534         }
1535     }
1536
1537     my $argumentsCountCheckString = "";
1538     if ($numMandatoryParams >= 1) {
1539         $argumentsCountCheckString .= "    if (args.Length() < $numMandatoryParams)\n";
1540         $argumentsCountCheckString .= "        return V8Proxy::throwNotEnoughArgumentsError(args.GetIsolate());\n";
1541     }
1542     return $argumentsCountCheckString;
1543 }
1544
1545 sub GetIndexOf
1546 {
1547     my $paramName = shift;
1548     my @paramList = @_;
1549     my $index = 0;
1550     foreach my $param (@paramList) {
1551         if ($paramName eq $param) {
1552             return $index;
1553         }
1554         $index++;
1555     }
1556     return -1;
1557 }
1558
1559 sub GenerateParametersCheck
1560 {
1561     my $function = shift;
1562     my $implClassName = shift;
1563
1564     my $parameterCheckString = "";
1565     my $paramIndex = 0;
1566     my @paramTransferListNames = ();
1567     my %replacements = ();
1568
1569     foreach my $parameter (@{$function->parameters}) {
1570         TranslateParameter($parameter);
1571
1572         my $parameterName = $parameter->name;
1573
1574         # Optional arguments with [Optional] should generate an early call with fewer arguments.
1575         # Optional arguments with [Optional=...] should not generate the early call.
1576         my $optional = $parameter->extendedAttributes->{"Optional"};
1577         if ($optional && $optional ne "DefaultIsUndefined" && $optional ne "DefaultIsNullString" && !$parameter->extendedAttributes->{"Callback"}) {
1578             $parameterCheckString .= "    if (args.Length() <= $paramIndex) {\n";
1579             my $functionCall = GenerateFunctionCallString($function, $paramIndex, "    " x 2, $implClassName, %replacements);
1580             $parameterCheckString .= $functionCall;
1581             $parameterCheckString .= "    }\n";
1582         }
1583
1584         my $parameterDefaultPolicy = "DefaultIsUndefined";
1585         if ($optional and $optional eq "DefaultIsNullString") {
1586             $parameterDefaultPolicy = "DefaultIsNullString";
1587         }
1588
1589         if (GetIndexOf($parameterName, @paramTransferListNames) != -1) {
1590             $replacements{$parameterName} = "messagePortArray" . ucfirst($parameterName);
1591             $paramIndex++;
1592             next;
1593         }
1594
1595         AddToImplIncludes("ExceptionCode.h");
1596         my $nativeType = GetNativeTypeFromSignature($parameter, $paramIndex);
1597         if ($parameter->extendedAttributes->{"Callback"}) {
1598             my $className = GetCallbackClassName($parameter->type);
1599             AddToImplIncludes("$className.h");
1600             if ($optional) {
1601                 $parameterCheckString .= "    RefPtr<" . $parameter->type . "> $parameterName;\n";
1602                 $parameterCheckString .= "    if (args.Length() > $paramIndex && !args[$paramIndex]->IsNull() && !args[$paramIndex]->IsUndefined()) {\n";
1603                 $parameterCheckString .= "        if (!args[$paramIndex]->IsFunction())\n";
1604                 $parameterCheckString .= "            return throwError(TYPE_MISMATCH_ERR, args.GetIsolate());\n";
1605                 $parameterCheckString .= "        $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n";
1606                 $parameterCheckString .= "    }\n";
1607             } else {
1608                 $parameterCheckString .= "    if (args.Length() <= $paramIndex || !args[$paramIndex]->IsFunction())\n";
1609                 $parameterCheckString .= "        return throwError(TYPE_MISMATCH_ERR, args.GetIsolate());\n";
1610                 $parameterCheckString .= "    RefPtr<" . $parameter->type . "> $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n";
1611             }
1612         } elsif ($parameter->type eq "SerializedScriptValue") {
1613             AddToImplIncludes("SerializedScriptValue.h");
1614             my $useTransferList = 0;
1615             my $transferListName = "";
1616             my $TransferListName = "";
1617             if ($parameter->extendedAttributes->{"TransferList"}) {
1618                 $transferListName = $parameter->extendedAttributes->{"TransferList"};
1619                 push(@paramTransferListNames, $transferListName);
1620
1621                 my @allParameterNames = ();
1622                 foreach my $parameter (@{$function->parameters}) {
1623                     push(@allParameterNames, $parameter->name);
1624                 }
1625                 my $transferListIndex = GetIndexOf($transferListName, @allParameterNames);
1626                 if ($transferListIndex == -1) {
1627                     die "IDL error: TransferList refers to a nonexistent argument";
1628                 }
1629
1630                 AddToImplIncludes("wtf/ArrayBuffer.h");
1631                 AddToImplIncludes("MessagePort.h");
1632                 $TransferListName = ucfirst($transferListName);
1633                 $parameterCheckString .= "    MessagePortArray messagePortArray$TransferListName;\n";
1634                 $parameterCheckString .= "    ArrayBufferArray arrayBufferArray$TransferListName;\n";
1635                 $parameterCheckString .= "    if (args.Length() > $transferListIndex) {\n";
1636                 $parameterCheckString .= "        if (!extractTransferables(args[$transferListIndex], messagePortArray$TransferListName, arrayBufferArray$TransferListName))\n";
1637                 $parameterCheckString .= "            return V8Proxy::throwTypeError(\"Could not extract transferables\");\n";
1638                 $parameterCheckString .= "    }\n";
1639                 $useTransferList = 1;
1640             }
1641             $parameterCheckString .= "    bool ${parameterName}DidThrow = false;\n";
1642             if (!$useTransferList) {
1643                     $parameterCheckString .= "    $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], 0, 0, ${parameterName}DidThrow, args.GetIsolate());\n";
1644             } else {
1645                     $parameterCheckString .= "    $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], &messagePortArray$TransferListName, &arrayBufferArray$TransferListName, ${parameterName}DidThrow, args.GetIsolate());\n";
1646             }
1647             $parameterCheckString .= "    if (${parameterName}DidThrow)\n";
1648             $parameterCheckString .= "        return v8::Undefined();\n";
1649         } elsif (TypeCanFailConversion($parameter)) {
1650             $parameterCheckString .= "    $nativeType $parameterName = " .
1651                  JSValueToNative($parameter, "args[$paramIndex]", "args.GetIsolate()") . ";\n";
1652             $parameterCheckString .= "    if (UNLIKELY(!$parameterName)) {\n";
1653             $parameterCheckString .= "        ec = TYPE_MISMATCH_ERR;\n";
1654             $parameterCheckString .= "        goto fail;\n";
1655             $parameterCheckString .= "    }\n";
1656         } elsif ($nativeType =~ /^V8Parameter/) {
1657             my $value = JSValueToNative($parameter, "MAYBE_MISSING_PARAMETER(args, $paramIndex, $parameterDefaultPolicy)", "args.GetIsolate()");
1658             $parameterCheckString .= "    " . ConvertToV8Parameter($parameter, $nativeType, $parameterName, $value) . "\n";
1659         } else {
1660             AddToImplIncludes("V8BindingMacros.h");
1661             # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
1662             # interface type, then if the incoming value does not implement that interface, a TypeError
1663             # is thrown rather than silently passing NULL to the C++ code.
1664             # Per the Web IDL and ECMAScript specifications, incoming values can always be converted
1665             # to both strings and numbers, so do not throw TypeError if the argument is of these
1666             # types.
1667             if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
1668                 my $argValue = "args[$paramIndex]";
1669                 my $argType = GetTypeFromSignature($parameter);
1670                 if (IsWrapperType($argType)) {
1671                     $parameterCheckString .= "    if (args.Length() > $paramIndex && !isUndefinedOrNull($argValue) && !V8${argType}::HasInstance($argValue)) {\n";
1672                     $parameterCheckString .= "        V8Proxy::throwTypeError();\n";
1673                     $parameterCheckString .= "        return v8::Handle<v8::Value>();\n";
1674                     $parameterCheckString .= "    }\n";
1675                 }
1676             }
1677             $parameterCheckString .= "    EXCEPTION_BLOCK($nativeType, $parameterName, " .
1678                  JSValueToNative($parameter, "MAYBE_MISSING_PARAMETER(args, $paramIndex, $parameterDefaultPolicy)", "args.GetIsolate()") . ");\n";
1679             if ($nativeType eq 'Dictionary') {
1680                $parameterCheckString .= "    if (args.Length() > $paramIndex && !$parameterName.isUndefinedOrNull() && !$parameterName.isObject()) {\n";
1681                if (@{$function->raisesExceptions}) {
1682                    $parameterCheckString .= "        ec = TYPE_MISMATCH_ERR;\n";
1683                    $parameterCheckString .= "        V8Proxy::setDOMException(ec, args.GetIsolate());\n";
1684                }
1685                $parameterCheckString .= "        return V8Proxy::throwTypeError(\"Not an object.\");\n";
1686                $parameterCheckString .= "    }\n";
1687             }
1688         }
1689
1690         if ($parameter->extendedAttributes->{"IsIndex"}) {
1691             $parameterCheckString .= "    if (UNLIKELY($parameterName < 0)) {\n";
1692             $parameterCheckString .= "        ec = INDEX_SIZE_ERR;\n";
1693             $parameterCheckString .= "        goto fail;\n";
1694             $parameterCheckString .= "    }\n";
1695         }
1696
1697         $paramIndex++;
1698     }
1699     return ($parameterCheckString, $paramIndex, %replacements);
1700 }
1701
1702 sub GenerateConstructorCallback
1703 {
1704     my $function = shift;
1705     my $dataNode = shift;
1706     my $implClassName = shift;
1707
1708     my $raisesExceptions = @{$function->raisesExceptions};
1709     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1710         $raisesExceptions = 1;
1711     }
1712     if (!$raisesExceptions) {
1713         foreach my $parameter (@{$function->parameters}) {
1714             if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
1715                 $raisesExceptions = 1;
1716             }
1717         }
1718     }
1719
1720     my @beforeArgumentList;
1721     my @afterArgumentList;
1722     push(@implContent, <<END);
1723 v8::Handle<v8::Value> V8${implClassName}::constructorCallback(const v8::Arguments& args)
1724 {
1725     INC_STATS("DOM.${implClassName}.Constructor");
1726
1727     if (!args.IsConstructCall())
1728         return V8Proxy::throwTypeError("DOM object constructor cannot be called as a function.");
1729
1730     if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
1731         return args.Holder();
1732 END
1733
1734     push(@implContent, GenerateArgumentsCountCheck($function, $dataNode));
1735
1736     if ($raisesExceptions) {
1737         AddToImplIncludes("ExceptionCode.h");
1738         push(@implContent, "\n");
1739         push(@implContent, "    ExceptionCode ec = 0;\n");
1740     }
1741
1742     # FIXME: Currently [Constructor(...)] does not yet support [Optional] arguments.
1743     # It just supports [Optional=DefaultIsUndefined] or [Optional=DefaultIsNullString].
1744     my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
1745     push(@implContent, $parameterCheckString);
1746
1747     if ($dataNode->extendedAttributes->{"CallWith"} && $dataNode->extendedAttributes->{"CallWith"} eq "ScriptExecutionContext") {
1748         push(@beforeArgumentList, "context");
1749         push(@implContent, <<END);
1750
1751     ScriptExecutionContext* context = getScriptExecutionContext();
1752     if (!context)
1753         return V8Proxy::throwError(V8Proxy::ReferenceError, "${implClassName} constructor's associated context is not available", args.GetIsolate());
1754 END
1755     }
1756
1757     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1758         push(@afterArgumentList, "ec");
1759     }
1760
1761     my @argumentList;
1762     my $index = 0;
1763     foreach my $parameter (@{$function->parameters}) {
1764         last if $index eq $paramIndex;
1765         if ($replacements{$parameter->name}) {
1766             push(@argumentList, $replacements{$parameter->name});
1767         } else {
1768             push(@argumentList, $parameter->name);
1769         }
1770         $index++;
1771     }
1772
1773     my $argumentString = join(", ", @beforeArgumentList, @argumentList, @afterArgumentList);
1774     push(@implContent, "\n");
1775     push(@implContent, "    RefPtr<${implClassName}> impl = ${implClassName}::create(${argumentString});\n");
1776     push(@implContent, "    v8::Handle<v8::Object> wrapper = args.Holder();\n");
1777
1778     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1779         push(@implContent, "    if (ec)\n");
1780         push(@implContent, "        goto fail;\n");
1781     }
1782
1783     my $DOMObject = GetDomMapName($dataNode, $implClassName);
1784     push(@implContent, <<END);
1785
1786     V8DOMWrapper::setDOMWrapper(wrapper, &info, impl.get());
1787     V8DOMWrapper::setJSWrapperFor${DOMObject}(impl.release(), v8::Persistent<v8::Object>::New(wrapper), args.GetIsolate());
1788     return args.Holder();
1789 END
1790
1791     if ($raisesExceptions) {
1792         push(@implContent, "  fail:\n");
1793         push(@implContent, "    return throwError(ec, args.GetIsolate());\n");
1794     }
1795
1796     push(@implContent, "}\n");
1797     push(@implContent, "\n");
1798 }
1799
1800 sub GenerateEventConstructorCallback
1801 {
1802     my $dataNode = shift;
1803     my $implClassName = shift;
1804
1805     AddToImplIncludes("Dictionary.h");
1806     AddToImplIncludes("V8BindingMacros.h");
1807     push(@implContent, <<END);
1808 v8::Handle<v8::Value> V8${implClassName}::constructorCallback(const v8::Arguments& args)
1809 {
1810     INC_STATS("DOM.${implClassName}.Constructor");
1811
1812     if (!args.IsConstructCall())
1813         return V8Proxy::throwTypeError("DOM object constructor cannot be called as a function.");
1814
1815     if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
1816         return args.Holder();
1817
1818     if (args.Length() < 1)
1819         return V8Proxy::throwNotEnoughArgumentsError(args.GetIsolate());
1820
1821     STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, type, args[0]);
1822     ${implClassName}Init eventInit;
1823     if (args.Length() >= 2) {
1824         EXCEPTION_BLOCK(Dictionary, options, args[1]);
1825         if (!fill${implClassName}Init(eventInit, options))
1826             return v8::Undefined();
1827     }
1828
1829     RefPtr<${implClassName}> event = ${implClassName}::create(type, eventInit);
1830
1831     V8DOMWrapper::setDOMWrapper(args.Holder(), &info, event.get());
1832     V8DOMWrapper::setJSWrapperForDOMObject(event.release(), v8::Persistent<v8::Object>::New(args.Holder()), args.GetIsolate());
1833     return args.Holder();
1834 }
1835
1836 bool fill${implClassName}Init(${implClassName}Init& eventInit, const Dictionary& options)
1837 {
1838 END
1839
1840     foreach my $interfaceBase (@{$dataNode->parents}) {
1841         push(@implContent, <<END);
1842     if (!fill${interfaceBase}Init(eventInit, options))
1843         return false;
1844
1845 END
1846     }
1847
1848     for (my $index = 0; $index < @{$dataNode->attributes}; $index++) {
1849         my $attribute = @{$dataNode->attributes}[$index];
1850         if ($attribute->signature->extendedAttributes->{"InitializedByEventConstructor"}) {
1851             my $attributeName = $attribute->signature->name;
1852             push(@implContent, "    options.get(\"$attributeName\", eventInit.$attributeName);\n");
1853         }
1854     }
1855
1856     push(@implContent, <<END);
1857     return true;
1858 }
1859
1860 END
1861 }
1862
1863 sub GenerateNamedConstructorCallback
1864 {
1865     my $function = shift;
1866     my $dataNode = shift;
1867     my $implClassName = shift;
1868
1869     my $raisesExceptions = @{$function->raisesExceptions};
1870     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1871         $raisesExceptions = 1;
1872     }
1873     if (!$raisesExceptions) {
1874         foreach my $parameter (@{$function->parameters}) {
1875             if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
1876                 $raisesExceptions = 1;
1877             }
1878         }
1879     }
1880
1881     my @beforeArgumentList;
1882     my @afterArgumentList;
1883
1884     if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
1885         push(@implContent, <<END);
1886 WrapperTypeInfo V8${implClassName}Constructor::info = { V8${implClassName}Constructor::GetTemplate, V8${implClassName}::derefObject, V8${implClassName}::toActiveDOMObject, 0 };
1887
1888 END
1889     } else {
1890         push(@implContent, <<END);
1891 WrapperTypeInfo V8${implClassName}Constructor::info = { V8${implClassName}Constructor::GetTemplate, 0, 0, 0 };
1892
1893 END
1894     }
1895
1896     push(@implContent, <<END);
1897 static v8::Handle<v8::Value> V8${implClassName}ConstructorCallback(const v8::Arguments& args)
1898 {
1899     INC_STATS("DOM.${implClassName}.Constructor");
1900
1901     if (!args.IsConstructCall())
1902         return V8Proxy::throwTypeError("DOM object constructor cannot be called as a function.");
1903
1904     if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
1905         return args.Holder();
1906
1907     Frame* frame = V8Proxy::retrieveFrameForCurrentContext();
1908     if (!frame)
1909         return V8Proxy::throwError(V8Proxy::ReferenceError, "${implClassName} constructor associated frame is unavailable", args.GetIsolate());
1910
1911     Document* document = frame->document();
1912
1913     // Make sure the document is added to the DOM Node map. Otherwise, the ${implClassName} instance
1914     // may end up being the only node in the map and get garbage-collected prematurely.
1915     toV8(document, args.GetIsolate());
1916
1917 END
1918
1919     push(@implContent, GenerateArgumentsCountCheck($function, $dataNode));
1920
1921     if ($raisesExceptions) {
1922         AddToImplIncludes("ExceptionCode.h");
1923         push(@implContent, "\n");
1924         push(@implContent, "    ExceptionCode ec = 0;\n");
1925     }
1926
1927     my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
1928     push(@implContent, $parameterCheckString);
1929
1930     push(@beforeArgumentList, "document");
1931
1932     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1933         push(@afterArgumentList, "ec");
1934     }
1935
1936     my @argumentList;
1937     my $index = 0;
1938     foreach my $parameter (@{$function->parameters}) {
1939         last if $index eq $paramIndex;
1940         if ($replacements{$parameter->name}) {
1941             push(@argumentList, $replacements{$parameter->name});
1942         } else {
1943             push(@argumentList, $parameter->name);
1944         }
1945         $index++;
1946     }
1947
1948     my $argumentString = join(", ", @beforeArgumentList, @argumentList, @afterArgumentList);
1949     push(@implContent, "\n");
1950     push(@implContent, "    RefPtr<${implClassName}> impl = ${implClassName}::createForJSConstructor(${argumentString});\n");
1951     push(@implContent, "    v8::Handle<v8::Object> wrapper = args.Holder();\n");
1952
1953     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1954         push(@implContent, "    if (ec)\n");
1955         push(@implContent, "        goto fail;\n");
1956     }
1957
1958     my $DOMObject = GetDomMapName($dataNode, $implClassName);
1959     push(@implContent, <<END);
1960
1961     V8DOMWrapper::setDOMWrapper(wrapper, &V8${implClassName}Constructor::info, impl.get());
1962     V8DOMWrapper::setJSWrapperFor${DOMObject}(impl.release(), v8::Persistent<v8::Object>::New(wrapper), args.GetIsolate());
1963     return args.Holder();
1964 END
1965
1966     if ($raisesExceptions) {
1967         push(@implContent, "  fail:\n");
1968         push(@implContent, "    return throwError(ec, args.GetIsolate());\n");
1969     }
1970
1971     push(@implContent, "}\n");
1972
1973     push(@implContent, <<END);
1974
1975 v8::Persistent<v8::FunctionTemplate> V8${implClassName}Constructor::GetTemplate()
1976 {
1977     static v8::Persistent<v8::FunctionTemplate> cachedTemplate;
1978     if (!cachedTemplate.IsEmpty())
1979         return cachedTemplate;
1980
1981     v8::HandleScope scope;
1982     v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8${implClassName}ConstructorCallback);
1983
1984     v8::Local<v8::ObjectTemplate> instance = result->InstanceTemplate();
1985     instance->SetInternalFieldCount(V8${implClassName}::internalFieldCount);
1986     result->SetClassName(v8::String::New("${implClassName}"));
1987     result->Inherit(V8${implClassName}::GetTemplate());
1988
1989     cachedTemplate = v8::Persistent<v8::FunctionTemplate>::New(result);
1990     return cachedTemplate;
1991 }
1992
1993 END
1994 }
1995
1996 sub GenerateBatchedAttributeData
1997 {
1998     my $dataNode = shift;
1999     my $interfaceName = $dataNode->name;
2000     my $attributes = shift;
2001
2002     foreach my $attribute (@$attributes) {
2003         my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2004         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2005         GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", "");
2006         push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
2007     }
2008 }
2009
2010 sub GenerateSingleBatchedAttribute
2011 {
2012     my $interfaceName = shift;
2013     my $attribute = shift;
2014     my $delimiter = shift;
2015     my $indent = shift;
2016     my $attrName = $attribute->signature->name;
2017     my $attrExt = $attribute->signature->extendedAttributes;
2018
2019     my $accessControl = "v8::DEFAULT";
2020     if ($attrExt->{"DoNotCheckSecurityOnGetter"}) {
2021         $accessControl = "v8::ALL_CAN_READ";
2022     } elsif ($attrExt->{"DoNotCheckSecurityOnSetter"}) {
2023         $accessControl = "v8::ALL_CAN_WRITE";
2024     } elsif ($attrExt->{"DoNotCheckSecurity"}) {
2025         $accessControl = "v8::ALL_CAN_READ";
2026         if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) {
2027             $accessControl .= " | v8::ALL_CAN_WRITE";
2028         }
2029     }
2030     if ($attrExt->{"V8Unforgeable"}) {
2031         $accessControl .= " | v8::PROHIBITS_OVERWRITING";
2032     }
2033     $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")";
2034
2035     my $customAccessor =
2036         $attrExt->{"Custom"} ||
2037         $attrExt->{"CustomSetter"} ||
2038         $attrExt->{"CustomGetter"} ||
2039         $attrExt->{"V8Custom"} ||
2040         $attrExt->{"V8CustomSetter"} ||
2041         $attrExt->{"V8CustomGetter"} ||
2042         "";
2043     if ($customAccessor eq "VALUE_IS_MISSING") {
2044         # use the naming convension, interface + (capitalize) attr name
2045         $customAccessor = $interfaceName . "::" . $attrName;
2046     }
2047
2048     my $getter;
2049     my $setter;
2050     my $propAttr = "v8::None";
2051     my $hasCustomSetter = 0;
2052
2053     # Check attributes.
2054     if ($attrExt->{"NotEnumerable"}) {
2055         $propAttr .= " | v8::DontEnum";
2056     }
2057     if ($attrExt->{"V8Unforgeable"}) {
2058         $propAttr .= " | v8::DontDelete";
2059     }
2060
2061     my $on_proto = "0 /* on instance */";
2062     my $data = "0 /* no data */";
2063
2064     # Constructor
2065     if ($attribute->signature->type =~ /Constructor$/) {
2066         my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
2067         $constructorType =~ s/Constructor$//;
2068         # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
2069         # We do not generate the header file for NamedConstructor of class XXXX,
2070         # since we generate the NamedConstructor declaration into the header file of class XXXX.
2071         if ($constructorType !~ /Constructor$/ || $attribute->signature->extendedAttributes->{"V8CustomConstructor"} || $attribute->signature->extendedAttributes->{"CustomConstructor"}) {
2072             AddToImplIncludes("V8${constructorType}.h", $attribute->signature->extendedAttributes->{"Conditional"});
2073         }
2074         if ($customAccessor) {
2075             $getter = "V8${customAccessor}AccessorGetter";
2076         } else {
2077             $data = "&V8${constructorType}::info";
2078             $getter = "${interfaceName}V8Internal::${interfaceName}ConstructorGetter";
2079         }
2080         $setter = "0";
2081         $propAttr = "v8::ReadOnly";
2082
2083     } else {
2084         # Default Getter and Setter
2085         $getter = "${interfaceName}V8Internal::${attrName}AttrGetter";
2086         $setter = "${interfaceName}V8Internal::${attrName}AttrSetter";
2087
2088         # Custom Setter
2089         if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
2090             $hasCustomSetter = 1;
2091             $setter = "V8${customAccessor}AccessorSetter";
2092         }
2093
2094         # Custom Getter
2095         if ($attrExt->{"CustomGetter"} || $attrExt->{"V8CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
2096             $getter = "V8${customAccessor}AccessorGetter";
2097         }
2098     }
2099
2100     # Replaceable
2101     if ($attrExt->{"Replaceable"} && !$hasCustomSetter) {
2102         $setter = "0";
2103         # Handle the special case of window.top being marked as Replaceable.
2104         # FIXME: Investigate whether we could treat window.top as replaceable
2105         # and allow shadowing without it being a security hole.
2106         if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) {
2107             $propAttr .= " | v8::ReadOnly";
2108         }
2109     }
2110
2111     # Read only attributes
2112     if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) {
2113         $setter = "0";
2114     }
2115
2116     # An accessor can be installed on the proto
2117     if ($attrExt->{"V8OnProto"}) {
2118         $on_proto = "1 /* on proto */";
2119     }
2120
2121     my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type .
2122                       "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
2123
2124     push(@implContent, $indent . "    \/\/ $commentInfo\n");
2125     push(@implContent, $indent . "    {\"$attrName\", $getter, $setter, $data, $accessControl, static_cast<v8::PropertyAttribute>($propAttr), $on_proto}" . $delimiter . "\n");
2126 }
2127
2128 sub GenerateImplementationIndexer
2129 {
2130     my $dataNode = shift;
2131     my $indexer = shift;
2132     my $interfaceName = $dataNode->name;
2133
2134     # FIXME: Figure out what NumericIndexedGetter is really supposed to do. Right now, it's only set on WebGL-related files.
2135     my $hasCustomSetter = $dataNode->extendedAttributes->{"CustomIndexedSetter"} && !$dataNode->extendedAttributes->{"NumericIndexedGetter"};
2136     my $hasGetter = $dataNode->extendedAttributes->{"IndexedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
2137
2138     # FIXME: Investigate and remove this nastinesss. In V8, named property handling and indexer handling are apparently decoupled,
2139     # which means that object[X] where X is a number doesn't reach named property indexer. So we need to provide
2140     # simplistic, mirrored indexer handling in addition to named property handling.
2141     my $isSpecialCase = exists $indexerSpecialCases{$interfaceName};
2142     if ($isSpecialCase) {
2143         $hasGetter = 1;
2144         if ($dataNode->extendedAttributes->{"CustomNamedSetter"}) {
2145             $hasCustomSetter = 1;
2146         }
2147     }
2148
2149     my $hasEnumerator = !$isSpecialCase && IsNodeSubType($dataNode);
2150
2151     # FIXME: Find a way to not have to special-case HTMLOptionsCollection.
2152     if ($interfaceName eq "HTMLOptionsCollection") {
2153         $hasEnumerator = 1;
2154         $hasGetter = 1;
2155     }
2156
2157     if (!$hasGetter) {
2158         return;
2159     }
2160
2161     AddToImplIncludes("V8Collection.h");
2162
2163     if (!$indexer) {
2164         $indexer = $codeGenerator->FindSuperMethod($dataNode, "item");
2165     }
2166
2167     my $indexerType = $indexer ? $indexer->type : 0;
2168
2169     # FIXME: Remove this once toV8 helper methods are implemented (see https://bugs.webkit.org/show_bug.cgi?id=32563).
2170     if ($interfaceName eq "WebKitCSSKeyframesRule") {
2171         $indexerType = "WebKitCSSKeyframeRule";
2172     }
2173
2174     if ($indexerType && !$hasCustomSetter) {
2175         if ($indexerType eq "DOMString") {
2176             my $conversion = $indexer->extendedAttributes->{"TreatReturnedNullStringAs"};
2177             if ($conversion && $conversion eq "Null") {
2178                 push(@implContent, <<END);
2179     setCollectionStringOrNullIndexedGetter<${interfaceName}>(desc);
2180 END
2181             } else {
2182                 push(@implContent, <<END);
2183     setCollectionStringIndexedGetter<${interfaceName}>(desc);
2184 END
2185             }
2186         } else {
2187             push(@implContent, <<END);
2188     setCollectionIndexedGetter<${interfaceName}, ${indexerType}>(desc);
2189 END
2190             # Include the header for this indexer type, because setCollectionIndexedGetter() requires toV8() for this type.
2191             AddToImplIncludes("V8${indexerType}.h");
2192         }
2193
2194         return;
2195     }
2196
2197     my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
2198     my $setOn = "Instance";
2199
2200     # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
2201     # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
2202     # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
2203     # on the object.
2204     if ($interfaceName eq "DOMWindow") {
2205         $setOn = "Prototype";
2206         $hasDeleter = 0;
2207     }
2208
2209     push(@implContent, "    desc->${setOn}Template()->SetIndexedPropertyHandler(V8${interfaceName}::indexedPropertyGetter");
2210     push(@implContent, $hasCustomSetter ? ", V8${interfaceName}::indexedPropertySetter" : ", 0");
2211     push(@implContent, ", 0"); # IndexedPropertyQuery -- not being used at the moment.
2212     push(@implContent, $hasDeleter ? ", V8${interfaceName}::indexedPropertyDeleter" : ", 0");
2213     push(@implContent, ", nodeCollectionIndexedPropertyEnumerator<${interfaceName}>") if $hasEnumerator;
2214     push(@implContent, ");\n");
2215 }
2216
2217 sub GenerateImplementationNamedPropertyGetter
2218 {
2219     my $dataNode = shift;
2220     my $namedPropertyGetter = shift;
2221     my $interfaceName = $dataNode->name;
2222     my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"CustomNamedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
2223
2224     # FIXME: Remove hard-coded HTMLOptionsCollection reference by changing HTMLOptionsCollection to not inherit
2225     # from HTMLCollection per W3C spec (http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#HTMLOptionsCollection).
2226     if ($interfaceName eq "HTMLOptionsCollection") {
2227         $interfaceName = "HTMLCollection";
2228         $hasCustomNamedGetter = 1;
2229     }
2230
2231     if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
2232         $hasCustomNamedGetter = 1;
2233     }
2234
2235     if ($interfaceName eq "HTMLDocument") {
2236         $hasCustomNamedGetter = 0;
2237     }
2238
2239     my $hasGetter = $dataNode->extendedAttributes->{"NamedGetter"} || $hasCustomNamedGetter;
2240     if (!$hasGetter) {
2241         return;
2242     }
2243
2244     if (!$namedPropertyGetter) {
2245         $namedPropertyGetter = $codeGenerator->FindSuperMethod($dataNode, "namedItem");
2246     }
2247
2248     if ($namedPropertyGetter && $namedPropertyGetter->type ne "Node" && !$namedPropertyGetter->extendedAttributes->{"Custom"} && !$hasCustomNamedGetter) {
2249         AddToImplIncludes("V8Collection.h");
2250         my $type = $namedPropertyGetter->type;
2251         push(@implContent, <<END);
2252     setCollectionNamedGetter<${interfaceName}, ${type}>(desc);
2253 END
2254         return;
2255     }
2256
2257     my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"CustomNamedSetter"};
2258     my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
2259     my $hasEnumerator = $dataNode->extendedAttributes->{"CustomEnumerateProperty"};
2260     my $setOn = "Instance";
2261
2262     # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
2263     # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
2264     # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
2265     # on the object.
2266     if ($interfaceName eq "DOMWindow") {
2267         $setOn = "Prototype";
2268         $hasDeleter = 0;
2269         $hasEnumerator = 0;
2270     }
2271
2272     push(@implContent, "    desc->${setOn}Template()->SetNamedPropertyHandler(V8${interfaceName}::namedPropertyGetter, ");
2273     push(@implContent, $hasCustomNamedSetter ? "V8${interfaceName}::namedPropertySetter, " : "0, ");
2274     # If there is a custom enumerator, there MUST be custom query to properly communicate property attributes.
2275     push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyQuery, " : "0, ");
2276     push(@implContent, $hasDeleter ? "V8${interfaceName}::namedPropertyDeleter, " : "0, ");
2277     push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyEnumerator" : "0");
2278     push(@implContent, ");\n");
2279 }
2280
2281 sub GenerateImplementationCustomCall
2282 {
2283     my $dataNode = shift;
2284     my $interfaceName = $dataNode->name;
2285     my $hasCustomCall = $dataNode->extendedAttributes->{"CustomCall"};
2286
2287     if ($hasCustomCall) {
2288         push(@implContent, "    desc->InstanceTemplate()->SetCallAsFunctionHandler(V8${interfaceName}::callAsFunctionCallback);\n");
2289     }
2290 }
2291
2292 sub GenerateImplementationMasqueradesAsUndefined
2293 {
2294     my $dataNode = shift;
2295     if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"})
2296     {
2297         push(@implContent, "    desc->InstanceTemplate()->MarkAsUndetectable();\n");
2298     }
2299 }
2300
2301 sub IsTypedArrayType
2302 {
2303     my $type = shift;
2304     return 1 if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView"));
2305     return 1 if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array"));
2306     return 1 if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array"));
2307     return 1 if (($type eq "Float32Array") or ($type eq "Float64Array"));
2308     return 0;
2309 }
2310
2311
2312 sub GenerateImplementation
2313 {
2314     my $object = shift;
2315     my $dataNode = shift;
2316     my $interfaceName = $dataNode->name;
2317     my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($dataNode);
2318     my $className = "V8$interfaceName";
2319     my $implClassName = $interfaceName;
2320
2321     # - Add default header template
2322     push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
2323
2324     AddToImplIncludes("RuntimeEnabledFeatures.h");
2325     AddToImplIncludes("ContextEnabledFeatures.h");
2326     AddToImplIncludes("V8Proxy.h");
2327     AddToImplIncludes("V8Binding.h");
2328     AddToImplIncludes("V8BindingState.h");
2329     AddToImplIncludes("V8DOMWrapper.h");
2330     AddToImplIncludes("V8IsolatedContext.h");
2331
2332     AddIncludesForType($interfaceName);
2333
2334     my $toActive = $dataNode->extendedAttributes->{"ActiveDOMObject"} ? "${className}::toActiveDOMObject" : "0";
2335
2336     # Find the super descriptor.
2337     my $parentClass = "";
2338     my $parentClassTemplate = "";
2339     foreach (@{$dataNode->parents}) {
2340         my $parent = $codeGenerator->StripModule($_);
2341         if ($parent eq "EventTarget") {
2342             next;
2343         }
2344         AddToImplIncludes("V8${parent}.h");
2345         $parentClass = "V8" . $parent;
2346         $parentClassTemplate = $parentClass . "::GetTemplate()";
2347         last;
2348     }
2349     push(@implContentDecls, "namespace WebCore {\n\n");
2350     my $parentClassInfo = $parentClass ? "&${parentClass}::info" : "0";
2351     push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, ${toActive}, ${parentClassInfo} };\n\n");   
2352     push(@implContentDecls, "namespace ${interfaceName}V8Internal {\n\n");
2353     push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");
2354
2355     my $hasConstructors = 0;
2356     # Generate property accessors for attributes.
2357     for (my $index = 0; $index < @{$dataNode->attributes}; $index++) {
2358         my $attribute = @{$dataNode->attributes}[$index];
2359         my $attrType = $attribute->signature->type;
2360
2361         # Generate special code for the constructor attributes.
2362         if ($attrType =~ /Constructor$/) {
2363             if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
2364                 $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
2365                 $hasConstructors = 1;
2366             }
2367             next;
2368         }
2369
2370         if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") {
2371             $attribute->signature->extendedAttributes->{"V8OnProto"} = 1;
2372         }
2373
2374         if ($attrType eq "SerializedScriptValue") {
2375             AddToImplIncludes("SerializedScriptValue.h");
2376         }
2377
2378         # Do not generate accessor if this is a custom attribute.  The
2379         # call will be forwarded to a hand-written accessor
2380         # implementation.
2381         if ($attribute->signature->extendedAttributes->{"Custom"} ||
2382             $attribute->signature->extendedAttributes->{"V8Custom"}) {
2383             next;
2384         }
2385
2386         # Generate the accessor.
2387         if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
2388             $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
2389             GenerateNormalAttrGetter($attribute, $dataNode, $implClassName, $interfaceName);
2390         }
2391         if (!$attribute->signature->extendedAttributes->{"CustomSetter"} &&
2392             !$attribute->signature->extendedAttributes->{"V8CustomSetter"} &&
2393             !$attribute->signature->extendedAttributes->{"Replaceable"} &&
2394             $attribute->type !~ /^readonly/ &&
2395             !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) {
2396             GenerateNormalAttrSetter($attribute, $dataNode, $implClassName, $interfaceName);
2397         }
2398     }
2399
2400     if ($hasConstructors) {
2401         GenerateConstructorGetter($dataNode, $implClassName);
2402     }
2403
2404     my $indexer;
2405     my $namedPropertyGetter;
2406     # Generate methods for functions.
2407     foreach my $function (@{$dataNode->functions}) {
2408         my $isCustom = $function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"};
2409         if (!$isCustom) {
2410             GenerateFunctionCallback($function, $dataNode, $implClassName);
2411             if ($function->{overloadIndex} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) {
2412                 GenerateOverloadedFunctionCallback($function, $dataNode, $implClassName);
2413             }
2414         }
2415
2416         if ($function->signature->name eq "item") {
2417             $indexer = $function->signature;
2418         }
2419
2420         if ($function->signature->name eq "namedItem") {
2421             $namedPropertyGetter = $function->signature;
2422         }
2423
2424         # If the function does not need domain security check, we need to
2425         # generate an access getter that returns different function objects
2426         # for different calling context.
2427         if (($dataNode->extendedAttributes->{"CheckSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2428             if (!$isCustom || $function->{overloadIndex} == 1) {
2429                 GenerateDomainSafeFunctionGetter($function, $implClassName);
2430             }
2431         }
2432     }
2433
2434     # Attributes
2435     my $attributes = $dataNode->attributes;
2436
2437     # For the DOMWindow interface we partition the attributes into the
2438     # ones that disallows shadowing and the rest.
2439     my @disallowsShadowing;
2440     # Also separate out attributes that are enabled at runtime so we can process them specially.
2441     my @enabledAtRuntime;
2442     my @enabledPerContext;
2443     my @normal;
2444     foreach my $attribute (@$attributes) {
2445
2446         if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"V8Unforgeable"}) {
2447             push(@disallowsShadowing, $attribute);
2448         } elsif ($attribute->signature->extendedAttributes->{"V8EnabledAtRuntime"}) {
2449             push(@enabledAtRuntime, $attribute);
2450         } elsif ($attribute->signature->extendedAttributes->{"V8EnabledPerContext"}) {
2451             push(@enabledPerContext, $attribute);
2452         } else {
2453             push(@normal, $attribute);
2454         }
2455     }
2456     $attributes = \@normal;
2457     # Put the attributes that disallow shadowing on the shadow object.
2458     if (@disallowsShadowing) {
2459         push(@implContent, "static const BatchedAttribute shadowAttrs[] = {\n");
2460         GenerateBatchedAttributeData($dataNode, \@disallowsShadowing);
2461         push(@implContent, "};\n\n");
2462     }
2463
2464     my $has_attributes = 0;
2465     if (@$attributes) {
2466         $has_attributes = 1;
2467         push(@implContent, "static const BatchedAttribute ${interfaceName}Attrs[] = {\n");
2468         GenerateBatchedAttributeData($dataNode, $attributes);
2469         push(@implContent, "};\n\n");
2470     }
2471
2472     # Setup table of standard callback functions
2473     my $num_callbacks = 0;
2474     my $has_callbacks = 0;
2475     foreach my $function (@{$dataNode->functions}) {
2476         # Only one table entry is needed for overloaded methods:
2477         next if $function->{overloadIndex} > 1;
2478
2479         my $attrExt = $function->signature->extendedAttributes;
2480         # Don't put any nonstandard functions into this table:
2481         if ($attrExt->{"V8Unforgeable"}) {
2482             next;
2483         }
2484         if ($function->isStatic) {
2485             next;
2486         }
2487         if ($attrExt->{"V8EnabledAtRuntime"} || RequiresCustomSignature($function) || $attrExt->{"V8DoNotCheckSignature"}) {
2488             next;
2489         }
2490         if ($attrExt->{"DoNotCheckSecurity"} &&
2491             ($dataNode->extendedAttributes->{"CheckSecurity"} || $interfaceName eq "DOMWindow")) {
2492             next;
2493         }
2494         if ($attrExt->{"NotEnumerable"} || $attrExt->{"V8ReadOnly"}) {
2495             next;
2496         }
2497         if (!$has_callbacks) {
2498             $has_callbacks = 1;
2499             push(@implContent, "static const BatchedCallback ${interfaceName}Callbacks[] = {\n");
2500         }
2501         my $name = $function->signature->name;
2502         my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
2503         my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2504         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2505         push(@implContent, <<END);
2506     {"$name", $callback},
2507 END
2508         push(@implContent, "#endif\n") if $conditionalString;
2509         $num_callbacks++;
2510     }
2511     push(@implContent, "};\n\n")  if $has_callbacks;
2512
2513     # Setup constants
2514     my $has_constants = 0;
2515     my @constantsEnabledAtRuntime;
2516     if (@{$dataNode->constants}) {
2517         $has_constants = 1;
2518         push(@implContent, "static const BatchedConstant ${interfaceName}Consts[] = {\n");
2519     }
2520     foreach my $constant (@{$dataNode->constants}) {
2521         my $name = $constant->name;
2522         my $value = $constant->value;
2523         my $attrExt = $constant->extendedAttributes;
2524         my $conditional = $attrExt->{"Conditional"};
2525         my $implementedBy = $attrExt->{"ImplementedBy"};
2526         if ($implementedBy) {
2527             AddToImplIncludes("${implementedBy}.h");
2528         }
2529         if ($attrExt->{"V8EnabledAtRuntime"}) {
2530             push(@constantsEnabledAtRuntime, $constant);
2531         } else {
2532             # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl
2533             # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF".  It would be better if we
2534             # handled this here, and converted it to a -1 constant in the c++ output.
2535             if ($conditional) {
2536                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2537                 push(@implContent, "#if ${conditionalString}\n");
2538             }
2539             push(@implContent, <<END);
2540     {"${name}", static_cast<signed int>($value)},
2541 END
2542             push(@implContent, "#endif\n") if $conditional;
2543         }
2544     }
2545     if ($has_constants) {
2546         push(@implContent, "};\n\n");
2547         push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode));
2548     }
2549
2550     push(@implContentDecls, "} // namespace ${interfaceName}V8Internal\n\n");
2551
2552     if ($dataNode->extendedAttributes->{"NamedConstructor"} && !($dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
2553         GenerateNamedConstructorCallback($dataNode->constructor, $dataNode, $interfaceName);
2554     } elsif ($dataNode->extendedAttributes->{"Constructor"} && !($dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
2555         GenerateConstructorCallback($dataNode->constructor, $dataNode, $interfaceName);
2556     } elsif (IsConstructorTemplate($dataNode, "Event")) {
2557         GenerateEventConstructorCallback($dataNode, $interfaceName);
2558     }
2559
2560     my $access_check = "";
2561     if ($dataNode->extendedAttributes->{"CheckSecurity"} && !($interfaceName eq "DOMWindow")) {
2562         $access_check = "instance->SetAccessCheckCallbacks(V8${interfaceName}::namedSecurityCheck, V8${interfaceName}::indexedSecurityCheck, v8::External::Wrap(&V8${interfaceName}::info));";
2563     }
2564
2565     # For the DOMWindow interface, generate the shadow object template
2566     # configuration method.
2567     if ($implClassName eq "DOMWindow") {
2568         push(@implContent, <<END);
2569 static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ)
2570 {
2571     batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs));
2572
2573     // Install a security handler with V8.
2574     templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info));
2575     templ->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
2576     return templ;
2577 }
2578 END
2579     }
2580
2581     if (!$parentClassTemplate) {
2582         $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()";
2583     }
2584
2585     # Generate the template configuration method
2586     push(@implContent,  <<END);
2587 static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc)
2588 {
2589     desc->ReadOnlyPrototype();
2590
2591     v8::Local<v8::Signature> defaultSignature;
2592 END
2593     if ($dataNode->extendedAttributes->{"V8EnabledAtRuntime"}) {
2594         my $enable_function = GetRuntimeEnableFunctionName($dataNode);
2595         push(@implContent, <<END);
2596     if (!${enable_function}())
2597         defaultSignature = configureTemplate(desc, \"\", $parentClassTemplate, V8${interfaceName}::internalFieldCount, 0, 0, 0, 0);
2598     else
2599 END
2600     }
2601     push(@implContent,  <<END);
2602     defaultSignature = configureTemplate(desc, \"${visibleInterfaceName}\", $parentClassTemplate, V8${interfaceName}::internalFieldCount,
2603 END
2604     # Set up our attributes if we have them
2605     if ($has_attributes) {
2606         push(@implContent, <<END);
2607         ${interfaceName}Attrs, WTF_ARRAY_LENGTH(${interfaceName}Attrs),
2608 END
2609     } else {
2610         push(@implContent, <<END);
2611         0, 0,
2612 END
2613     }
2614
2615     if ($has_callbacks) {
2616         push(@implContent, <<END);
2617         ${interfaceName}Callbacks, WTF_ARRAY_LENGTH(${interfaceName}Callbacks));
2618 END
2619     } else {
2620         push(@implContent, <<END);
2621         0, 0);
2622 END
2623     }
2624     
2625     AddToImplIncludes("wtf/UnusedParam.h");
2626     push(@implContent, <<END);
2627     UNUSED_PARAM(defaultSignature); // In some cases, it will not be used.
2628 END
2629
2630     if (IsConstructable($dataNode)) {
2631         push(@implContent, <<END);
2632     desc->SetCallHandler(V8${interfaceName}::constructorCallback);
2633 END
2634     }
2635
2636     if ($access_check or @enabledAtRuntime or @{$dataNode->functions} or $has_constants) {
2637         push(@implContent,  <<END);
2638     v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
2639     v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate();
2640     UNUSED_PARAM(instance); // In some cases, it will not be used.
2641     UNUSED_PARAM(proto); // In some cases, it will not be used.
2642 END
2643     }
2644
2645     push(@implContent,  "    $access_check\n");
2646
2647     # Setup the enable-at-runtime attrs if we have them
2648     foreach my $runtime_attr (@enabledAtRuntime) {
2649         my $enable_function = GetRuntimeEnableFunctionName($runtime_attr->signature);
2650         my $conditionalString = $codeGenerator->GenerateConditionalString($runtime_attr->signature);
2651         push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
2652         push(@implContent, "    if (${enable_function}()) {\n");
2653         push(@implContent, "        static const BatchedAttribute attrData =\\\n");
2654         GenerateSingleBatchedAttribute($interfaceName, $runtime_attr, ";", "    ");
2655         push(@implContent, <<END);
2656         configureAttribute(instance, proto, attrData);
2657     }
2658 END
2659         push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2660     }
2661
2662     # Setup the enable-at-runtime constants if we have them
2663     foreach my $runtime_const (@constantsEnabledAtRuntime) {
2664         my $enable_function = GetRuntimeEnableFunctionName($runtime_const);
2665         my $conditionalString = $codeGenerator->GenerateConditionalString($runtime_const);
2666         my $name = $runtime_const->name;
2667         my $value = $runtime_const->value;
2668         push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
2669         push(@implContent, "    if (${enable_function}()) {\n");
2670         push(@implContent, <<END);
2671         static const BatchedConstant constData = {"${name}", static_cast<signed int>(${value})};
2672         batchConfigureConstants(desc, proto, &constData, 1);
2673 END
2674         push(@implContent, "    }\n");
2675         push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2676     }
2677
2678     GenerateImplementationIndexer($dataNode, $indexer);
2679     GenerateImplementationNamedPropertyGetter($dataNode, $namedPropertyGetter);
2680     GenerateImplementationCustomCall($dataNode);
2681     GenerateImplementationMasqueradesAsUndefined($dataNode);
2682
2683     # Define our functions with Set() or SetAccessor()
2684     my $total_functions = 0;
2685     foreach my $function (@{$dataNode->functions}) {
2686         # Only one accessor is needed for overloaded methods:
2687         next if $function->{overloadIndex} > 1;
2688
2689         $total_functions++;
2690         my $attrExt = $function->signature->extendedAttributes;
2691         my $name = $function->signature->name;
2692
2693         my $property_attributes = "v8::DontDelete";
2694         if ($attrExt->{"NotEnumerable"}) {
2695             $property_attributes .= " | v8::DontEnum";
2696         }
2697         if ($attrExt->{"V8ReadOnly"}) {
2698             $property_attributes .= " | v8::ReadOnly";
2699         }
2700
2701         my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
2702
2703         my $template = "proto";
2704         if ($attrExt->{"V8Unforgeable"}) {
2705             $template = "instance";
2706         }
2707         if ($function->isStatic) {
2708             $template = "desc";
2709         }
2710
2711         my $conditional = "";
2712         if ($attrExt->{"V8EnabledAtRuntime"}) {
2713             # Only call Set()/SetAccessor() if this method should be enabled
2714             my $enable_function = GetRuntimeEnableFunctionName($function->signature);
2715             $conditional = "if (${enable_function}())\n        ";
2716         }
2717
2718         if ($attrExt->{"DoNotCheckSecurity"} &&
2719             ($dataNode->extendedAttributes->{"CheckSecurity"} || $interfaceName eq "DOMWindow")) {
2720             # Mark the accessor as ReadOnly and set it on the proto object so
2721             # it can be shadowed. This is really a hack to make it work.
2722             # There are several sceneria to call into the accessor:
2723             #   1) from the same domain: "window.open":
2724             #      the accessor finds the DOM wrapper in the proto chain;
2725             #   2) from the same domain: "window.__proto__.open":
2726             #      the accessor will NOT find a DOM wrapper in the prototype chain
2727             #   3) from another domain: "window.open":
2728             #      the access find the DOM wrapper in the prototype chain
2729             #   "window.__proto__.open" from another domain will fail when
2730             #   accessing '__proto__'
2731             #
2732             # The solution is very hacky and fragile, it really needs to be replaced
2733             # by a better solution.
2734             $property_attributes .= " | v8::ReadOnly";
2735             push(@implContent, <<END);
2736
2737     // $commentInfo
2738     ${conditional}$template->SetAccessor(v8::String::New("$name"), ${interfaceName}V8Internal::${name}AttrGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>($property_attributes));
2739 END
2740             $num_callbacks++;
2741             next;
2742         }
2743
2744         my $signature = "defaultSignature";
2745         if ($attrExt->{"V8DoNotCheckSignature"} || $function->isStatic) {
2746             $signature = "v8::Local<v8::Signature>()";
2747         }
2748
2749         if (RequiresCustomSignature($function)) {
2750             $signature = "${name}Signature";
2751             push(@implContent, "\n    // Custom Signature '$name'\n", CreateCustomSignature($function));
2752         }
2753
2754         # Normal function call is a template
2755         my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
2756
2757         if ($property_attributes eq "v8::DontDelete") {
2758             $property_attributes = "";
2759         } else {
2760             $property_attributes = ", static_cast<v8::PropertyAttribute>($property_attributes)";
2761         }
2762
2763         if ($template eq "proto" && $conditional eq "" && $signature eq "defaultSignature" && $property_attributes eq "") {
2764             # Standard type of callback, already created in the batch, so skip it here.
2765             next;
2766         }
2767
2768         my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2769         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2770
2771         push(@implContent, <<END);
2772     ${conditional}$template->Set(v8::String::New("$name"), v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), ${signature})$property_attributes);
2773 END
2774
2775         push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
2776         $num_callbacks++;
2777     }
2778
2779     die "Wrong number of callbacks generated for $interfaceName ($num_callbacks, should be $total_functions)" if $num_callbacks != $total_functions;
2780
2781     if ($has_constants) {
2782         push(@implContent, <<END);
2783     batchConfigureConstants(desc, proto, ${interfaceName}Consts, WTF_ARRAY_LENGTH(${interfaceName}Consts));
2784 END
2785     }
2786
2787     # Special cases
2788     if ($interfaceName eq "DOMWindow") {
2789         push(@implContent, <<END);
2790
2791     proto->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
2792     desc->SetHiddenPrototype(true);
2793     instance->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
2794     // Set access check callbacks, but turned off initially.
2795     // When a context is detached from a frame, turn on the access check.
2796     // Turning on checks also invalidates inline caches of the object.
2797     instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false);
2798 END
2799     }
2800     if ($interfaceName eq "HTMLDocument") {
2801         push(@implContent, <<END);
2802     desc->SetHiddenPrototype(true);
2803 END
2804     }
2805     if ($interfaceName eq "Location") {
2806         push(@implContent, <<END);
2807
2808     // For security reasons, these functions are on the instance instead
2809     // of on the prototype object to ensure that they cannot be overwritten.
2810     instance->SetAccessor(v8::String::New("reload"), V8Location::reloadAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
2811     instance->SetAccessor(v8::String::New("replace"), V8Location::replaceAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
2812     instance->SetAccessor(v8::String::New("assign"), V8Location::assignAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
2813 END
2814     }
2815
2816     my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
2817     push(@implContent, <<END);
2818
2819     // Custom toString template
2820     desc->Set(getToStringName(), getToStringTemplate());
2821     return desc;
2822 }
2823
2824 v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate()
2825 {
2826     V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
2827     V8BindingPerIsolateData::TemplateMap::iterator result = data->rawTemplateMap().find(&info);
2828     if (result != data->rawTemplateMap().end())
2829         return result->second;
2830
2831     v8::HandleScope handleScope;
2832     v8::Persistent<v8::FunctionTemplate> templ = createRawTemplate();
2833     data->rawTemplateMap().add(&info, templ);
2834     return templ;
2835 }
2836
2837 v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()
2838 {
2839     V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
2840     V8BindingPerIsolateData::TemplateMap::iterator result = data->templateMap().find(&info);
2841     if (result != data->templateMap().end())
2842         return result->second;
2843
2844     v8::HandleScope handleScope;
2845     v8::Persistent<v8::FunctionTemplate> templ =
2846         Configure${className}Template(GetRawTemplate());
2847     data->templateMap().add(&info, templ);
2848     return templ;
2849 }
2850
2851 bool ${className}::HasInstance(v8::Handle<v8::Value> value)
2852 {
2853     return GetRawTemplate()->HasInstance(value);
2854 }
2855
2856 END
2857
2858     if (@enabledPerContext) {
2859         push(@implContent, <<END);
2860 void ${className}::installPerContextProperties(v8::Handle<v8::Object> instance, ${implClassName}* impl)
2861 {
2862     v8::Local<v8::Object> proto = v8::Local<v8::Object>::Cast(instance->GetPrototype());
2863 END
2864         # Setup the enable-by-settings attrs if we have them
2865         foreach my $runtimeAttr (@enabledPerContext) {
2866             my $enableFunction = GetContextEnableFunction($runtimeAttr->signature);
2867             my $conditionalString = $codeGenerator->GenerateConditionalString($runtimeAttr->signature);
2868             push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
2869             push(@implContent, "    if (ContextEnabledFeatures::${enableFunction}(impl)) {\n");
2870             push(@implContent, "        static const BatchedAttribute attrData =\\\n");
2871             GenerateSingleBatchedAttribute($interfaceName, $runtimeAttr, ";", "    ");
2872             push(@implContent, <<END);
2873         configureAttribute(instance, proto, attrData);
2874 END
2875             push(@implContent, "    }\n");
2876             push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
2877         }
2878
2879         push(@implContent, <<END);
2880 }
2881 END
2882     }
2883
2884     if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
2885         # MessagePort is handled like an active dom object even though it doesn't inherit
2886         # from ActiveDOMObject, so don't try to cast it to ActiveDOMObject.
2887         my $returnValue = $interfaceName eq "MessagePort" ? "0" : "toNative(object)";
2888         push(@implContent, <<END);
2889 ActiveDOMObject* ${className}::toActiveDOMObject(v8::Handle<v8::Object> object)
2890 {
2891     return ${returnValue};
2892 }      
2893 END
2894     }
2895
2896     if ($implClassName eq "DOMWindow") {
2897         push(@implContent, <<END);
2898 v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate()
2899 {
2900     static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObjectCache;
2901     if (V8DOMWindowShadowObjectCache.IsEmpty()) {
2902         V8DOMWindowShadowObjectCache = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
2903         ConfigureShadowObjectTemplate(V8DOMWindowShadowObjectCache);
2904     }
2905     return V8DOMWindowShadowObjectCache;
2906 }
2907 END
2908     }
2909
2910     GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType);
2911
2912     push(@implContent, <<END);
2913
2914 void ${className}::derefObject(void* object)
2915 {
2916     static_cast<${nativeType}*>(object)->deref();
2917 }
2918
2919 } // namespace WebCore
2920 END
2921
2922     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
2923     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2924     
2925     # We've already added the header for this file in implFixedHeader, so remove
2926     # it from implIncludes to ensure we don't #include it twice.
2927     delete $implIncludes{"${className}.h"};
2928 }
2929
2930 sub GenerateHeaderContentHeader
2931 {
2932     my $dataNode = shift;
2933     my $className = "V8" . $dataNode->name;
2934     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
2935
2936     my @headerContentHeader = split("\r", $headerTemplate);
2937
2938     push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString;
2939     push(@headerContentHeader, "\n#ifndef ${className}" . "_h");
2940     push(@headerContentHeader, "\n#define ${className}" . "_h\n\n");
2941     return @headerContentHeader;
2942 }
2943
2944 sub GenerateImplementationContentHeader
2945 {
2946     my $dataNode = shift;
2947     my $className = "V8" . $dataNode->name;
2948     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
2949
2950     my @implContentHeader = split("\r", $headerTemplate);
2951
2952     push(@implContentHeader, "\n#include \"config.h\"\n");
2953     push(@implContentHeader, "#include \"${className}.h\"\n\n");
2954     push(@implContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
2955     return @implContentHeader;
2956 }
2957
2958 sub GenerateCallbackHeader
2959 {
2960     my $object = shift;
2961     my $dataNode = shift;
2962
2963     my $interfaceName = $dataNode->name;
2964     my $className = "V8$interfaceName";
2965
2966
2967     # - Add default header template
2968     push(@headerContent, GenerateHeaderContentHeader($dataNode));
2969
2970     my @unsortedIncludes = ();
2971     push(@unsortedIncludes, "#include \"ActiveDOMCallback.h\"");
2972     push(@unsortedIncludes, "#include \"$interfaceName.h\"");
2973     push(@unsortedIncludes, "#include \"WorldContextHandle.h\"");
2974     push(@unsortedIncludes, "#include <v8.h>");
2975     push(@unsortedIncludes, "#include <wtf/Forward.h>");
2976     push(@headerContent, join("\n", sort @unsortedIncludes));
2977     
2978     push(@headerContent, "\n\nnamespace WebCore {\n\n");
2979     push(@headerContent, "class ScriptExecutionContext;\n\n");
2980     push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
2981
2982     push(@headerContent, <<END);
2983 public:
2984     static PassRefPtr<${className}> create(v8::Local<v8::Value> value, ScriptExecutionContext* context)
2985     {
2986         ASSERT(value->IsObject());
2987         ASSERT(context);
2988         return adoptRef(new ${className}(value->ToObject(), context));
2989     }
2990
2991     virtual ~${className}();
2992
2993 END
2994
2995     # Functions
2996     my $numFunctions = @{$dataNode->functions};
2997     if ($numFunctions > 0) {
2998         push(@headerContent, "    // Functions\n");
2999         foreach my $function (@{$dataNode->functions}) {
3000             my @params = @{$function->parameters};
3001             if (!$function->signature->extendedAttributes->{"Custom"} &&
3002                 !(GetNativeType($function->signature->type) eq "bool")) {
3003                     push(@headerContent, "    COMPILE_ASSERT(false)");
3004             }
3005
3006             push(@headerContent, "    virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "(");
3007
3008             my @args = ();
3009             foreach my $param (@params) {
3010                 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
3011             }
3012             push(@headerContent, join(", ", @args));
3013             push(@headerContent, ");\n");
3014         }
3015     }
3016
3017     push(@headerContent, <<END);
3018
3019 private:
3020     ${className}(v8::Local<v8::Object>, ScriptExecutionContext*);
3021
3022     v8::Persistent<v8::Object> m_callback;
3023     WorldContextHandle m_worldContext;
3024 };
3025
3026 END
3027
3028     push(@headerContent, "}\n\n");
3029     push(@headerContent, "#endif // $className" . "_h\n\n");
3030
3031     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
3032     push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
3033 }
3034
3035 sub GenerateCallbackImplementation
3036 {
3037     my $object = shift;
3038     my $dataNode = shift;
3039     my $interfaceName = $dataNode->name;
3040     my $className = "V8$interfaceName";
3041
3042     # - Add default header template
3043     push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
3044          
3045     AddToImplIncludes("ScriptExecutionContext.h");
3046     AddToImplIncludes("V8Binding.h");
3047     AddToImplIncludes("V8CustomVoidCallback.h");
3048     AddToImplIncludes("V8Proxy.h");
3049
3050     push(@implContent, "#include <wtf/Assertions.h>\n\n");
3051     push(@implContent, "namespace WebCore {\n\n");
3052     push(@implContent, <<END);
3053 ${className}::${className}(v8::Local<v8::Object> callback, ScriptExecutionContext* context)
3054     : ActiveDOMCallback(context)
3055     , m_callback(v8::Persistent<v8::Object>::New(callback))
3056     , m_worldContext(UseCurrentWorld)
3057 {
3058 }
3059
3060 ${className}::~${className}()
3061 {
3062     m_callback.Dispose();
3063 }
3064
3065 END
3066
3067     # Functions
3068     my $numFunctions = @{$dataNode->functions};
3069     if ($numFunctions > 0) {
3070         push(@implContent, "// Functions\n");
3071         foreach my $function (@{$dataNode->functions}) {
3072             my @params = @{$function->parameters};
3073             if ($function->signature->extendedAttributes->{"Custom"} ||
3074                 !(GetNativeTypeForCallbacks($function->signature->type) eq "bool")) {
3075                 next;
3076             }
3077
3078             AddIncludesForType($function->signature->type);
3079             push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "(");
3080
3081             my @args = ();
3082             my @argsCheck = ();
3083             my $thisType = $function->signature->extendedAttributes->{"PassThisToCallback"};
3084             foreach my $param (@params) {
3085                 my $paramName = $param->name;
3086                 AddIncludesForType($param->type);
3087                 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $paramName);
3088                 if ($thisType and $thisType eq $param->type) {
3089                     push(@argsCheck, <<END);
3090     ASSERT(${paramName});
3091
3092 END
3093                 }
3094             }
3095             push(@implContent, join(", ", @args));
3096
3097             push(@implContent, ")\n");
3098             push(@implContent, "{\n");
3099             push(@implContent, @argsCheck) if @argsCheck;
3100             push(@implContent, "    if (!canInvokeCallback())\n");
3101             push(@implContent, "        return true;\n\n");
3102             push(@implContent, "    v8::HandleScope handleScope;\n\n");
3103             push(@implContent, "    v8::Handle<v8::Context> v8Context = toV8Context(scriptExecutionContext(), m_worldContext);\n");
3104             push(@implContent, "    if (v8Context.IsEmpty())\n");
3105             push(@implContent, "        return true;\n\n");
3106             push(@implContent, "    v8::Context::Scope scope(v8Context);\n\n");
3107
3108             @args = ();
3109             foreach my $param (@params) {
3110                 my $paramName = $param->name;
3111                 push(@implContent, "    v8::Handle<v8::Value> ${paramName}Handle = " . NativeToJSValue($param, $paramName, "0") . ";\n");
3112                 push(@implContent, "    if (${paramName}Handle.IsEmpty()) {\n");
3113                 push(@implContent, "        if (!isScriptControllerTerminating())\n");
3114                 push(@implContent, "            CRASH();\n");
3115                 push(@implContent, "        return true;\n");
3116                 push(@implContent, "    }\n");
3117                 push(@args, "        ${paramName}Handle");
3118             }
3119
3120             if (scalar(@args) > 0) {
3121                 push(@implContent, "\n    v8::Handle<v8::Value> argv[] = {\n");
3122                 push(@implContent, join(",\n", @args));
3123                 push(@implContent, "\n    };\n\n");
3124             } else {
3125                 push(@implContent, "\n    v8::Handle<v8::Value> *argv = 0;\n\n");
3126             }
3127             push(@implContent, "    bool callbackReturnValue = false;\n");
3128             if ($thisType) {
3129                 foreach my $param (@params) {
3130                     next if $param->type ne $thisType;
3131                     my $paramName = $param->name;
3132                     push(@implContent, "    return !invokeCallback(m_callback, v8::Handle<v8::Object>::Cast(${paramName}Handle), " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n");
3133                     last;
3134                 }
3135             } else {
3136                 push(@implContent, "    return !invokeCallback(m_callback, " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n");
3137             }
3138             push(@implContent, "}\n");
3139         }
3140     }
3141
3142     push(@implContent, "\n} // namespace WebCore\n\n");
3143
3144     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
3145     push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
3146 }
3147
3148 sub GenerateToV8Converters
3149 {
3150     my $dataNode = shift;
3151     my $interfaceName = shift;
3152     my $className = shift;
3153     my $nativeType = shift;
3154
3155     my $domMapName = GetDomMapName($dataNode, $interfaceName);
3156     my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
3157     my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
3158     my $wrapSlowArgumentType = GetPassRefPtrType($nativeType);
3159
3160     push(@implContent, <<END);
3161
3162 v8::Handle<v8::Object> ${className}::wrapSlow(${wrapSlowArgumentType} impl, v8::Isolate* isolate)
3163 {
3164     v8::Handle<v8::Object> wrapper;
3165 END
3166
3167     my $proxyInit;
3168     if (IsNodeSubType($dataNode)) {
3169         $proxyInit = "V8Proxy::retrieve(impl->document()->frame())";
3170         # DocumentType nodes are the only nodes that may have a NULL document.
3171         if ($interfaceName eq "DocumentType") {
3172             $proxyInit = "impl->document() ? $proxyInit : 0";
3173         }
3174     } else {
3175         $proxyInit = "0";
3176     }
3177     push(@implContent, <<END);
3178     V8Proxy* proxy = $proxyInit;
3179 END
3180
3181     if (IsSubType($dataNode, "Document")) {
3182         push(@implContent, <<END);
3183     if (proxy && proxy->windowShell()->context().IsEmpty() && proxy->windowShell()->initContextIfNeeded()) {
3184         // initContextIfNeeded may have created a wrapper for the object, retry from the start.
3185         return ${className}::wrap(impl.get(), isolate);
3186     }
3187 END
3188     }
3189
3190     # FIXME: We need a better way of recovering the correct prototype chain
3191     # for every sort of object. For now, we special-case cross-origin visible
3192     # objects (i.e., those with CheckSecurity).
3193     if (IsVisibleAcrossOrigins($dataNode)) {
3194         push(@implContent, <<END);
3195     if (impl->frame()) {
3196         proxy = V8Proxy::retrieve(impl->frame());
3197         if (proxy)
3198             proxy->windowShell()->initContextIfNeeded();
3199     }
3200 END
3201     }
3202
3203     if (IsNodeSubType($dataNode) || IsVisibleAcrossOrigins($dataNode)) {
3204         push(@implContent, <<END);
3205
3206     // Enter the node's context and create the wrapper in that context.
3207     v8::Handle<v8::Context> context;
3208     if (proxy && !proxy->matchesCurrentContext()) {
3209         // For performance, we enter the context only if the currently running context
3210         // is different from the context that we are about to enter.
3211         context = proxy->context();
3212         if (!context.IsEmpty())
3213             context->Enter();
3214     }
3215 END
3216     }
3217
3218     push(@implContent, <<END);
3219     wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl.get());
3220 END
3221     if (IsNodeSubType($dataNode) || IsVisibleAcrossOrigins($dataNode)) {
3222         push(@implContent, <<END);
3223     // Exit the node's context if it was entered.
3224     if (!context.IsEmpty())
3225         context->Exit();
3226 END
3227     }
3228
3229     push(@implContent, <<END);
3230     if (UNLIKELY(wrapper.IsEmpty()))
3231         return wrapper;
3232
3233     v8::Persistent<v8::Object> wrapperHandle = v8::Persistent<v8::Object>::New(wrapper);
3234
3235     if (!hasDependentLifetime)
3236         wrapperHandle.MarkIndependent();
3237 END
3238     if (IsNodeSubType($dataNode)) {
3239         push(@implContent, <<END);
3240     wrapperHandle.SetWrapperClassId(v8DOMSubtreeClassId);
3241 END
3242     }
3243     push(@implContent, <<END);
3244     V8DOMWrapper::setJSWrapperFor${domMapName}(impl, wrapperHandle, isolate);
3245     return wrapper;
3246 }
3247 END
3248 }
3249
3250 sub GetDomMapFunction
3251 {
3252     my $dataNode = shift;
3253     my $interfaceName = shift;
3254     my $getIsolate = shift;
3255
3256     return "get" . GetDomMapName($dataNode, $interfaceName) . "Map(" . $getIsolate . ")";
3257 }
3258
3259 sub GetDomMapName
3260 {
3261     my $dataNode = shift;
3262     my $type = shift;
3263
3264     return "ActiveDOMNode" if (IsNodeSubType($dataNode) && $dataNode->extendedAttributes->{"ActiveDOMObject"});
3265     return "DOMNode" if IsNodeSubType($dataNode);
3266     return "ActiveDOMObject" if $dataNode->extendedAttributes->{"ActiveDOMObject"};
3267     return "DOMObject";
3268 }
3269
3270 sub GetNativeTypeForConversions
3271 {
3272     my $dataNode = shift;
3273     my $type = shift;
3274
3275     $type = $codeGenerator->GetSVGTypeNeedingTearOff($type) if $codeGenerator->IsSVGTypeNeedingTearOff($type); 
3276     return $type;
3277 }
3278
3279 sub GenerateFunctionCallString()
3280 {
3281     my $function = shift;
3282     my $numberOfParameters = shift;
3283     my $indent = shift;
3284     my $implClassName = shift;
3285     my %replacements = @_;
3286
3287     my $name = $function->signature->name;
3288     my $returnType = GetTypeFromSignature($function->signature);
3289     my $nativeReturnType = GetNativeType($returnType, 0);
3290     my $result = "";
3291
3292     my $isSVGTearOffType = ($codeGenerator->IsSVGTypeNeedingTearOff($returnType) and not $implClassName =~ /List$/);
3293     $nativeReturnType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($returnType) if $isSVGTearOffType;
3294
3295     if ($function->signature->extendedAttributes->{"ImplementedAs"}) {
3296         $name = $function->signature->extendedAttributes->{"ImplementedAs"};
3297     }
3298
3299     my $index = 0;
3300     my $hasScriptState = 0;
3301
3302     my @arguments;
3303     my $functionName;
3304     my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
3305     if ($implementedBy) {
3306         AddToImplIncludes("${implementedBy}.h");
3307         unshift(@arguments, "imp") if !$function->isStatic;
3308         $functionName = "${implementedBy}::${name}";
3309     } elsif ($function->isStatic) {
3310         $functionName = "${implClassName}::${name}";
3311     } else {
3312         $functionName = "imp->${name}";
3313     }
3314
3315     my $callWith = $function->signature->extendedAttributes->{"CallWith"};
3316     my @callWithOutput = ();
3317     my @callWithArgs = GenerateCallWith($callWith, \@callWithOutput, $indent, 0, 1, $function);
3318     $result .= join("", @callWithOutput);
3319     push(@arguments, @callWithArgs);
3320     $index += @callWithArgs;
3321     $numberOfParameters += @callWithArgs;
3322
3323     foreach my $parameter (@{$function->parameters}) {
3324         if ($index eq $numberOfParameters) {
3325             last;
3326         }
3327         my $paramName = $parameter->name;
3328         my $paramType = $parameter->type;
3329
3330         if ($replacements{$paramName}) {
3331             push @arguments, $replacements{$paramName};
3332         } elsif ($parameter->type eq "IDBKey" || $parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") {
3333             push @arguments, "$paramName.get()";
3334         } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($parameter->type) and not $implClassName =~ /List$/) {
3335             push @arguments, "$paramName->propertyReference()";
3336             $result .= $indent . "if (!$paramName) {\n";
3337             $result .= $indent . "    V8Proxy::setDOMException(WebCore::TYPE_MISMATCH_ERR, args.GetIsolate());\n";
3338             $result .= $indent . "    return v8::Handle<v8::Value>();\n";
3339             $result .= $indent . "}\n";
3340         } elsif ($parameter->type eq "SVGMatrix" and $implClassName eq "SVGTransformList") {
3341             push @arguments, "$paramName.get()";
3342         } else {
3343             push @arguments, $paramName;
3344         }
3345         $index++;
3346     }
3347
3348     if (@{$function->raisesExceptions}) {
3349         push @arguments, "ec";
3350     }
3351
3352     my $functionString = "$functionName(" . join(", ", @arguments) . ")";
3353
3354     my $return = "result";
3355     my $returnIsRef = IsRefPtrType($returnType);
3356
3357     if ($returnType eq "void") {
3358         $result .= $indent . "$functionString;\n";
3359     } elsif ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState") or @{$function->raisesExceptions}) {
3360         $result .= $indent . $nativeReturnType . " result = $functionString;\n";
3361     } else {
3362         # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
3363         $return = $functionString;
3364         $returnIsRef = 0;
3365
3366         if ($implClassName eq "SVGTransformList" and IsRefPtrType($returnType)) {
3367             $return = "WTF::getPtr(" . $return . ")";
3368         }
3369     }
3370
3371     if (@{$function->raisesExceptions}) {
3372         $result .= $indent . "if (UNLIKELY(ec))\n";
3373         $result .= $indent . "    goto fail;\n";
3374     }
3375
3376     if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
3377         $result .= $indent . "if (state.hadException())\n";
3378         $result .= $indent . "    return throwError(state.exception(), args.GetIsolate());\n"
3379     }
3380
3381     if ($isSVGTearOffType) {
3382         AddToImplIncludes("V8$returnType.h");
3383         AddToImplIncludes("SVGPropertyTearOff.h");
3384         my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($returnType);
3385         $result .= $indent . "return toV8(WTF::getPtr(${svgNativeType}::create($return)), args.GetIsolate());\n";
3386         return $result;
3387     }
3388
3389     # If the implementing class is a POD type, commit changes
3390     if ($codeGenerator->IsSVGTypeNeedingTearOff($implClassName) and not $implClassName =~ /List$/) {
3391         $result .= $indent . "wrapper->commitChange();\n";
3392     }
3393
3394     $return .= ".release()" if ($returnIsRef);
3395     $result .= $indent . ReturnNativeToJSValue($function->signature, $return, "args.GetIsolate()") . ";\n";
3396
3397     return $result;
3398 }
3399
3400
3401 sub GetTypeFromSignature
3402 {
3403     my $signature = shift;
3404
3405     return $codeGenerator->StripModule($signature->type);
3406 }
3407
3408
3409 sub GetNativeTypeFromSignature
3410 {
3411     my $signature = shift;
3412     my $parameterIndex = shift;
3413
3414     my $type = GetTypeFromSignature($signature);
3415
3416     if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
3417         # Special-case index arguments because we need to check that they aren't < 0.
3418         return "int";
3419     }
3420
3421     $type = GetNativeType($type, $parameterIndex >= 0 ? 1 : 0);
3422
3423     if ($parameterIndex >= 0 && $type eq "V8Parameter") {
3424         # FIXME: This implements [TreatNullAs=NullString] and [TreatUndefinedAs=NullString],
3425         # but the Web IDL spec requires [TreatNullAs=EmptyString] and [TreatUndefinedAs=EmptyString].
3426         my $mode = "";
3427         if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") and ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString")) {
3428             $mode = "WithUndefinedOrNullCheck";
3429         } elsif (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") or $signature->extendedAttributes->{"Reflect"}) {
3430             $mode = "WithNullCheck";
3431         }
3432         # FIXME: Add the case for 'elsif ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString"))'.
3433         $type .= "<$mode>";
3434     }
3435
3436     return $type;
3437 }
3438
3439 sub IsRefPtrType
3440 {
3441     my $type = shift;
3442
3443     return 0 if $type eq "boolean";
3444     return 0 if $type eq "float";
3445     return 0 if $type eq "int";
3446     return 0 if $type eq "Date";
3447     return 0 if $type eq "DOMString";
3448     return 0 if $type eq "double";
3449     return 0 if $type eq "short";
3450     return 0 if $type eq "long";
3451     return 0 if $type eq "unsigned";
3452     return 0 if $type eq "unsigned long";
3453     return 0 if $type eq "unsigned short";
3454     return 0 if $type eq "float[]";
3455     return 0 if $type eq "double[]";
3456
3457     return 1;
3458 }
3459
3460 sub GetNativeType
3461 {
3462     my $type = shift;
3463     my $isParameter = shift;
3464
3465     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
3466     if ($svgNativeType) {
3467         if ($svgNativeType =~ /List$/) {
3468             return "${svgNativeType}*";
3469         } else {
3470             return "RefPtr<${svgNativeType} >";
3471         }
3472     }
3473
3474     if ($type eq "float" or $type eq "double") {
3475         return $type;
3476     }
3477
3478     return "V8Parameter" if ($type eq "DOMString" or $type eq "DOMUserData") and $isParameter;
3479     return "int" if $type eq "int";
3480     return "int" if $type eq "short" or $type eq "unsigned short";
3481     return "unsigned" if $type eq "unsigned long";
3482     return "int" if $type eq "long";
3483     return "long long" if $type eq "long long";
3484     return "unsigned long long" if $type eq "unsigned long long";
3485     return "bool" if $type eq "boolean";
3486     return "String" if $type eq "DOMString";
3487     return "Range::CompareHow" if $type eq "CompareHow";
3488     return "DOMTimeStamp" if $type eq "DOMTimeStamp";
3489     return "unsigned" if $type eq "unsigned int";
3490     return "Node*" if $type eq "EventTarget" and $isParameter;
3491     return "double" if $type eq "Date";
3492     return "ScriptValue" if $type eq "DOMObject";
3493     return "Dictionary" if $type eq "Dictionary";
3494
3495     return "String" if $type eq "DOMUserData";  # FIXME: Temporary hack?
3496
3497     # temporary hack
3498     return "RefPtr<NodeFilter>" if $type eq "NodeFilter";
3499
3500     return "RefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue";
3501
3502     return "RefPtr<IDBKey>" if $type eq "IDBKey";
3503
3504     # necessary as resolvers could be constructed on fly.
3505     return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver";
3506
3507     return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter;
3508
3509     return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener";
3510
3511     # FIXME: Support T[], T[]?, sequence<T> generically
3512     return "Vector<float>" if $type eq "float[]";
3513     return "Vector<double>" if $type eq "double[]";
3514     return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
3515     return "RefPtr<DOMStringList>" if $type eq "DOMString[]";
3516
3517     # Default, assume native type is a pointer with same type name as idl type
3518     return "${type}*";
3519 }
3520
3521 sub GetNativeTypeForCallbacks
3522 {
3523     my $type = shift;
3524     return "const String&" if $type eq "DOMString";
3525     return "SerializedScriptValue*" if $type eq "SerializedScriptValue";
3526
3527     # Callbacks use raw pointers, so pass isParameter = 1
3528     return GetNativeType($type, 1);
3529 }
3530
3531 sub TranslateParameter
3532 {
3533     my $signature = shift;
3534
3535     # The IDL uses some pseudo-types which don't really exist.
3536     if ($signature->type eq "TimeoutHandler") {
3537       $signature->type("DOMString");
3538     }
3539 }
3540
3541 sub TypeCanFailConversion
3542 {
3543     my $signature = shift;
3544
3545     my $type = GetTypeFromSignature($signature);
3546
3547     AddToImplIncludes("ExceptionCode.h") if $type eq "Attr";
3548     return 1 if $type eq "Attr";
3549     return 1 if $type eq "VoidCallback";
3550     return 0;
3551 }
3552
3553 sub JSValueToNative
3554 {
3555     my $signature = shift;
3556     my $value = shift;
3557     my $getIsolate = shift;
3558
3559     my $type = GetTypeFromSignature($signature);
3560
3561     return "$value" if $type eq "JSObject";
3562     return "$value->BooleanValue()" if $type eq "boolean";
3563     return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double";
3564
3565     return "toInt32($value)" if $type eq "long" or $type eq "short";
3566     return "toUInt32($value)" if $type eq "unsigned long" or $type eq "unsigned short";
3567     return "toInt64($value)" if $type eq "unsigned long long" or $type eq "long long";
3568     return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow";
3569     return "toWebCoreDate($value)" if $type eq "Date";
3570     return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMStringList";
3571     # FIXME: Add proper support for T[], T[]? and sequence<T>.
3572     return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMString[]";
3573     if ($type eq "float[]") {
3574         AddToImplIncludes("wtf/Vector.h");
3575         return "v8NumberArrayToVector<float>($value)";
3576     }
3577     if ($type eq "double[]") {
3578         AddToImplIncludes("wtf/Vector.h");
3579         return "v8NumberArrayToVector<double>($value)";
3580     }
3581
3582     if ($type eq "DOMString" or $type eq "DOMUserData") {
3583         return $value;
3584     }
3585
3586     if ($type eq "SerializedScriptValue") {
3587         AddToImplIncludes("SerializedScriptValue.h");
3588         return "SerializedScriptValue::create($value, $getIsolate)";
3589     }
3590
3591     if ($type eq "IDBKey") {
3592         AddToImplIncludes("IDBBindingUtilities.h");
3593         AddToImplIncludes("IDBKey.h");
3594         return "createIDBKeyFromValue($value)";
3595     }
3596
3597     if ($type eq "Dictionary") {
3598         AddToImplIncludes("Dictionary.h");
3599         return $value;
3600     }
3601
3602     if ($type eq "DOMObject") {
3603         AddToImplIncludes("ScriptValue.h");
3604         return "ScriptValue($value)";
3605     }
3606
3607     if ($type eq "NodeFilter") {
3608         return "V8DOMWrapper::wrapNativeNodeFilter($value)";
3609     }
3610
3611     if ($type eq "MediaQueryListListener") {
3612         AddToImplIncludes("MediaQueryListListener.h");
3613         return "MediaQueryListListener::create(" . $value . ")";
3614     }
3615
3616     # Default, assume autogenerated type conversion routines
3617     if ($type eq "EventTarget") {
3618         AddToImplIncludes("V8Node.h");
3619
3620         # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget.
3621         return "V8Node::HasInstance($value) ? V8Node::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
3622     }
3623
3624     if ($type eq "XPathNSResolver") {
3625         return "V8DOMWrapper::getXPathNSResolver($value)";
3626     }
3627
3628     my $arrayType = $codeGenerator->GetArrayType($type);
3629     if ($arrayType) {
3630         return "toNativeArray<$arrayType>($value)";
3631     }
3632
3633     AddIncludesForType($type);
3634
3635     if (IsDOMNodeType($type)) {
3636         AddToImplIncludes("V8${type}.h");
3637
3638         # Perform type checks on the parameter, if it is expected Node type,
3639         # return NULL.
3640         return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
3641     } else {
3642         AddToImplIncludes("V8$type.h");
3643
3644         # Perform type checks on the parameter, if it is expected Node type,
3645         # return NULL.
3646         return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
3647     }
3648 }
3649
3650 sub GetV8HeaderName
3651 {
3652     my $type = shift;
3653     return "V8Event.h" if $type eq "DOMTimeStamp";
3654     return "EventListener.h" if $type eq "EventListener";
3655     return "EventTarget.h" if $type eq "EventTarget";
3656     return "SerializedScriptValue.h" if $type eq "SerializedScriptValue";
3657     return "ScriptValue.h" if $type eq "DOMObject";
3658     return "V8DOMStringList.h" if $type eq "DOMString[]";
3659     return "V8${type}.h";
3660 }
3661
3662 sub CreateCustomSignature
3663 {
3664     my $function = shift;
3665     my $count = @{$function->parameters};
3666     my $name = $function->signature->name;
3667     my $result = "    const int ${name}Argc = ${count};\n" .
3668       "    v8::Handle<v8::FunctionTemplate> ${name}Argv[${name}Argc] = { ";
3669     my $first = 1;
3670     foreach my $parameter (@{$function->parameters}) {
3671         if ($first) { $first = 0; }
3672         else { $result .= ", "; }
3673         if (IsWrapperType($parameter->type)) {
3674             if ($parameter->type eq "XPathNSResolver") {
3675                 # Special case for XPathNSResolver.  All other browsers accepts a callable,
3676                 # so, even though it's against IDL, accept objects here.
3677                 $result .= "v8::Handle<v8::FunctionTemplate>()";
3678             } else {
3679                 my $type = $parameter->type;
3680                 my $arrayType = $codeGenerator->GetArrayType($type);
3681                 if ($arrayType) {
3682                     AddToImplIncludes("$arrayType.h");
3683                 } else {
3684                     my $header = GetV8HeaderName($type);
3685                     AddToImplIncludes($header);
3686                 }
3687                 $result .= "V8${type}::GetRawTemplate()";
3688             }
3689         } else {
3690             $result .= "v8::Handle<v8::FunctionTemplate>()";
3691         }
3692     }
3693     $result .= " };\n";
3694     $result .= "    v8::Handle<v8::Signature> ${name}Signature = v8::Signature::New(desc, ${name}Argc, ${name}Argv);\n";
3695     return $result;
3696 }
3697
3698
3699 sub RequiresCustomSignature
3700 {
3701     my $function = shift;
3702     # No signature needed for Custom function
3703     if ($function->signature->extendedAttributes->{"Custom"} ||
3704         $function->signature->extendedAttributes->{"V8Custom"}) {
3705         return 0;
3706