CodeGeneratorV8.pm   [plain text]


# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
# Copyright (C) 2006 Apple Computer, Inc.
# Copyright (C) 2007, 2008, 2009, 2012 Google Inc.
# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
# Copyright (C) Research In Motion Limited 2010. All rights reserved.
# Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with this library; see the file COPYING.LIB.  If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#

package CodeGeneratorV8;

use strict;

use Digest::MD5;

use constant FileNamePrefix => "V8";

my $codeGenerator;

my $module = "";
my $outputDir = "";
my $outputHeadersDir = "";

my @headerContent = ();
my @implContentHeader = ();
my @implFixedHeader = ();
my @implContent = ();
my @implContentDecls = ();
my %implIncludes = ();
my %headerIncludes = ();

my @allParents = ();

# Default .h template
my $headerTemplate = << "EOF";
/*
    This file is part of the WebKit open source project.
    This file has been generated by generate-bindings.pl. DO NOT MODIFY!

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/
EOF

# Default constructor
sub new
{
    my $object = shift;
    my $reference = { };

    $codeGenerator = shift;
    $outputDir = shift;
    $outputHeadersDir = shift;

    bless($reference, $object);
    return $reference;
}

# Params: 'domClass' struct
sub GenerateInterface
{
    my $object = shift;
    my $dataNode = shift;
    my $defines = shift;

    # Start actual generation
    if ($dataNode->extendedAttributes->{"Callback"}) {
        $object->GenerateCallbackHeader($dataNode);
        $object->GenerateCallbackImplementation($dataNode);
    } else {
        $object->GenerateHeader($dataNode);
        $object->GenerateImplementation($dataNode);
    }

    $object->WriteData($dataNode);
}

# Params: 'idlDocument' struct
sub GenerateModule
{
    my $object = shift;
    my $dataNode = shift;

    $module = $dataNode->module;
}

sub AddToImplIncludes
{
    my $header = shift;
    my $conditional = shift;

    if (not $conditional) {
        $implIncludes{$header} = 1;
    } elsif (not exists($implIncludes{$header})) {
        $implIncludes{$header} = $conditional;
    } else {
        my $oldValue = $implIncludes{$header};
        if ($oldValue ne 1) {
            my %newValue = ();
            $newValue{$conditional} = 1;
            foreach my $condition (split(/\|/, $oldValue)) {
                $newValue{$condition} = 1;
            }
            $implIncludes{$header} = join("|", sort keys %newValue);
        }
    }
}

sub AddIncludesForType
{
    my $type = $codeGenerator->StripModule(shift);

    # When we're finished with the one-file-per-class
    # reorganization, we won't need these special cases.
    if (IsTypedArrayType($type)) {
        AddToImplIncludes("wtf/${type}.h");
    }
    if (!$codeGenerator->IsPrimitiveType($type) and !$codeGenerator->IsStringType($type) and !$codeGenerator->SkipIncludeHeader($type) and $type ne "Date") {
        # default, include the same named file
        AddToImplIncludes(GetV8HeaderName(${type}));

        if ($type =~ /SVGPathSeg/) {
            my $joinedName = $type;
            $joinedName =~ s/Abs|Rel//;
            AddToImplIncludes("${joinedName}.h");
        }
    }

    # additional includes (things needed to compile the bindings but not the header)

    if ($type eq "CanvasRenderingContext2D") {
        AddToImplIncludes("CanvasGradient.h");
        AddToImplIncludes("CanvasPattern.h");
        AddToImplIncludes("CanvasStyle.h");
    }

    if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
        AddToImplIncludes("PlatformString.h");
    }

    if ($type eq "CSSStyleSheet" or $type eq "StyleSheet") {
        AddToImplIncludes("CSSImportRule.h");
    }

    if ($type eq "CSSStyleDeclaration") {
        AddToImplIncludes("StylePropertySet.h");
    }

    if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") {
        # So we can get String -> AtomicString conversion for namedItem().
        AddToImplIncludes("wtf/text/AtomicString.h");
    }
}

sub GetSVGPropertyTypes
{
    my $implType = shift;

    my $svgPropertyType;
    my $svgListPropertyType;
    my $svgNativeType;

    return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/;

    $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType);
    return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType;

    # Append space to avoid compilation errors when using  PassRefPtr<$svgNativeType>
    $svgNativeType = "$svgNativeType ";

    my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType);
    if ($svgNativeType =~ /SVGPropertyTearOff/) {
        $svgPropertyType = $svgWrappedNativeType;
        AddToImplIncludes("SVGAnimatedPropertyTearOff.h");
    } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
        $svgListPropertyType = $svgWrappedNativeType;
        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
        $headerIncludes{"SVGStaticListPropertyTearOff.h"} = 1;
    } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
        $svgListPropertyType = $svgWrappedNativeType;
        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
        $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
    } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
        $svgListPropertyType = $svgWrappedNativeType;
        $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
    }

    if ($svgPropertyType) {
        $svgPropertyType = "SVGPoint" if $svgPropertyType eq "FloatPoint";
    }

    return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
}

sub GenerateHeader
{
    my $object = shift;
    my $dataNode = shift;

    my $interfaceName = $dataNode->name;
    my $className = "V8$interfaceName";
    my $implClassName = $interfaceName;

    # Copy contents of parent classes except the first parent or if it is
    # EventTarget.
    $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1);
    $codeGenerator->LinkOverloadedFunctions($dataNode);

    my $hasDependentLifetime = $dataNode->extendedAttributes->{"V8DependentLifetime"} || $dataNode->extendedAttributes->{"ActiveDOMObject"} || $className =~ /SVG/;
    if (!$hasDependentLifetime) {
        foreach (@{$dataNode->parents}) {
            my $parent = $codeGenerator->StripModule($_);
            next if $parent eq "EventTarget";
            $headerIncludes{"V8${parent}.h"} = 1;
        }
    }

    # - Add default header template
    push(@headerContent, GenerateHeaderContentHeader($dataNode));

    $headerIncludes{"wtf/text/StringHash.h"} = 1;
    $headerIncludes{"WrapperTypeInfo.h"} = 1;
    $headerIncludes{"V8DOMWrapper.h"} = 1;
    $headerIncludes{"wtf/HashMap.h"} = 1;
    $headerIncludes{"v8.h"} = 1;

    my $headerClassInclude = GetHeaderClassInclude($implClassName);
    $headerIncludes{$headerClassInclude} = 1 if $headerClassInclude ne "";

    my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);

    foreach my $headerInclude (sort keys(%headerIncludes)) {
        if ($headerInclude =~ /wtf|v8\.h/) {
            push(@headerContent, "#include \<${headerInclude}\>\n");
        } else {
            push(@headerContent, "#include \"${headerInclude}\"\n");
        }
    }

    push(@headerContent, "\nnamespace WebCore {\n");
    push(@headerContent, "\ntemplate<typename PropertyType> class SVGPropertyTearOff;\n") if $svgPropertyType;
    if ($svgNativeType) {
        if ($svgNativeType =~ /SVGStaticListPropertyTearOff/) {
            push(@headerContent, "\ntemplate<typename PropertyType> class SVGStaticListPropertyTearOff;\n");
        } else {
            push(@headerContent, "\ntemplate<typename PropertyType> class SVGListPropertyTearOff;\n");
        }
    }

    push(@headerContent, "\n");
    push(@headerContent, "class FloatRect;\n") if $svgPropertyType && $svgPropertyType eq "FloatRect";
    push(@headerContent, "class Dictionary;\n") if IsConstructorTemplate($dataNode, "Event");

    my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
    if ($dataNode->extendedAttributes->{"NamedConstructor"}) {
        push(@headerContent, <<END);
class V8${nativeType}Constructor {
public:
    static v8::Persistent<v8::FunctionTemplate> GetTemplate();
    static WrapperTypeInfo info;
};

END
    }

    push(@headerContent, "class $className {\n");
    push(@headerContent, "public:\n");

    push(@headerContent, "    static const bool hasDependentLifetime = ");
    if ($hasDependentLifetime) {
        push(@headerContent, "true;\n");
    } elsif (@{$dataNode->parents}) {
        # Even if this type doesn't have the V8DependentLifetime attribute its parents may.
        # Let the compiler statically determine this for us.
        my $separator = "";
        foreach (@{$dataNode->parents}) {
            my $parent = $codeGenerator->StripModule($_);
            next if $parent eq "EventTarget";
            $headerIncludes{"V8${parent}.h"} = 1;
            push(@headerContent, "${separator}V8${parent}::hasDependentLifetime");
            $separator = " || ";
        }
        push(@headerContent, ";\n");
    } else {
        push(@headerContent, "false;\n");
    }

    my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName);
    my $forceNewObjectParameter = IsDOMNodeType($interfaceName) ? ", bool forceNewObject = false" : "";
    my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
    my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";

    push(@headerContent, <<END);
    static bool HasInstance(v8::Handle<v8::Value>);
    static v8::Persistent<v8::FunctionTemplate> GetRawTemplate();
    static v8::Persistent<v8::FunctionTemplate> GetTemplate();
    static ${nativeType}* toNative(v8::Handle<v8::Object> object)
    {
        return reinterpret_cast<${nativeType}*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex));
    }
    inline static v8::Handle<v8::Object> wrap(${nativeType}*, v8::Isolate* = 0${forceNewObjectParameter});
    static void derefObject(void*);
    static WrapperTypeInfo info;
END
    if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
        push(@headerContent, "    static ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object>);\n");
    }

    if ($implClassName eq "DOMWindow") {
        push(@headerContent, <<END);
    static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate();
END
    }

    if ($implClassName eq "HTMLDocument") {
      push(@headerContent, <<END);
  static v8::Local<v8::Object> WrapInShadowObject(v8::Local<v8::Object> wrapper, Node* impl);
  static v8::Handle<v8::Value> GetNamedProperty(HTMLDocument* htmlDocument, const AtomicString& key, v8::Isolate*);
END
    }

    my @enabledAtRuntime;
    foreach my $function (@{$dataNode->functions}) {
        my $name = $function->signature->name;
        my $attrExt = $function->signature->extendedAttributes;

        if (($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) && !$attrExt->{"ImplementedBy"} && $function->{overloadIndex} == 1) {
            my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
            push(@headerContent, <<END);
    static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments&);
END
            push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
        }

        if ($attrExt->{"V8EnabledAtRuntime"}) {
            push(@enabledAtRuntime, $function);
        }
    }

    if (IsConstructable($dataNode)) {
        push(@headerContent, <<END);
    static v8::Handle<v8::Value> constructorCallback(const v8::Arguments&);
END
    }

    foreach my $attribute (@{$dataNode->attributes}) {
        my $name = $attribute->signature->name;
        my $attrExt = $attribute->signature->extendedAttributes;
        my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
        if (($attrExt->{"V8CustomGetter"} || $attrExt->{"CustomGetter"} ||
             $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) &&
            !$attrExt->{"ImplementedBy"}) {
            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
            push(@headerContent, <<END);
    static v8::Handle<v8::Value> ${name}AccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);
END
            push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
        }
        if (($attrExt->{"V8CustomSetter"} || $attrExt->{"CustomSetter"} ||
             $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) &&
            !$attrExt->{"ImplementedBy"}) {
            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
            push(@headerContent, <<END);
    static void ${name}AccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value>, const v8::AccessorInfo&);
END
            push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
        }
        if ($attrExt->{"V8EnabledAtRuntime"}) {
            push(@enabledAtRuntime, $attribute);
        }
    }

    GenerateHeaderNamedAndIndexedPropertyAccessors($dataNode);
    GenerateHeaderCustomCall($dataNode);
    GenerateHeaderCustomInternalFieldIndices($dataNode);

    if ($dataNode->extendedAttributes->{"CheckSecurity"}) {
        push(@headerContent, <<END);
    static bool namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType, v8::Local<v8::Value> data);
    static bool indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType, v8::Local<v8::Value> data);
END
    }

    my $wrapSlowArgumentType = GetPassRefPtrType($nativeType);
    push(@headerContent, <<END);
private:
    static v8::Handle<v8::Object> wrapSlow(${wrapSlowArgumentType}, v8::Isolate*);
};

END

    push(@headerContent, <<END);
v8::Handle<v8::Object> ${className}::wrap(${nativeType}* impl, v8::Isolate* isolate${forceNewObjectInput})
{
END
    push(@headerContent, "    if (!forceNewObject) {\n") if IsDOMNodeType($interfaceName);
    my $getCachedWrapper = IsNodeSubType($dataNode) ? "V8DOMWrapper::getCachedWrapper(impl)" : "${domMapFunction}.get(impl)";
    push(@headerContent, <<END);
        v8::Handle<v8::Object> wrapper = $getCachedWrapper;
        if (!wrapper.IsEmpty())
            return wrapper;
END
    push(@headerContent, "    }\n") if IsDOMNodeType($interfaceName);
    push(@headerContent, <<END);
    return ${className}::wrapSlow(impl, isolate);
}
END

    if ($interfaceName eq 'Element') {
        # Do not generate toV8() for performance optimization.
    } elsif (!($dataNode->extendedAttributes->{"CustomToJSObject"} or $dataNode->extendedAttributes->{"V8CustomToJSObject"})) {
        push(@headerContent, <<END);

inline v8::Handle<v8::Value> toV8(${nativeType}* impl, v8::Isolate* isolate = 0${forceNewObjectParameter})
{
    if (!impl)
        return v8::Null();
    return ${className}::wrap(impl, isolate${forceNewObjectCall});
}
END
    } elsif ($interfaceName ne 'Node') {
        push(@headerContent, <<END);

v8::Handle<v8::Value> toV8(${nativeType}*, v8::Isolate* = 0${forceNewObjectParameter});
END
    } else {
        push(@headerContent, <<END);

v8::Handle<v8::Value> toV8Slow(Node*, v8::Isolate*, bool);

inline v8::Handle<v8::Value> toV8(Node* impl, v8::Isolate* isolate = 0, bool forceNewObject = false)
{
    if (UNLIKELY(!impl))
        return v8::Null();
    if (UNLIKELY(forceNewObject))
        return toV8Slow(impl, isolate, forceNewObject);
    v8::Handle<v8::Value> wrapper = V8DOMWrapper::getCachedWrapper(impl);
    if (!wrapper.IsEmpty())
        return wrapper;
    return toV8Slow(impl, isolate, false);
}
END
    }

    push(@headerContent, <<END);
inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl, v8::Isolate* isolate = 0${forceNewObjectParameter})
{
    return toV8(impl.get(), isolate${forceNewObjectCall});
}
END

    if (IsConstructorTemplate($dataNode, "Event")) {
        push(@headerContent, "\nbool fill${implClassName}Init(${implClassName}Init&, const Dictionary&);\n");
    }

    push(@headerContent, "\n}\n\n");
    push(@headerContent, "#endif // $className" . "_h\n");

    my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
    push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
}

sub GetInternalFields
{
    my $dataNode = shift;
    my $name = $dataNode->name;

    my @customInternalFields = ();
    # We can't ask whether a parent type has a given extendedAttribute,
    # so special-case AbstractWorker and WorkerContext to include all sub-types.
    # Event listeners on DOM nodes are explicitly supported in the GC controller.
    # FIXME: SVGElementInstance should probably have the EventTarget extended attribute, but doesn't.
    if (!IsNodeSubType($dataNode)
        && ($dataNode->extendedAttributes->{"EventTarget"}
            || $dataNode->extendedAttributes->{"IsWorkerContext"}
            || IsSubType($dataNode, "AbstractWorker")
            || $name eq "SVGElementInstance")) {
        push(@customInternalFields, "eventListenerCacheIndex");
    }

    if ($name eq "DOMWindow") {
        push(@customInternalFields, "enteredIsolatedWorldIndex");
    }
    return @customInternalFields;
}

sub GetHeaderClassInclude
{
    my $className = shift;
    if ($className =~ /SVGPathSeg/) {
        $className =~ s/Abs|Rel//;
    }
    return "wtf/${className}.h" if IsTypedArrayType($className);
    return "" if ($codeGenerator->SkipIncludeHeader($className));
    return "${className}.h";
}

sub GenerateHeaderCustomInternalFieldIndices
{
    my $dataNode = shift;
    my @customInternalFields = GetInternalFields($dataNode);
    my $customFieldCounter = 0;
    foreach my $customInternalField (@customInternalFields) {
        push(@headerContent, <<END);
    static const int ${customInternalField} = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
END
        $customFieldCounter++;
    }
    push(@headerContent, <<END);
    static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
END
}

my %indexerSpecialCases = (
    "Storage" => 1,
    "HTMLAppletElement" => 1,
    "HTMLEmbedElement" => 1,
    "HTMLObjectElement" => 1
);

sub GenerateHeaderNamedAndIndexedPropertyAccessors
{
    my $dataNode = shift;
    my $interfaceName = $dataNode->name;
    my $hasCustomIndexedGetter = $dataNode->extendedAttributes->{"IndexedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
    my $hasCustomIndexedSetter = $dataNode->extendedAttributes->{"CustomIndexedSetter"} && !$dataNode->extendedAttributes->{"NumericIndexedGetter"};
    my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"NamedGetter"} || $dataNode->extendedAttributes->{"CustomNamedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
    my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"CustomNamedSetter"};
    my $hasCustomDeleters = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
    my $hasCustomEnumerator = $dataNode->extendedAttributes->{"CustomEnumerateProperty"};
    if ($interfaceName eq "HTMLOptionsCollection") {
        $interfaceName = "HTMLCollection";
        $hasCustomIndexedGetter = 1;
        $hasCustomNamedGetter = 1;
    }
    if ($interfaceName eq "DOMWindow") {
        $hasCustomDeleters = 0;
        $hasCustomEnumerator = 0;
    }
    if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
        $hasCustomNamedGetter = 1;
    }
    if ($interfaceName eq "HTMLDocument") {
        $hasCustomNamedGetter = 0;
        $hasCustomIndexedGetter = 0;
    }
    my $isIndexerSpecialCase = exists $indexerSpecialCases{$interfaceName};

    if ($hasCustomIndexedGetter || $isIndexerSpecialCase) {
        push(@headerContent, <<END);
    static v8::Handle<v8::Value> indexedPropertyGetter(uint32_t, const v8::AccessorInfo&);
END
    }

    if ($isIndexerSpecialCase || $hasCustomIndexedSetter) {
        push(@headerContent, <<END);
    static v8::Handle<v8::Value> indexedPropertySetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&);
END
    }
    if ($hasCustomDeleters) {
        push(@headerContent, <<END);
    static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t, const v8::AccessorInfo&);
END
    }
    if ($hasCustomNamedGetter) {
        push(@headerContent, <<END);
    static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String>, const v8::AccessorInfo&);
END
    }
    if ($hasCustomNamedSetter) {
        push(@headerContent, <<END);
    static v8::Handle<v8::Value> namedPropertySetter(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo&);
END
    }
    if ($hasCustomDeleters) {
        push(@headerContent, <<END);
    static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String>, const v8::AccessorInfo&);
END
    }
    if ($hasCustomEnumerator) {
        push(@headerContent, <<END);
    static v8::Handle<v8::Array> namedPropertyEnumerator(const v8::AccessorInfo&);
    static v8::Handle<v8::Integer> namedPropertyQuery(v8::Local<v8::String>, const v8::AccessorInfo&);
END
    }
}

sub GenerateHeaderCustomCall
{
    my $dataNode = shift;

    if ($dataNode->extendedAttributes->{"CustomCall"}) {
        push(@headerContent, "    static v8::Handle<v8::Value> callAsFunctionCallback(const v8::Arguments&);\n");
    }
    if ($dataNode->name eq "Event") {
        push(@headerContent, "    static v8::Handle<v8::Value> dataTransferAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
        push(@headerContent, "    static void valueAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value>, const v8::AccessorInfo&);\n");
    }
    if ($dataNode->name eq "Location") {
        push(@headerContent, "    static v8::Handle<v8::Value> assignAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
        push(@headerContent, "    static v8::Handle<v8::Value> reloadAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
        push(@headerContent, "    static v8::Handle<v8::Value> replaceAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
    }
}

sub GenerateSetDOMException
{
    my $indent = shift;
    my $getIsolate = shift;
    my $result = "";

    $result .= $indent . "if (UNLIKELY(ec)) {\n";
    $result .= $indent . "    V8Proxy::setDOMException(ec, $getIsolate);\n";
    $result .= $indent . "    return v8::Handle<v8::Value>();\n";
    $result .= $indent . "}\n";

    return $result;
}

sub IsSubType
{
    my $dataNode = shift;
    my $parentType = shift;
    return 1 if ($dataNode->name eq $parentType);
    foreach (@allParents) {
        my $parent = $codeGenerator->StripModule($_);
        return 1 if $parent eq $parentType;
    }
    return 0;
}

sub IsNodeSubType
{
    my $dataNode = shift;
    return IsSubType($dataNode, "Node");
}

sub IsVisibleAcrossOrigins
{
    my $dataNode = shift;
    return $dataNode->extendedAttributes->{"CheckSecurity"} && !($dataNode->name eq "DOMWindow");
}

sub IsConstructable
{
    my $dataNode = shift;

    return $dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"Constructor"} || $dataNode->extendedAttributes->{"ConstructorTemplate"};
}

sub IsConstructorTemplate
{
    my $dataNode = shift;
    my $template = shift;

    return $dataNode->extendedAttributes->{"ConstructorTemplate"} && $dataNode->extendedAttributes->{"ConstructorTemplate"} eq $template;
}

sub GenerateDomainSafeFunctionGetter
{
    my $function = shift;
    my $implClassName = shift;

    my $className = "V8" . $implClassName;
    my $funcName = $function->signature->name;

    my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())";
    if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) {
        $signature = "v8::Local<v8::Signature>()";
    }

    my $newTemplateString = GenerateNewFunctionTemplate($function, $implClassName, $signature);

    push(@implContentDecls, <<END);
static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS(\"DOM.$implClassName.$funcName._get\");
    static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(${className}::GetTemplate(), info.This());
    if (holder.IsEmpty()) {
        // can only reach here by 'object.__proto__.func', and it should passed
        // domain security check already
        return privateTemplate->GetFunction();
    }
    ${implClassName}* imp = ${className}::toNative(holder);
    if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) {
        static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
        return sharedTemplate->GetFunction();
    }
    return privateTemplate->GetFunction();
}

END
}

sub GenerateConstructorGetter
{
    my $dataNode = shift;
    my $implClassName = shift;

    push(@implContentDecls, <<END);
static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS(\"DOM.$implClassName.constructors._get\");
    v8::Handle<v8::Value> data = info.Data();
    ASSERT(data->IsExternal() || data->IsNumber());
    WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data);
END

    if ($implClassName eq "DOMWindow") {
        push(@implContentDecls, <<END);
    // Get the proxy corresponding to the DOMWindow if possible to
    // make sure that the constructor function is constructed in the
    // context of the DOMWindow and not in the context of the caller.
    return V8DOMWrapper::constructorForType(type, V8DOMWindow::toNative(info.Holder()));
END
    } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
        push(@implContentDecls, <<END);
    return V8DOMWrapper::constructorForType(type, V8WorkerContext::toNative(info.Holder()));
END
    } else {
        push(@implContentDecls, "    return v8::Handle<v8::Value>();");
    }

    push(@implContentDecls, <<END);
}

END
}

sub GenerateNormalAttrGetter
{
    my $attribute = shift;
    my $dataNode = shift;
    my $implClassName = shift;
    my $interfaceName = shift;

    my $attrExt = $attribute->signature->extendedAttributes;
    my $attrName = $attribute->signature->name;
    my $attrType = GetTypeFromSignature($attribute->signature);
    my $nativeType = GetNativeTypeFromSignature($attribute->signature, -1);

    my $getterStringUsesImp = $implClassName ne "SVGNumber";
    my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);

    # Getter
    my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
    push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;

    push(@implContentDecls, <<END);
static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS(\"DOM.$implClassName.$attrName._get\");
END

    if ($svgNativeType) {
        my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
        if ($svgWrappedNativeType =~ /List/) {
            push(@implContentDecls, <<END);
    $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
END
        } else {
            push(@implContentDecls, <<END);
    $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());
    $svgWrappedNativeType& impInstance = wrapper->propertyReference();
END
            if ($getterStringUsesImp) {
                push(@implContentDecls, <<END);
    $svgWrappedNativeType* imp = &impInstance;
END
            }
        }
    } elsif ($attrExt->{"V8OnProto"} || $attrExt->{"V8Unforgeable"}) {
        if ($interfaceName eq "DOMWindow") {
            push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = info.Holder();
END
        } else {
            # perform lookup first
            push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
    if (holder.IsEmpty())
        return v8::Handle<v8::Value>();
END
        }
        push(@implContentDecls, <<END);
    ${implClassName}* imp = V8${implClassName}::toNative(holder);
END
    } else {
        my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
        my $url = $attribute->signature->extendedAttributes->{"URL"};
        if ($getterStringUsesImp && $reflect && !$url && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
            # Generate super-compact call for regular attribute getter:
            my $contentAttributeName = $reflect eq "VALUE_IS_MISSING" ? lc $attrName : $reflect;
            my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
            AddToImplIncludes("${namespace}.h");
            push(@implContentDecls, "    return getElementStringAttr(info, ${namespace}::${contentAttributeName}Attr);\n");
            push(@implContentDecls, "}\n\n");
            push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
            return;
            # Skip the rest of the function!
        }
        if ($attribute->signature->type eq "SerializedScriptValue" && $attrExt->{"CachedAttribute"}) {
            push(@implContentDecls, <<END);
    v8::Handle<v8::String> propertyName = v8::String::NewSymbol("${attrName}");
    v8::Handle<v8::Value> value = info.Holder()->GetHiddenValue(propertyName);
    if (!value.IsEmpty())
        return value;
END
        }
        push(@implContentDecls, <<END);
    ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
END
    }

    # Generate security checks if necessary
    if ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
        push(@implContentDecls, "    if (!V8BindingSecurity::shouldAllowAccessToNode(V8BindingState::Only(), imp->" . $attribute->signature->name . "()))\n        return v8::Handle<v8::Value>(v8::Null());\n\n");
    }

    my $useExceptions = 1 if @{$attribute->getterExceptions};
    if ($useExceptions) {
        AddToImplIncludes("ExceptionCode.h");
        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
    }

    my $returnType = GetTypeFromSignature($attribute->signature);
    my $getterString;

    if ($getterStringUsesImp) {
        my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);

        push(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContentDecls, "    ", 0, 0));

        push(@arguments, "ec") if $useExceptions;
        if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
            my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
            AddToImplIncludes("${implementedBy}.h");
            unshift(@arguments, "imp");
            $functionName = "${implementedBy}::${functionName}";
        } else {
            $functionName = "imp->${functionName}";
        }
        $getterString = "${functionName}(" . join(", ", @arguments) . ")";
    } else {
        $getterString = "impInstance";
    }

    my $result;
    my $wrapper;

    if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") {
        push(@implContentDecls, "    if (!imp->document())\n");
        push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
    }

    if ($useExceptions) {
        if ($nativeType =~ /^V8Parameter/) {
            push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $getterString) . ";\n");
        } else {
            push(@implContentDecls, "    $nativeType v = $getterString;\n");
        }
        push(@implContentDecls, GenerateSetDOMException("    ", "info.GetIsolate()"));

        if ($codeGenerator->ExtendedAttributeContains($attribute->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
            push(@implContentDecls, "    if (state.hadException())\n");
            push(@implContentDecls, "        return throwError(state.exception());\n");
        }

        $result = "v";
        $result .= ".release()" if (IsRefPtrType($returnType));
    } else {
        # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
        $result = $getterString;
        # Fix amigious conversion problem, by casting to the base type first ($getterString returns a type that inherits from SVGAnimatedEnumeration, not the base class directly).
        $result = "static_pointer_cast<SVGAnimatedEnumeration>($result)" if $returnType eq "SVGAnimatedEnumeration";
    }
 
    # Special case for readonly or Replaceable attributes (with a few exceptions). This attempts to ensure that JS wrappers don't get
    # garbage-collected prematurely when their lifetime is strongly tied to their owner. We accomplish this by inserting a reference to
    # the newly created wrapper into an internal field of the holder object.
    if (!IsNodeSubType($dataNode) && $attrName ne "self" && (IsWrapperType($returnType) && ($attribute->type =~ /^readonly/ || $attribute->signature->extendedAttributes->{"Replaceable"})
        && $returnType ne "EventTarget" && $returnType ne "SerializedScriptValue" && $returnType ne "DOMWindow" 
        && $returnType ne "MessagePortArray"
        && $returnType !~ /SVG/ && $returnType !~ /HTML/ && !IsDOMNodeType($returnType))) {

        my $arrayType = $codeGenerator->GetArrayType($returnType);
        if ($arrayType) {
            if (!$codeGenerator->SkipIncludeHeader($arrayType)) {
                AddToImplIncludes("V8$arrayType.h");
                AddToImplIncludes("$arrayType.h");
            }
            push(@implContentDecls, "    return v8Array(${getterString}, info.GetIsolate());\n");
            push(@implContentDecls, "}\n\n");
            return;
        }

        AddIncludesForType($returnType);
        # Check for a wrapper in the wrapper cache. If there is one, we know that a hidden reference has already
        # been created. If we don't find a wrapper, we create both a wrapper and a hidden reference.
        push(@implContentDecls, "    RefPtr<$returnType> result = ${getterString};\n");
        my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName);
        push(@implContentDecls, "    v8::Handle<v8::Value> wrapper = result.get() ? ${domMapFunction}.get(result.get()) : v8::Handle<v8::Object>();\n");
        push(@implContentDecls, "    if (wrapper.IsEmpty()) {\n");
        push(@implContentDecls, "        wrapper = toV8(result.get(), info.GetIsolate());\n");
        push(@implContentDecls, "        if (!wrapper.IsEmpty())\n");
        if ($dataNode->name eq "DOMWindow") {
            push(@implContentDecls, "            V8DOMWrapper::setNamedHiddenWindowReference(imp->frame(), \"${attrName}\", wrapper);\n");
        } else {
            push(@implContentDecls, "            V8DOMWrapper::setNamedHiddenReference(info.Holder(), \"${attrName}\", wrapper);\n");
        }
        push(@implContentDecls, "    }\n");
        push(@implContentDecls, "    return wrapper;\n");
        push(@implContentDecls, "}\n\n");
        push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
        return;
    }

    if ($codeGenerator->IsSVGAnimatedType($implClassName) and $codeGenerator->IsSVGTypeNeedingTearOff($attrType)) {
        AddToImplIncludes("V8$attrType.h");
        my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
        # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked.
        push(@implContentDecls, "    return toV8(static_cast<$svgNativeType*>($result), info.GetIsolate());\n");
    } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($attrType) and not $implClassName =~ /List$/) {
        AddToImplIncludes("V8$attrType.h");
        AddToImplIncludes("SVGPropertyTearOff.h");
        my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
        if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) {
            my $getter = $result;
            $getter =~ s/imp->//;
            $getter =~ s/\(\)//;

            my $updateMethod = "&${implClassName}::update" . $codeGenerator->WK_ucfirst($getter);

            my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($implClassName);
            if ($selfIsTearOffType) {
                AddToImplIncludes("SVGStaticPropertyWithParentTearOff.h");
                $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyWithParentTearOff<$implClassName, /;

                if ($result =~ /matrix/ and $implClassName eq "SVGTransform") {
                    # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform
                    # and a svgMatrix() method returning a SVGMatrix, used for the bindings.
                    $result =~ s/matrix/svgMatrix/;
                }

                push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(wrapper, $result, $updateMethod)), info.GetIsolate());\n");
            } else {
                AddToImplIncludes("SVGStaticPropertyTearOff.h");
                $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /;

                push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(imp, $result, $updateMethod)), info.GetIsolate());\n");
            }
        } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) {
            push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(imp, $result)), info.GetIsolate());\n");
        } elsif ($tearOffType =~ /SVG(Point|PathSeg)List/) {
            push(@implContentDecls, "    return toV8(WTF::getPtr($result), info.GetIsolate());\n");
        } else {
            push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create($result)), info.GetIsolate());\n");
        }
    } elsif ($attribute->signature->type eq "MessagePortArray") {
        AddToImplIncludes("V8Array.h");
        AddToImplIncludes("MessagePort.h");
        my $getterFunc = $codeGenerator->WK_lcfirst($attribute->signature->name);
        push(@implContentDecls, <<END);
    MessagePortArray* ports = imp->${getterFunc}();
    if (!ports)
        return v8::Array::New(0);
    MessagePortArray portsCopy(*ports);
    v8::Local<v8::Array> portArray = v8::Array::New(portsCopy.size());
    for (size_t i = 0; i < portsCopy.size(); ++i)
        portArray->Set(v8::Integer::New(i), toV8(portsCopy[i].get(), info.GetIsolate()));
    return portArray;
END
    } else {
        if ($attribute->signature->type eq "SerializedScriptValue" && $attrExt->{"CachedAttribute"}) {
            my $getterFunc = $codeGenerator->WK_lcfirst($attribute->signature->name);
            push(@implContentDecls, <<END);
    SerializedScriptValue* serialized = imp->${getterFunc}();
    value = serialized ? serialized->deserialize() : v8::Handle<v8::Value>(v8::Null());
    info.Holder()->SetHiddenValue(propertyName, value);
    return value;
END
        } else {
            push(@implContentDecls, "    " . ReturnNativeToJSValue($attribute->signature, $result, "info.GetIsolate()").";\n");
        }
    }

    push(@implContentDecls, "}\n\n");  # end of getter
    push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
}

sub GenerateNormalAttrSetter
{
    my $attribute = shift;
    my $dataNode = shift;
    my $implClassName = shift;
    my $interfaceName = shift;

    AddToImplIncludes("V8BindingMacros.h");

    my $attrName = $attribute->signature->name;
    my $attrExt = $attribute->signature->extendedAttributes;

    my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
    push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;

    push(@implContentDecls, "static void ${attrName}AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n");
    push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");

    # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
    # interface type, then if the incoming value does not implement that interface, a TypeError is
    # thrown rather than silently passing NULL to the C++ code.
    # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to both
    # strings and numbers, so do not throw TypeError if the attribute is of these types.
    if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
        my $argType = GetTypeFromSignature($attribute->signature);
        if (IsWrapperType($argType)) {
            push(@implContentDecls, "    if (!isUndefinedOrNull(value) && !V8${argType}::HasInstance(value)) {\n");
            push(@implContentDecls, "        V8Proxy::throwTypeError();\n");
            push(@implContentDecls, "        return;\n");
            push(@implContentDecls, "    }\n");
        }
    }

    my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
    if ($svgNativeType) {
        my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
        if ($svgWrappedNativeType =~ /List$/) {
            push(@implContentDecls, <<END);
    $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
END
        } else {
            AddToImplIncludes("ExceptionCode.h");
            push(@implContentDecls, "    $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());\n");
            push(@implContentDecls, "    if (wrapper->role() == AnimValRole) {\n");
            push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR, info.GetIsolate());\n");
            push(@implContentDecls, "        return;\n");
            push(@implContentDecls, "    }\n");
            push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
            push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
        }
    } elsif ($attrExt->{"V8OnProto"}) {
      if ($interfaceName eq "DOMWindow") {
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = info.Holder();
END
      } else {
        # perform lookup first
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
    if (holder.IsEmpty())
        return;
END
      }
    push(@implContentDecls, <<END);
    ${implClassName}* imp = V8${implClassName}::toNative(holder);
END
    } else {
        my $attrType = GetTypeFromSignature($attribute->signature);
        my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
        if ($reflect && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
            # Generate super-compact call for regular attribute setter:
            my $contentAttributeName = $reflect eq "VALUE_IS_MISSING" ? lc $attrName : $reflect;
            my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
            AddToImplIncludes("${namespace}.h");
            push(@implContentDecls, "    setElementStringAttr(info, ${namespace}::${contentAttributeName}Attr, value);\n");
            push(@implContentDecls, "}\n\n");
            push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
            return;
            # Skip the rest of the function!
        }

        push(@implContentDecls, <<END);
    ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
END
    }

    my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
    if ($attribute->signature->type eq "EventListener") {
        if ($dataNode->name eq "DOMWindow") {
            push(@implContentDecls, "    if (!imp->document())\n");
            push(@implContentDecls, "        return;\n");
        }
    } else {
        my $value = JSValueToNative($attribute->signature, "value", "info.GetIsolate()");
        my $arrayType = $codeGenerator->GetArrayType($nativeType);

        if ($nativeType =~ /^V8Parameter/) {
            push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $value, "VOID") . "\n");
        } elsif ($arrayType) {
            push(@implContentDecls, "    Vector<$arrayType> v = $value;\n");
        } else {
            push(@implContentDecls, "    $nativeType v = $value;\n");
        }
    }

    my $result = "v";
    my $returnType = GetTypeFromSignature($attribute->signature);
    if (IsRefPtrType($returnType) && !$codeGenerator->GetArrayType($returnType)) {
        $result = "WTF::getPtr(" . $result . ")";
    }

    my $useExceptions = 1 if @{$attribute->setterExceptions};

    if ($useExceptions) {
        AddToImplIncludes("ExceptionCode.h");
        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
    }

    if ($implClassName eq "SVGNumber") {
        push(@implContentDecls, "    *imp = $result;\n");
    } else {
        if ($attribute->signature->type eq "EventListener") {
            my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName);
            AddToImplIncludes("V8AbstractEventListener.h");
            if (!IsNodeSubType($dataNode)) {
                push(@implContentDecls, "    transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n");
            }
            if ($interfaceName eq "WorkerContext" and $attribute->signature->name eq "onerror") {
                AddToImplIncludes("V8EventListenerList.h");
                AddToImplIncludes("V8WorkerContextErrorHandler.h");
                push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WorkerContextErrorHandler>(value, true)");
            } elsif ($interfaceName eq "DOMWindow" and $attribute->signature->name eq "onerror") {
                AddToImplIncludes("V8EventListenerList.h");
                AddToImplIncludes("V8WindowErrorHandler.h");
                push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WindowErrorHandler>(value, true)");
            } else {
                push(@implContentDecls, "    imp->set$implSetterFunctionName(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)");
            }
            push(@implContentDecls, ", ec") if $useExceptions;
            push(@implContentDecls, ");\n");
        } else {
            my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);

            push(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContentDecls, "    ", 1, 0));

            push(@arguments, $result);
            push(@arguments, "ec") if $useExceptions;
            if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
                my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
                AddToImplIncludes("${implementedBy}.h");
                unshift(@arguments, "imp");
                $functionName = "${implementedBy}::${functionName}";
            } else {
                $functionName = "imp->${functionName}";
            }
            push(@implContentDecls, "    ${functionName}(" . join(", ", @arguments) . ");\n");
        }
    }

    if ($useExceptions) {
        push(@implContentDecls, "    if (UNLIKELY(ec))\n");
        push(@implContentDecls, "        V8Proxy::setDOMException(ec, info.GetIsolate());\n");
    }

    if ($codeGenerator->ExtendedAttributeContains($attribute->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
        push(@implContentDecls, "    if (state.hadException())\n");
        push(@implContentDecls, "        throwError(state.exception());\n");
    }

    if ($svgNativeType) {
        if ($useExceptions) {
            push(@implContentDecls, "    if (!ec)\n");
            push(@implContentDecls, "        wrapper->commitChange();\n");
        } else {
            push(@implContentDecls, "    wrapper->commitChange();\n");
        }
    }

    if ($attribute->signature->type eq "SerializedScriptValue" && $attribute->signature->extendedAttributes->{"CachedAttribute"}) {
        push(@implContentDecls, <<END);
    info.Holder()->DeleteHiddenValue(v8::String::NewSymbol("${attrName}")); // Invalidate the cached value.
END
    }

    push(@implContentDecls, "    return;\n");
    push(@implContentDecls, "}\n\n");  # end of setter
    push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
}

sub GetFunctionTemplateCallbackName
{
    my $function = shift;
    my $interfaceName = shift;

    my $name = $function->signature->name;

    if ($function->signature->extendedAttributes->{"Custom"} ||
        $function->signature->extendedAttributes->{"V8Custom"}) {
        if ($function->signature->extendedAttributes->{"Custom"} &&
            $function->signature->extendedAttributes->{"V8Custom"}) {
            die "Custom and V8Custom should be mutually exclusive!"
        }
        return "V8${interfaceName}::${name}Callback";
    } else {
        return "${interfaceName}V8Internal::${name}Callback";
    }
}

sub GenerateNewFunctionTemplate
{
    my $function = shift;
    my $interfaceName = shift;
    my $signature = shift;

    my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
    return "v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), $signature)";
}

sub GenerateEventListenerCallback
{
    my $implClassName = shift;
    my $requiresHiddenDependency = shift;
    my $functionName = shift;
    my $lookupType = ($functionName eq "add") ? "OrCreate" : "Only";
    my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
    my $hiddenDependencyAction = ($functionName eq "add") ? "create" : "remove";
 
    push(@implContentDecls, <<END);
static v8::Handle<v8::Value> ${functionName}EventListenerCallback(const v8::Arguments& args)
{
    INC_STATS("DOM.${implClassName}.${functionName}EventListener()");
    RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFind${lookupType});
    if (listener) {
        V8${implClassName}::toNative(args.Holder())->${functionName}EventListener(v8ValueToAtomicWebCoreString(args[0]), listener${passRefPtrHandling}, args[2]->BooleanValue());
END
    if ($requiresHiddenDependency) {
        push(@implContentDecls, <<END);
        ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], V8${implClassName}::eventListenerCacheIndex);
END
    }
    push(@implContentDecls, <<END);
    }
    return v8::Undefined();
}

END
}

sub GenerateParametersCheckExpression
{
    my $numParameters = shift;
    my $function = shift;

    my @andExpression = ();
    push(@andExpression, "args.Length() == $numParameters");
    my $parameterIndex = 0;
    foreach my $parameter (@{$function->parameters}) {
        last if $parameterIndex >= $numParameters;
        my $value = "args[$parameterIndex]";
        my $type = GetTypeFromSignature($parameter);

        # Only DOMString or wrapper types are checked.
        # For DOMString, Null, Undefined and any Object are accepted too, as
        # these are acceptable values for a DOMString argument (any Object can
        # be converted to a string via .toString).
        if ($codeGenerator->IsStringType($type)) {
            push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())");
        } elsif ($parameter->extendedAttributes->{"Callback"}) {
            # For Callbacks only checks if the value is null or object.
            push(@andExpression, "(${value}->IsNull() || ${value}->IsFunction())");
        } elsif (IsArrayType($type)) {
            # FIXME: Add proper support for T[], T[]?, sequence<T>.
            push(@andExpression, "(${value}->IsNull() || ${value}->IsArray())");
        } elsif (IsWrapperType($type)) {
            push(@andExpression, "(${value}->IsNull() || V8${type}::HasInstance($value))");
        }

        $parameterIndex++;
    }
    my $res = join(" && ", @andExpression);
    $res = "($res)" if @andExpression > 1;
    return $res;
}

sub GenerateFunctionParametersCheck
{
    my $function = shift;

    my @orExpression = ();
    my $numParameters = 0;
    foreach my $parameter (@{$function->parameters}) {
        if ($parameter->extendedAttributes->{"Optional"}) {
            push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
        }
        $numParameters++;
    }
    push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
    return join(" || ", @orExpression);
}

sub GenerateOverloadedFunctionCallback
{
    my $function = shift;
    my $dataNode = shift;
    my $implClassName = shift;

    # Generate code for choosing the correct overload to call. Overloads are
    # chosen based on the total number of arguments passed and the type of
    # values passed in non-primitive argument slots. When more than a single
    # overload is applicable, precedence is given according to the order of
    # declaration in the IDL.

    my $name = $function->signature->name;
    my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
    push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
    push(@implContentDecls, <<END);
static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
{
    INC_STATS(\"DOM.$implClassName.$name\");
END

    foreach my $overload (@{$function->{overloads}}) {
        my $parametersCheck = GenerateFunctionParametersCheck($overload);
        push(@implContentDecls, "    if ($parametersCheck)\n");
        push(@implContentDecls, "        return ${name}$overload->{overloadIndex}Callback(args);\n");
    }
    push(@implContentDecls, <<END);
    V8Proxy::throwTypeError();
    return notHandledByInterceptor();
END
    push(@implContentDecls, "}\n\n");
    push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
}

sub GenerateFunctionCallback
{
    my $function = shift;
    my $dataNode = shift;
    my $implClassName = shift;

    my $interfaceName = $dataNode->name;
    my $name = $function->signature->name;

    if (@{$function->{overloads}} > 1) {
        # Append a number to an overloaded method's name to make it unique:
        $name = $name . $function->{overloadIndex};
    }

    # Adding and removing event listeners are not standard callback behavior,
    # but they are extremely consistent across the various classes that take event listeners,
    # so we can generate them as a "special case".
    if ($name eq "addEventListener") {
        GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "add");
        return;
    } elsif ($name eq "removeEventListener") {
        GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "remove");
        return;
    }

    my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
    push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
    push(@implContentDecls, <<END);
static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
{
    INC_STATS(\"DOM.$implClassName.$name\");
END

    push(@implContentDecls, GenerateArgumentsCountCheck($function, $dataNode));

    my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);

    if ($svgNativeType) {
        my $nativeClassName = GetNativeType($implClassName); 
        if ($implClassName =~ /List$/) {
            push(@implContentDecls, "    $nativeClassName imp = V8${implClassName}::toNative(args.Holder());\n");
        } else {
            AddToImplIncludes("ExceptionCode.h");
            push(@implContentDecls, "    $nativeClassName wrapper = V8${implClassName}::toNative(args.Holder());\n");
            push(@implContentDecls, "    if (wrapper->role() == AnimValRole) {\n");
            push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR, args.GetIsolate());\n");
            push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
            push(@implContentDecls, "    }\n");
            my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
            push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
            push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
        }
    } elsif (!$function->isStatic) {
        push(@implContentDecls, <<END);
    ${implClassName}* imp = V8${implClassName}::toNative(args.Holder());
END
    }

    # Check domain security if needed
    if (($dataNode->extendedAttributes->{"CheckSecurity"}
       || $interfaceName eq "DOMWindow")
       && !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
    # We have not find real use cases yet.
    push(@implContentDecls, <<END);
    if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
        return v8::Handle<v8::Value>();
END
    }

    my $raisesExceptions = @{$function->raisesExceptions};
    if (!$raisesExceptions) {
        foreach my $parameter (@{$function->parameters}) {
            if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
                $raisesExceptions = 1;
            }
        }
    }

    if ($raisesExceptions) {
        AddToImplIncludes("ExceptionCode.h");
        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
        push(@implContentDecls, "    {\n");
        # The brace here is needed to prevent the ensuing 'goto fail's from jumping past constructors
        # of objects (like Strings) declared later, causing compile errors. The block scope ends
        # right before the label 'fail:'.
    }

    if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) {
        push(@implContentDecls, "    if (!V8BindingSecurity::shouldAllowAccessToNode(V8BindingState::Only(), imp->" . $function->signature->name . "(ec)))\n");
        push(@implContentDecls, "        return v8::Handle<v8::Value>(v8::Null());\n");
END
    }

    my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
    push(@implContentDecls, $parameterCheckString);

    # Build the function call string.
    push(@implContentDecls, GenerateFunctionCallString($function, $paramIndex, "    ", $implClassName, %replacements));

    if ($raisesExceptions) {
        push(@implContentDecls, "    }\n");
        push(@implContentDecls, "    fail:\n");
        push(@implContentDecls, "    V8Proxy::setDOMException(ec, args.GetIsolate());\n");
        push(@implContentDecls, "    return v8::Handle<v8::Value>();\n");
    }

    push(@implContentDecls, "}\n\n");
    push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
}

sub GenerateCallWith
{
    my $callWith = shift;
    return () unless $callWith;
    my $outputArray = shift;
    my $indent = shift;
    my $returnVoid = shift;
    my $emptyContext = shift;
    my $function = shift;

    my @callWithArgs;
    if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
        if ($emptyContext) {
            push(@$outputArray, $indent . "EmptyScriptState state;\n");
            push(@callWithArgs, "&state");
        } else {
            push(@$outputArray, $indent . "ScriptState* state = ScriptState::current();\n");
            push(@$outputArray, $indent . "if (!state)\n");
            push(@$outputArray, $indent . "    return" . ($returnVoid ? "" : " v8::Undefined()") . ";\n");
            push(@callWithArgs, "state");
        }
    }
    if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptExecutionContext")) {
        push(@$outputArray, $indent . "ScriptExecutionContext* scriptContext = getScriptExecutionContext();\n");
        push(@$outputArray, $indent . "if (!scriptContext)\n");
        push(@$outputArray, $indent . "    return" . ($returnVoid ? "" : " v8::Undefined()") . ";\n");
        push(@callWithArgs, "scriptContext");
    }
    if ($function and $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments")) {
        push(@$outputArray, $indent . "RefPtr<ScriptArguments> scriptArguments(createScriptArguments(args, " . @{$function->parameters} . "));\n");
        push(@callWithArgs, "scriptArguments");
        AddToImplIncludes("ScriptArguments.h");
    }
    if ($codeGenerator->ExtendedAttributeContains($callWith, "CallStack")) {
        push(@$outputArray, $indent . "RefPtr<ScriptCallStack> callStack(createScriptCallStackForInspector());\n");
        push(@$outputArray, $indent . "if (!callStack)\n");
        push(@$outputArray, $indent . "    return v8::Undefined();\n");
        push(@callWithArgs, "callStack");
        AddToImplIncludes("ScriptCallStack.h");
        AddToImplIncludes("ScriptCallStackFactory.h");
    }
    return @callWithArgs;
}

sub GenerateArgumentsCountCheck
{
    my $function = shift;
    my $dataNode = shift;

    my $numMandatoryParams = 0;
    my $optionalSeen = 0;
    foreach my $param (@{$function->parameters}) {
        if ($param->extendedAttributes->{"Optional"}) {
            $optionalSeen = 1;
        } else {
            die "An argument must not be declared to be optional unless all subsequent arguments to the operation are also optional." if $optionalSeen;
            $numMandatoryParams++;
        }
    }

    my $argumentsCountCheckString = "";
    if ($numMandatoryParams >= 1) {
        $argumentsCountCheckString .= "    if (args.Length() < $numMandatoryParams)\n";
        $argumentsCountCheckString .= "        return V8Proxy::throwNotEnoughArgumentsError();\n";
    }
    return $argumentsCountCheckString;
}

sub GetIndexOf
{
    my $paramName = shift;
    my @paramList = @_;
    my $index = 0;
    foreach my $param (@paramList) {
        if ($paramName eq $param) {
            return $index;
        }
        $index++;
    }
    return -1;
}

sub GenerateParametersCheck
{
    my $function = shift;
    my $implClassName = shift;

    my $parameterCheckString = "";
    my $paramIndex = 0;
    my @paramTransferListNames = ();
    my %replacements = ();

    foreach my $parameter (@{$function->parameters}) {
        TranslateParameter($parameter);

        my $parameterName = $parameter->name;

        # Optional arguments with [Optional] should generate an early call with fewer arguments.
        # Optional arguments with [Optional=...] should not generate the early call.
        my $optional = $parameter->extendedAttributes->{"Optional"};
        if ($optional && $optional ne "DefaultIsUndefined" && $optional ne "DefaultIsNullString" && !$parameter->extendedAttributes->{"Callback"}) {
            $parameterCheckString .= "    if (args.Length() <= $paramIndex) {\n";
            my $functionCall = GenerateFunctionCallString($function, $paramIndex, "    " x 2, $implClassName, %replacements);
            $parameterCheckString .= $functionCall;
            $parameterCheckString .= "    }\n";
        }

        my $parameterDefaultPolicy = "DefaultIsUndefined";
        if ($optional and $optional eq "DefaultIsNullString") {
            $parameterDefaultPolicy = "DefaultIsNullString";
        }

        if (GetIndexOf($parameterName, @paramTransferListNames) != -1) {
            $replacements{$parameterName} = "messagePortArray" . ucfirst($parameterName);
            $paramIndex++;
            next;
        }

        AddToImplIncludes("ExceptionCode.h");
        my $nativeType = GetNativeTypeFromSignature($parameter, $paramIndex);
        if ($parameter->extendedAttributes->{"Callback"}) {
            my $className = GetCallbackClassName($parameter->type);
            AddToImplIncludes("$className.h");
            if ($optional) {
                $parameterCheckString .= "    RefPtr<" . $parameter->type . "> $parameterName;\n";
                $parameterCheckString .= "    if (args.Length() > $paramIndex && !args[$paramIndex]->IsNull() && !args[$paramIndex]->IsUndefined()) {\n";
                $parameterCheckString .= "        if (!args[$paramIndex]->IsFunction())\n";
                $parameterCheckString .= "            return throwError(TYPE_MISMATCH_ERR);\n";
                $parameterCheckString .= "        $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n";
                $parameterCheckString .= "    }\n";
            } else {
                $parameterCheckString .= "    if (args.Length() <= $paramIndex || !args[$paramIndex]->IsFunction())\n";
                $parameterCheckString .= "        return throwError(TYPE_MISMATCH_ERR);\n";
                $parameterCheckString .= "    RefPtr<" . $parameter->type . "> $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n";
            }
        } elsif ($parameter->type eq "SerializedScriptValue") {
            AddToImplIncludes("SerializedScriptValue.h");
            my $useTransferList = 0;
            my $transferListName = "";
            my $TransferListName = "";
            if ($parameter->extendedAttributes->{"TransferList"}) {
                $transferListName = $parameter->extendedAttributes->{"TransferList"};
                push(@paramTransferListNames, $transferListName);

                my @allParameterNames = ();
                foreach my $parameter (@{$function->parameters}) {
                    push(@allParameterNames, $parameter->name);
                }
                my $transferListIndex = GetIndexOf($transferListName, @allParameterNames);
                if ($transferListIndex == -1) {
                    die "IDL error: TransferList refers to a nonexistent argument";
                }

                AddToImplIncludes("wtf/ArrayBuffer.h");
                AddToImplIncludes("MessagePort.h");
                $TransferListName = ucfirst($transferListName);
                $parameterCheckString .= "    MessagePortArray messagePortArray$TransferListName;\n";
                $parameterCheckString .= "    ArrayBufferArray arrayBufferArray$TransferListName;\n";
                $parameterCheckString .= "    if (args.Length() > $transferListIndex) {\n";
                $parameterCheckString .= "        if (!extractTransferables(args[$transferListIndex], messagePortArray$TransferListName, arrayBufferArray$TransferListName))\n";
                $parameterCheckString .= "            return throwError(\"Could not extract transferables\", V8Proxy::TypeError);\n";
                $parameterCheckString .= "    }\n";
                $useTransferList = 1;
            }
            $parameterCheckString .= "    bool ${parameterName}DidThrow = false;\n";
            if (!$useTransferList) {
                    $parameterCheckString .= "    $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], 0, 0, ${parameterName}DidThrow, args.GetIsolate());\n";
            } else {
                    $parameterCheckString .= "    $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], &messagePortArray$TransferListName, &arrayBufferArray$TransferListName, ${parameterName}DidThrow, args.GetIsolate());\n";
            }
            $parameterCheckString .= "    if (${parameterName}DidThrow)\n";
            $parameterCheckString .= "        return v8::Undefined();\n";
        } elsif (TypeCanFailConversion($parameter)) {
            $parameterCheckString .= "    $nativeType $parameterName = " .
                 JSValueToNative($parameter, "args[$paramIndex]", "args.GetIsolate()") . ";\n";
            $parameterCheckString .= "    if (UNLIKELY(!$parameterName)) {\n";
            $parameterCheckString .= "        ec = TYPE_MISMATCH_ERR;\n";
            $parameterCheckString .= "        goto fail;\n";
            $parameterCheckString .= "    }\n";
        } elsif ($nativeType =~ /^V8Parameter/) {
            my $value = JSValueToNative($parameter, "MAYBE_MISSING_PARAMETER(args, $paramIndex, $parameterDefaultPolicy)", "args.GetIsolate()");
            $parameterCheckString .= "    " . ConvertToV8Parameter($parameter, $nativeType, $parameterName, $value) . "\n";
        } else {
            AddToImplIncludes("V8BindingMacros.h");
            # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
            # interface type, then if the incoming value does not implement that interface, a TypeError
            # is thrown rather than silently passing NULL to the C++ code.
            # Per the Web IDL and ECMAScript specifications, incoming values can always be converted
            # to both strings and numbers, so do not throw TypeError if the argument is of these
            # types.
            if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
                my $argValue = "args[$paramIndex]";
                my $argType = GetTypeFromSignature($parameter);
                if (IsWrapperType($argType)) {
                    $parameterCheckString .= "    if (args.Length() > $paramIndex && !isUndefinedOrNull($argValue) && !V8${argType}::HasInstance($argValue)) {\n";
                    $parameterCheckString .= "        V8Proxy::throwTypeError();\n";
                    $parameterCheckString .= "        return notHandledByInterceptor();\n";
                    $parameterCheckString .= "    }\n";
                }
            }
            $parameterCheckString .= "    EXCEPTION_BLOCK($nativeType, $parameterName, " .
                 JSValueToNative($parameter, "MAYBE_MISSING_PARAMETER(args, $paramIndex, $parameterDefaultPolicy)", "args.GetIsolate()") . ");\n";
            if ($nativeType eq 'Dictionary') {
               $parameterCheckString .= "    if (args.Length() > $paramIndex && !$parameterName.isUndefinedOrNull() && !$parameterName.isObject()) {\n";
               if (@{$function->raisesExceptions}) {
                   $parameterCheckString .= "        ec = TYPE_MISMATCH_ERR;\n";
                   $parameterCheckString .= "        V8Proxy::setDOMException(ec, args.GetIsolate());\n";
               }
               $parameterCheckString .= "        return throwError(\"Not an object.\", V8Proxy::TypeError);\n";
               $parameterCheckString .= "    }\n";
            }
        }

        if ($parameter->extendedAttributes->{"IsIndex"}) {
            $parameterCheckString .= "    if (UNLIKELY($parameterName < 0)) {\n";
            $parameterCheckString .= "        ec = INDEX_SIZE_ERR;\n";
            $parameterCheckString .= "        goto fail;\n";
            $parameterCheckString .= "    }\n";
        }

        $paramIndex++;
    }
    return ($parameterCheckString, $paramIndex, %replacements);
}

sub GenerateConstructorCallback
{
    my $function = shift;
    my $dataNode = shift;
    my $implClassName = shift;

    my $raisesExceptions = @{$function->raisesExceptions};
    if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
        $raisesExceptions = 1;
    }
    if (!$raisesExceptions) {
        foreach my $parameter (@{$function->parameters}) {
            if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
                $raisesExceptions = 1;
            }
        }
    }

    my @beforeArgumentList;
    my @afterArgumentList;
    push(@implContent, <<END);
v8::Handle<v8::Value> V8${implClassName}::constructorCallback(const v8::Arguments& args)
{
    INC_STATS("DOM.${implClassName}.Constructor");

    if (!args.IsConstructCall())
        return throwError("DOM object constructor cannot be called as a function.", V8Proxy::TypeError);

    if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
        return args.Holder();
END

    push(@implContent, GenerateArgumentsCountCheck($function, $dataNode));

    if ($raisesExceptions) {
        AddToImplIncludes("ExceptionCode.h");
        push(@implContent, "\n");
        push(@implContent, "    ExceptionCode ec = 0;\n");
    }

    # FIXME: Currently [Constructor(...)] does not yet support [Optional] arguments.
    # It just supports [Optional=DefaultIsUndefined] or [Optional=DefaultIsNullString].
    my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
    push(@implContent, $parameterCheckString);

    if ($dataNode->extendedAttributes->{"CallWith"} && $dataNode->extendedAttributes->{"CallWith"} eq "ScriptExecutionContext") {
        push(@beforeArgumentList, "context");
        push(@implContent, <<END);

    ScriptExecutionContext* context = getScriptExecutionContext();
    if (!context)
        return throwError("${implClassName} constructor's associated context is not available", V8Proxy::ReferenceError);
END
    }

    if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
        push(@afterArgumentList, "ec");
    }

    my @argumentList;
    my $index = 0;
    foreach my $parameter (@{$function->parameters}) {
        last if $index eq $paramIndex;
        if ($replacements{$parameter->name}) {
            push(@argumentList, $replacements{$parameter->name});
        } else {
            push(@argumentList, $parameter->name);
        }
        $index++;
    }

    my $argumentString = join(", ", @beforeArgumentList, @argumentList, @afterArgumentList);
    push(@implContent, "\n");
    push(@implContent, "    RefPtr<${implClassName}> impl = ${implClassName}::create(${argumentString});\n");
    push(@implContent, "    v8::Handle<v8::Object> wrapper = args.Holder();\n");

    if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
        push(@implContent, "    if (ec)\n");
        push(@implContent, "        goto fail;\n");
    }

    my $DOMObject = GetDomMapName($dataNode, $implClassName);
    push(@implContent, <<END);

    V8DOMWrapper::setDOMWrapper(wrapper, &info, impl.get());
    V8DOMWrapper::setJSWrapperFor${DOMObject}(impl.release(), v8::Persistent<v8::Object>::New(wrapper), args.GetIsolate());
    return args.Holder();
END

    if ($raisesExceptions) {
        push(@implContent, "  fail:\n");
        push(@implContent, "    return throwError(ec);\n");
    }

    push(@implContent, "}\n");
    push(@implContent, "\n");
}

sub GenerateEventConstructorCallback
{
    my $dataNode = shift;
    my $implClassName = shift;

    AddToImplIncludes("Dictionary.h");
    AddToImplIncludes("V8BindingMacros.h");
    push(@implContent, <<END);
v8::Handle<v8::Value> V8${implClassName}::constructorCallback(const v8::Arguments& args)
{
    INC_STATS("DOM.${implClassName}.Constructor");

    if (!args.IsConstructCall())
        return throwError("DOM object constructor cannot be called as a function.", V8Proxy::TypeError);

    if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
        return args.Holder();

    if (args.Length() < 1)
        return V8Proxy::throwNotEnoughArgumentsError();

    STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, type, args[0]);
    ${implClassName}Init eventInit;
    if (args.Length() >= 2) {
        EXCEPTION_BLOCK(Dictionary, options, args[1]);
        if (!fill${implClassName}Init(eventInit, options))
            return v8::Undefined();
    }

    RefPtr<${implClassName}> event = ${implClassName}::create(type, eventInit);

    V8DOMWrapper::setDOMWrapper(args.Holder(), &info, event.get());
    V8DOMWrapper::setJSWrapperForDOMObject(event.release(), v8::Persistent<v8::Object>::New(args.Holder()), args.GetIsolate());
    return args.Holder();
}

bool fill${implClassName}Init(${implClassName}Init& eventInit, const Dictionary& options)
{
END

    foreach my $interfaceBase (@{$dataNode->parents}) {
        push(@implContent, <<END);
    if (!fill${interfaceBase}Init(eventInit, options))
        return false;

END
    }

    for (my $index = 0; $index < @{$dataNode->attributes}; $index++) {
        my $attribute = @{$dataNode->attributes}[$index];
        if ($attribute->signature->extendedAttributes->{"InitializedByEventConstructor"}) {
            my $attributeName = $attribute->signature->name;
            push(@implContent, "    options.get(\"$attributeName\", eventInit.$attributeName);\n");
        }
    }

    push(@implContent, <<END);
    return true;
}

END
}

sub GenerateNamedConstructorCallback
{
    my $function = shift;
    my $dataNode = shift;
    my $implClassName = shift;

    my $raisesExceptions = @{$function->raisesExceptions};
    if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
        $raisesExceptions = 1;
    }
    if (!$raisesExceptions) {
        foreach my $parameter (@{$function->parameters}) {
            if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
                $raisesExceptions = 1;
            }
        }
    }

    my @beforeArgumentList;
    my @afterArgumentList;

    if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
        push(@implContent, <<END);
WrapperTypeInfo V8${implClassName}Constructor::info = { V8${implClassName}Constructor::GetTemplate, V8${implClassName}::derefObject, V8${implClassName}::toActiveDOMObject, 0 };

END
    } else {
        push(@implContent, <<END);
WrapperTypeInfo V8${implClassName}Constructor::info = { V8${implClassName}Constructor::GetTemplate, 0, 0, 0 };

END
    }

    push(@implContent, <<END);
static v8::Handle<v8::Value> V8${implClassName}ConstructorCallback(const v8::Arguments& args)
{
    INC_STATS("DOM.${implClassName}.Constructor");

    if (!args.IsConstructCall())
        return throwError("DOM object constructor cannot be called as a function.", V8Proxy::TypeError);

    if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
        return args.Holder();

    Frame* frame = V8Proxy::retrieveFrameForCurrentContext();
    if (!frame)
        return throwError("${implClassName} constructor associated frame is unavailable", V8Proxy::ReferenceError);

    Document* document = frame->document();

    // Make sure the document is added to the DOM Node map. Otherwise, the ${implClassName} instance
    // may end up being the only node in the map and get garbage-collected prematurely.
    toV8(document, args.GetIsolate());

END

    push(@implContent, GenerateArgumentsCountCheck($function, $dataNode));

    if ($raisesExceptions) {
        AddToImplIncludes("ExceptionCode.h");
        push(@implContent, "\n");
        push(@implContent, "    ExceptionCode ec = 0;\n");
    }

    my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
    push(@implContent, $parameterCheckString);

    push(@beforeArgumentList, "document");

    if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
        push(@afterArgumentList, "ec");
    }

    my @argumentList;
    my $index = 0;
    foreach my $parameter (@{$function->parameters}) {
        last if $index eq $paramIndex;
        if ($replacements{$parameter->name}) {
            push(@argumentList, $replacements{$parameter->name});
        } else {
            push(@argumentList, $parameter->name);
        }
        $index++;
    }

    my $argumentString = join(", ", @beforeArgumentList, @argumentList, @afterArgumentList);
    push(@implContent, "\n");
    push(@implContent, "    RefPtr<${implClassName}> impl = ${implClassName}::createForJSConstructor(${argumentString});\n");
    push(@implContent, "    v8::Handle<v8::Object> wrapper = args.Holder();\n");

    if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
        push(@implContent, "    if (ec)\n");
        push(@implContent, "        goto fail;\n");
    }

    my $DOMObject = GetDomMapName($dataNode, $implClassName);
    push(@implContent, <<END);

    V8DOMWrapper::setDOMWrapper(wrapper, &V8${implClassName}Constructor::info, impl.get());
    V8DOMWrapper::setJSWrapperFor${DOMObject}(impl.release(), v8::Persistent<v8::Object>::New(wrapper), args.GetIsolate());
    return args.Holder();
END

    if ($raisesExceptions) {
        push(@implContent, "  fail:\n");
        push(@implContent, "    return throwError(ec);\n");
    }

    push(@implContent, "}\n");

    push(@implContent, <<END);

v8::Persistent<v8::FunctionTemplate> V8${implClassName}Constructor::GetTemplate()
{
    static v8::Persistent<v8::FunctionTemplate> cachedTemplate;
    if (!cachedTemplate.IsEmpty())
        return cachedTemplate;

    v8::HandleScope scope;
    v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8${implClassName}ConstructorCallback);

    v8::Local<v8::ObjectTemplate> instance = result->InstanceTemplate();
    instance->SetInternalFieldCount(V8${implClassName}::internalFieldCount);
    result->SetClassName(v8::String::New("${implClassName}"));
    result->Inherit(V8${implClassName}::GetTemplate());

    cachedTemplate = v8::Persistent<v8::FunctionTemplate>::New(result);
    return cachedTemplate;
}

END
}

sub GenerateBatchedAttributeData
{
    my $dataNode = shift;
    my $interfaceName = $dataNode->name;
    my $attributes = shift;

    foreach my $attribute (@$attributes) {
        my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
        push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
        GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", "");
        push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
    }
}

sub GenerateSingleBatchedAttribute
{
    my $interfaceName = shift;
    my $attribute = shift;
    my $delimiter = shift;
    my $indent = shift;
    my $attrName = $attribute->signature->name;
    my $attrExt = $attribute->signature->extendedAttributes;

    my $accessControl = "v8::DEFAULT";
    if ($attrExt->{"DoNotCheckSecurityOnGetter"}) {
        $accessControl = "v8::ALL_CAN_READ";
    } elsif ($attrExt->{"DoNotCheckSecurityOnSetter"}) {
        $accessControl = "v8::ALL_CAN_WRITE";
    } elsif ($attrExt->{"DoNotCheckSecurity"}) {
        $accessControl = "v8::ALL_CAN_READ";
        if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) {
            $accessControl .= " | v8::ALL_CAN_WRITE";
        }
    }
    if ($attrExt->{"V8Unforgeable"}) {
        $accessControl .= " | v8::PROHIBITS_OVERWRITING";
    }
    $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")";

    my $customAccessor =
        $attrExt->{"Custom"} ||
        $attrExt->{"CustomSetter"} ||
        $attrExt->{"CustomGetter"} ||
        $attrExt->{"V8Custom"} ||
        $attrExt->{"V8CustomSetter"} ||
        $attrExt->{"V8CustomGetter"} ||
        "";
    if ($customAccessor eq "VALUE_IS_MISSING") {
        # use the naming convension, interface + (capitalize) attr name
        $customAccessor = $interfaceName . "::" . $attrName;
    }

    my $getter;
    my $setter;
    my $propAttr = "v8::None";
    my $hasCustomSetter = 0;

    # Check attributes.
    if ($attrExt->{"NotEnumerable"}) {
        $propAttr .= " | v8::DontEnum";
    }
    if ($attrExt->{"V8Unforgeable"}) {
        $propAttr .= " | v8::DontDelete";
    }

    my $on_proto = "0 /* on instance */";
    my $data = "0 /* no data */";

    # Constructor
    if ($attribute->signature->type =~ /Constructor$/) {
        my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
        $constructorType =~ s/Constructor$//;
        # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
        # We do not generate the header file for NamedConstructor of class XXXX,
        # since we generate the NamedConstructor declaration into the header file of class XXXX.
        if ($constructorType !~ /Constructor$/ || $attribute->signature->extendedAttributes->{"V8CustomConstructor"} || $attribute->signature->extendedAttributes->{"CustomConstructor"}) {
            AddToImplIncludes("V8${constructorType}.h", $attribute->signature->extendedAttributes->{"Conditional"});
        }
        if ($customAccessor) {
            $getter = "V8${customAccessor}AccessorGetter";
        } else {
            $data = "&V8${constructorType}::info";
            $getter = "${interfaceName}V8Internal::${interfaceName}ConstructorGetter";
        }
        $setter = "0";
        $propAttr = "v8::ReadOnly";

    } else {
        # Default Getter and Setter
        $getter = "${interfaceName}V8Internal::${attrName}AttrGetter";
        $setter = "${interfaceName}V8Internal::${attrName}AttrSetter";

        # Custom Setter
        if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
            $hasCustomSetter = 1;
            $setter = "V8${customAccessor}AccessorSetter";
        }

        # Custom Getter
        if ($attrExt->{"CustomGetter"} || $attrExt->{"V8CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
            $getter = "V8${customAccessor}AccessorGetter";
        }
    }

    # Replaceable
    if ($attrExt->{"Replaceable"} && !$hasCustomSetter) {
        $setter = "0";
        # Handle the special case of window.top being marked as Replaceable.
        # FIXME: Investigate whether we could treat window.top as replaceable
        # and allow shadowing without it being a security hole.
        if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) {
            $propAttr .= " | v8::ReadOnly";
        }
    }

    # Read only attributes
    if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) {
        $setter = "0";
    }

    # An accessor can be installed on the proto
    if ($attrExt->{"V8OnProto"}) {
        $on_proto = "1 /* on proto */";
    }

    my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type .
                      "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";

    push(@implContent, $indent . "    \/\/ $commentInfo\n");
    push(@implContent, $indent . "    {\"$attrName\", $getter, $setter, $data, $accessControl, static_cast<v8::PropertyAttribute>($propAttr), $on_proto}" . $delimiter . "\n");
}

sub GenerateImplementationIndexer
{
    my $dataNode = shift;
    my $indexer = shift;
    my $interfaceName = $dataNode->name;

    # FIXME: Figure out what NumericIndexedGetter is really supposed to do. Right now, it's only set on WebGL-related files.
    my $hasCustomSetter = $dataNode->extendedAttributes->{"CustomIndexedSetter"} && !$dataNode->extendedAttributes->{"NumericIndexedGetter"};
    my $hasGetter = $dataNode->extendedAttributes->{"IndexedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};

    # FIXME: Find a way to not have to special-case HTMLOptionsCollection.
    if ($interfaceName eq "HTMLOptionsCollection") {
        $hasGetter = 1;
    }

    # FIXME: Investigate and remove this nastinesss. In V8, named property handling and indexer handling are apparently decoupled,
    # which means that object[X] where X is a number doesn't reach named property indexer. So we need to provide
    # simplistic, mirrored indexer handling in addition to named property handling.
    my $isSpecialCase = exists $indexerSpecialCases{$interfaceName};
    if ($isSpecialCase) {
        $hasGetter = 1;
        if ($dataNode->extendedAttributes->{"CustomNamedSetter"}) {
            $hasCustomSetter = 1;
        }
    }

    if (!$hasGetter) {
        return;
    }

    AddToImplIncludes("V8Collection.h");

    if (!$indexer) {
        $indexer = $codeGenerator->FindSuperMethod($dataNode, "item");
    }

    my $indexerType = $indexer ? $indexer->type : 0;

    # FIXME: Remove this once toV8 helper methods are implemented (see https://bugs.webkit.org/show_bug.cgi?id=32563).
    if ($interfaceName eq "WebKitCSSKeyframesRule") {
        $indexerType = "WebKitCSSKeyframeRule";
    }

    if ($indexerType && !$hasCustomSetter) {
        if ($indexerType eq "DOMString") {
            my $conversion = $indexer->extendedAttributes->{"TreatReturnedNullStringAs"};
            if ($conversion && $conversion eq "Null") {
                push(@implContent, <<END);
    setCollectionStringOrNullIndexedGetter<${interfaceName}>(desc);
END
            } else {
                push(@implContent, <<END);
    setCollectionStringIndexedGetter<${interfaceName}>(desc);
END
            }
        } else {
            push(@implContent, <<END);
    setCollectionIndexedGetter<${interfaceName}, ${indexerType}>(desc);
END
            # Include the header for this indexer type, because setCollectionIndexedGetter() requires toV8() for this type.
            AddToImplIncludes("V8${indexerType}.h");
        }

        return;
    }

    my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
    my $hasEnumerator = !$isSpecialCase && IsNodeSubType($dataNode);
    my $setOn = "Instance";

    # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
    # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
    # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
    # on the object.
    if ($interfaceName eq "DOMWindow") {
        $setOn = "Prototype";
        $hasDeleter = 0;
    }

    push(@implContent, "    desc->${setOn}Template()->SetIndexedPropertyHandler(V8${interfaceName}::indexedPropertyGetter");
    push(@implContent, $hasCustomSetter ? ", V8${interfaceName}::indexedPropertySetter" : ", 0");
    push(@implContent, ", 0"); # IndexedPropertyQuery -- not being used at the moment.
    push(@implContent, $hasDeleter ? ", V8${interfaceName}::indexedPropertyDeleter" : ", 0");
    push(@implContent, ", nodeCollectionIndexedPropertyEnumerator<${interfaceName}>") if $hasEnumerator;
    push(@implContent, ");\n");
}

sub GenerateImplementationNamedPropertyGetter
{
    my $dataNode = shift;
    my $namedPropertyGetter = shift;
    my $interfaceName = $dataNode->name;
    my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"CustomNamedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};

    # FIXME: Remove hard-coded HTMLOptionsCollection reference by changing HTMLOptionsCollection to not inherit
    # from HTMLCollection per W3C spec (http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#HTMLOptionsCollection).
    if ($interfaceName eq "HTMLOptionsCollection") {
        $interfaceName = "HTMLCollection";
        $hasCustomNamedGetter = 1;
    }

    if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
        $hasCustomNamedGetter = 1;
    }

    if ($interfaceName eq "HTMLDocument") {
        $hasCustomNamedGetter = 0;
    }

    my $hasGetter = $dataNode->extendedAttributes->{"NamedGetter"} || $hasCustomNamedGetter;
    if (!$hasGetter) {
        return;
    }

    if (!$namedPropertyGetter) {
        $namedPropertyGetter = $codeGenerator->FindSuperMethod($dataNode, "namedItem");
    }

    if ($namedPropertyGetter && $namedPropertyGetter->type ne "Node" && !$namedPropertyGetter->extendedAttributes->{"Custom"} && !$hasCustomNamedGetter) {
        AddToImplIncludes("V8Collection.h");
        my $type = $namedPropertyGetter->type;
        push(@implContent, <<END);
    setCollectionNamedGetter<${interfaceName}, ${type}>(desc);
END
        return;
    }

    my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"CustomNamedSetter"};
    my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
    my $hasEnumerator = $dataNode->extendedAttributes->{"CustomEnumerateProperty"};
    my $setOn = "Instance";

    # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
    # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
    # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
    # on the object.
    if ($interfaceName eq "DOMWindow") {
        $setOn = "Prototype";
        $hasDeleter = 0;
        $hasEnumerator = 0;
    }

    push(@implContent, "    desc->${setOn}Template()->SetNamedPropertyHandler(V8${interfaceName}::namedPropertyGetter, ");
    push(@implContent, $hasCustomNamedSetter ? "V8${interfaceName}::namedPropertySetter, " : "0, ");
    # If there is a custom enumerator, there MUST be custom query to properly communicate property attributes.
    push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyQuery, " : "0, ");
    push(@implContent, $hasDeleter ? "V8${interfaceName}::namedPropertyDeleter, " : "0, ");
    push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyEnumerator" : "0");
    push(@implContent, ");\n");
}

sub GenerateImplementationCustomCall
{
    my $dataNode = shift;
    my $interfaceName = $dataNode->name;
    my $hasCustomCall = $dataNode->extendedAttributes->{"CustomCall"};

    if ($hasCustomCall) {
        push(@implContent, "    desc->InstanceTemplate()->SetCallAsFunctionHandler(V8${interfaceName}::callAsFunctionCallback);\n");
    }
}

sub GenerateImplementationMasqueradesAsUndefined
{
    my $dataNode = shift;
    if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"})
    {
        push(@implContent, "    desc->InstanceTemplate()->MarkAsUndetectable();\n");
    }
}

sub IsTypedArrayType
{
    my $type = shift;
    return 1 if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView"));
    return 1 if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array"));
    return 1 if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array"));
    return 1 if (($type eq "Float32Array") or ($type eq "Float64Array"));
    return 0;
}


sub GenerateImplementation
{
    my $object = shift;
    my $dataNode = shift;
    my $interfaceName = $dataNode->name;
    my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($dataNode);
    my $className = "V8$interfaceName";
    my $implClassName = $interfaceName;

    # - Add default header template
    push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
         
    AddToImplIncludes("RuntimeEnabledFeatures.h");
    AddToImplIncludes("V8Proxy.h");
    AddToImplIncludes("V8Binding.h");
    AddToImplIncludes("V8BindingState.h");
    AddToImplIncludes("V8DOMWrapper.h");
    AddToImplIncludes("V8IsolatedContext.h");

    AddIncludesForType($interfaceName);

    my $toActive = $dataNode->extendedAttributes->{"ActiveDOMObject"} ? "${className}::toActiveDOMObject" : "0";

    # Find the super descriptor.
    my $parentClass = "";
    my $parentClassTemplate = "";
    foreach (@{$dataNode->parents}) {
        my $parent = $codeGenerator->StripModule($_);
        if ($parent eq "EventTarget") {
            next;
        }
        AddToImplIncludes("V8${parent}.h");
        $parentClass = "V8" . $parent;
        $parentClassTemplate = $parentClass . "::GetTemplate()";
        last;
    }
    push(@implContentDecls, "namespace WebCore {\n\n");
    my $parentClassInfo = $parentClass ? "&${parentClass}::info" : "0";
    push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, ${toActive}, ${parentClassInfo} };\n\n");   
    push(@implContentDecls, "namespace ${interfaceName}V8Internal {\n\n");
    push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");

    my $hasConstructors = 0;
    # Generate property accessors for attributes.
    for (my $index = 0; $index < @{$dataNode->attributes}; $index++) {
        my $attribute = @{$dataNode->attributes}[$index];
        my $attrType = $attribute->signature->type;

        # Generate special code for the constructor attributes.
        if ($attrType =~ /Constructor$/) {
            if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
                $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
                $hasConstructors = 1;
            }
            next;
        }

        if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") {
            $attribute->signature->extendedAttributes->{"V8OnProto"} = 1;
        }

        if ($attrType eq "SerializedScriptValue") {
            AddToImplIncludes("SerializedScriptValue.h");
        }

        # Do not generate accessor if this is a custom attribute.  The
        # call will be forwarded to a hand-written accessor
        # implementation.
        if ($attribute->signature->extendedAttributes->{"Custom"} ||
            $attribute->signature->extendedAttributes->{"V8Custom"}) {
            next;
        }

        # Generate the accessor.
        if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
            $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
            GenerateNormalAttrGetter($attribute, $dataNode, $implClassName, $interfaceName);
        }
        if (!$attribute->signature->extendedAttributes->{"CustomSetter"} &&
            !$attribute->signature->extendedAttributes->{"V8CustomSetter"} &&
            !$attribute->signature->extendedAttributes->{"Replaceable"} &&
            $attribute->type !~ /^readonly/ &&
            !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) {
            GenerateNormalAttrSetter($attribute, $dataNode, $implClassName, $interfaceName);
        }
    }

    if ($hasConstructors) {
        GenerateConstructorGetter($dataNode, $implClassName);
    }

    my $indexer;
    my $namedPropertyGetter;
    # Generate methods for functions.
    foreach my $function (@{$dataNode->functions}) {
        my $isCustom = $function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"};
        if (!$isCustom) {
            GenerateFunctionCallback($function, $dataNode, $implClassName);
            if ($function->{overloadIndex} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) {
                GenerateOverloadedFunctionCallback($function, $dataNode, $implClassName);
            }
        }

        if ($function->signature->name eq "item") {
            $indexer = $function->signature;
        }

        if ($function->signature->name eq "namedItem") {
            $namedPropertyGetter = $function->signature;
        }

        # If the function does not need domain security check, we need to
        # generate an access getter that returns different function objects
        # for different calling context.
        if (($dataNode->extendedAttributes->{"CheckSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
            if (!$isCustom || $function->{overloadIndex} == 1) {
                GenerateDomainSafeFunctionGetter($function, $implClassName);
            }
        }
    }

    # Attributes
    my $attributes = $dataNode->attributes;

    # For the DOMWindow interface we partition the attributes into the
    # ones that disallows shadowing and the rest.
    my @disallowsShadowing;
    # Also separate out attributes that are enabled at runtime so we can process them specially.
    my @enabledAtRuntime;
    my @normal;
    foreach my $attribute (@$attributes) {

        if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"V8Unforgeable"}) {
            push(@disallowsShadowing, $attribute);
        } elsif ($attribute->signature->extendedAttributes->{"V8EnabledAtRuntime"}) {
            push(@enabledAtRuntime, $attribute);
        } else {
            push(@normal, $attribute);
        }
    }
    $attributes = \@normal;
    # Put the attributes that disallow shadowing on the shadow object.
    if (@disallowsShadowing) {
        push(@implContent, "static const BatchedAttribute shadowAttrs[] = {\n");
        GenerateBatchedAttributeData($dataNode, \@disallowsShadowing);
        push(@implContent, "};\n\n");
    }

    my $has_attributes = 0;
    if (@$attributes) {
        $has_attributes = 1;
        push(@implContent, "static const BatchedAttribute ${interfaceName}Attrs[] = {\n");
        GenerateBatchedAttributeData($dataNode, $attributes);
        push(@implContent, "};\n\n");
    }

    # Setup table of standard callback functions
    my $num_callbacks = 0;
    my $has_callbacks = 0;
    foreach my $function (@{$dataNode->functions}) {
        # Only one table entry is needed for overloaded methods:
        next if $function->{overloadIndex} > 1;

        my $attrExt = $function->signature->extendedAttributes;
        # Don't put any nonstandard functions into this table:
        if ($attrExt->{"V8Unforgeable"}) {
            next;
        }
        if ($function->isStatic) {
            next;
        }
        if ($attrExt->{"V8EnabledAtRuntime"} || RequiresCustomSignature($function) || $attrExt->{"V8DoNotCheckSignature"}) {
            next;
        }
        if ($attrExt->{"DoNotCheckSecurity"} &&
            ($dataNode->extendedAttributes->{"CheckSecurity"} || $interfaceName eq "DOMWindow")) {
            next;
        }
        if ($attrExt->{"NotEnumerable"} || $attrExt->{"V8ReadOnly"}) {
            next;
        }
        if (!$has_callbacks) {
            $has_callbacks = 1;
            push(@implContent, "static const BatchedCallback ${interfaceName}Callbacks[] = {\n");
        }
        my $name = $function->signature->name;
        my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
        my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
        push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
        push(@implContent, <<END);
    {"$name", $callback},
END
        push(@implContent, "#endif\n") if $conditionalString;
        $num_callbacks++;
    }
    push(@implContent, "};\n\n")  if $has_callbacks;

    # Setup constants
    my $has_constants = 0;
    my @constantsEnabledAtRuntime;
    if (@{$dataNode->constants}) {
        $has_constants = 1;
        push(@implContent, "static const BatchedConstant ${interfaceName}Consts[] = {\n");
    }
    foreach my $constant (@{$dataNode->constants}) {
        my $name = $constant->name;
        my $value = $constant->value;
        my $attrExt = $constant->extendedAttributes;
        my $conditional = $attrExt->{"Conditional"};
        my $implementedBy = $attrExt->{"ImplementedBy"};
        if ($implementedBy) {
            AddToImplIncludes("${implementedBy}.h");
        }
        if ($attrExt->{"V8EnabledAtRuntime"}) {
            push(@constantsEnabledAtRuntime, $constant);
        } else {
            # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl
            # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF".  It would be better if we
            # handled this here, and converted it to a -1 constant in the c++ output.
            if ($conditional) {
                my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
                push(@implContent, "#if ${conditionalString}\n");
            }
            push(@implContent, <<END);
    {"${name}", static_cast<signed int>($value)},
END
            push(@implContent, "#endif\n") if $conditional;
        }
    }
    if ($has_constants) {
        push(@implContent, "};\n\n");
        push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode));
    }

    push(@implContentDecls, "} // namespace ${interfaceName}V8Internal\n\n");

    if ($dataNode->extendedAttributes->{"NamedConstructor"} && !($dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
        GenerateNamedConstructorCallback($dataNode->constructor, $dataNode, $interfaceName);
    } elsif ($dataNode->extendedAttributes->{"Constructor"} && !($dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
        GenerateConstructorCallback($dataNode->constructor, $dataNode, $interfaceName);
    } elsif (IsConstructorTemplate($dataNode, "Event")) {
        GenerateEventConstructorCallback($dataNode, $interfaceName);
    }

    my $access_check = "";
    if ($dataNode->extendedAttributes->{"CheckSecurity"} && !($interfaceName eq "DOMWindow")) {
        $access_check = "instance->SetAccessCheckCallbacks(V8${interfaceName}::namedSecurityCheck, V8${interfaceName}::indexedSecurityCheck, v8::External::Wrap(&V8${interfaceName}::info));";
    }

    # For the DOMWindow interface, generate the shadow object template
    # configuration method.
    if ($implClassName eq "DOMWindow") {
        push(@implContent, <<END);
static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ)
{
    batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs));

    // Install a security handler with V8.
    templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info));
    templ->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
    return templ;
}
END
    }

    if (!$parentClassTemplate) {
        $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()";
    }

    # Generate the template configuration method
    push(@implContent,  <<END);
static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc)
{
    desc->ReadOnlyPrototype();

    v8::Local<v8::Signature> defaultSignature;
END
    if ($dataNode->extendedAttributes->{"V8EnabledAtRuntime"}) {
        my $enable_function = GetRuntimeEnableFunctionName($dataNode);
        push(@implContent, <<END);
    if (!${enable_function}())
        defaultSignature = configureTemplate(desc, \"\", $parentClassTemplate, V8${interfaceName}::internalFieldCount, 0, 0, 0, 0);
    else
END
    }
    push(@implContent,  <<END);
    defaultSignature = configureTemplate(desc, \"${visibleInterfaceName}\", $parentClassTemplate, V8${interfaceName}::internalFieldCount,
END
    # Set up our attributes if we have them
    if ($has_attributes) {
        push(@implContent, <<END);
        ${interfaceName}Attrs, WTF_ARRAY_LENGTH(${interfaceName}Attrs),
END
    } else {
        push(@implContent, <<END);
        0, 0,
END
    }

    if ($has_callbacks) {
        push(@implContent, <<END);
        ${interfaceName}Callbacks, WTF_ARRAY_LENGTH(${interfaceName}Callbacks));
END
    } else {
        push(@implContent, <<END);
        0, 0);
END
    }
    
    AddToImplIncludes("wtf/UnusedParam.h");
    push(@implContent, <<END);
    UNUSED_PARAM(defaultSignature); // In some cases, it will not be used.
END

    if (IsConstructable($dataNode)) {
        push(@implContent, <<END);
    desc->SetCallHandler(V8${interfaceName}::constructorCallback);
END
    }

    if ($access_check or @enabledAtRuntime or @{$dataNode->functions} or $has_constants) {
        push(@implContent,  <<END);
    v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
    v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate();
    UNUSED_PARAM(instance); // In some cases, it will not be used.
    UNUSED_PARAM(proto); // In some cases, it will not be used.
END
    }

    push(@implContent,  "    $access_check\n");

    # Setup the enable-at-runtime attrs if we have them
    foreach my $runtime_attr (@enabledAtRuntime) {
        my $enable_function = GetRuntimeEnableFunctionName($runtime_attr->signature);
        my $conditionalString = $codeGenerator->GenerateConditionalString($runtime_attr->signature);
        push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
        push(@implContent, "    if (${enable_function}()) {\n");
        push(@implContent, "        static const BatchedAttribute attrData =\\\n");
        GenerateSingleBatchedAttribute($interfaceName, $runtime_attr, ";", "    ");
        push(@implContent, <<END);
        configureAttribute(instance, proto, attrData);
    }
END
        push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
    }

    # Setup the enable-at-runtime constants if we have them
    foreach my $runtime_const (@constantsEnabledAtRuntime) {
        my $enable_function = GetRuntimeEnableFunctionName($runtime_const);
        my $conditionalString = $codeGenerator->GenerateConditionalString($runtime_const);
        my $name = $runtime_const->name;
        my $value = $runtime_const->value;
        push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
        push(@implContent, "    if (${enable_function}()) {\n");
        push(@implContent, <<END);
        static const BatchedConstant constData = {"${name}", static_cast<signed int>(${value})};
        batchConfigureConstants(desc, proto, &constData, 1);
END
        push(@implContent, "    }\n");
        push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
    }

    GenerateImplementationIndexer($dataNode, $indexer);
    GenerateImplementationNamedPropertyGetter($dataNode, $namedPropertyGetter);
    GenerateImplementationCustomCall($dataNode);
    GenerateImplementationMasqueradesAsUndefined($dataNode);

    # Define our functions with Set() or SetAccessor()
    my $total_functions = 0;
    foreach my $function (@{$dataNode->functions}) {
        # Only one accessor is needed for overloaded methods:
        next if $function->{overloadIndex} > 1;

        $total_functions++;
        my $attrExt = $function->signature->extendedAttributes;
        my $name = $function->signature->name;

        my $property_attributes = "v8::DontDelete";
        if ($attrExt->{"NotEnumerable"}) {
            $property_attributes .= " | v8::DontEnum";
        }
        if ($attrExt->{"V8ReadOnly"}) {
            $property_attributes .= " | v8::ReadOnly";
        }

        my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";

        my $template = "proto";
        if ($attrExt->{"V8Unforgeable"}) {
            $template = "instance";
        }
        if ($function->isStatic) {
            $template = "desc";
        }

        my $conditional = "";
        if ($attrExt->{"V8EnabledAtRuntime"}) {
            # Only call Set()/SetAccessor() if this method should be enabled
            my $enable_function = GetRuntimeEnableFunctionName($function->signature);
            $conditional = "if (${enable_function}())\n        ";
        }

        if ($attrExt->{"DoNotCheckSecurity"} &&
            ($dataNode->extendedAttributes->{"CheckSecurity"} || $interfaceName eq "DOMWindow")) {
            # Mark the accessor as ReadOnly and set it on the proto object so
            # it can be shadowed. This is really a hack to make it work.
            # There are several sceneria to call into the accessor:
            #   1) from the same domain: "window.open":
            #      the accessor finds the DOM wrapper in the proto chain;
            #   2) from the same domain: "window.__proto__.open":
            #      the accessor will NOT find a DOM wrapper in the prototype chain
            #   3) from another domain: "window.open":
            #      the access find the DOM wrapper in the prototype chain
            #   "window.__proto__.open" from another domain will fail when
            #   accessing '__proto__'
            #
            # The solution is very hacky and fragile, it really needs to be replaced
            # by a better solution.
            $property_attributes .= " | v8::ReadOnly";
            push(@implContent, <<END);

    // $commentInfo
    ${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));
END
            $num_callbacks++;
            next;
        }

        my $signature = "defaultSignature";
        if ($attrExt->{"V8DoNotCheckSignature"} || $function->isStatic) {
            $signature = "v8::Local<v8::Signature>()";
        }

        if (RequiresCustomSignature($function)) {
            $signature = "${name}Signature";
            push(@implContent, "\n    // Custom Signature '$name'\n", CreateCustomSignature($function));
        }

        # Normal function call is a template
        my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);

        if ($property_attributes eq "v8::DontDelete") {
            $property_attributes = "";
        } else {
            $property_attributes = ", static_cast<v8::PropertyAttribute>($property_attributes)";
        }

        if ($template eq "proto" && $conditional eq "" && $signature eq "defaultSignature" && $property_attributes eq "") {
            # Standard type of callback, already created in the batch, so skip it here.
            next;
        }

        my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
        push(@implContent, "#if ${conditionalString}\n") if $conditionalString;

        push(@implContent, <<END);
    ${conditional}$template->Set(v8::String::New("$name"), v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), ${signature})$property_attributes);
END

        push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
        $num_callbacks++;
    }

    die "Wrong number of callbacks generated for $interfaceName ($num_callbacks, should be $total_functions)" if $num_callbacks != $total_functions;

    if ($has_constants) {
        push(@implContent, <<END);
    batchConfigureConstants(desc, proto, ${interfaceName}Consts, WTF_ARRAY_LENGTH(${interfaceName}Consts));
END
    }

    # Special cases
    if ($interfaceName eq "DOMWindow") {
        push(@implContent, <<END);

    proto->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
    desc->SetHiddenPrototype(true);
    instance->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
    // Set access check callbacks, but turned off initially.
    // When a context is detached from a frame, turn on the access check.
    // Turning on checks also invalidates inline caches of the object.
    instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false);
END
    }
    if ($interfaceName eq "HTMLDocument") {
        push(@implContent, <<END);
    desc->SetHiddenPrototype(true);
END
    }
    if ($interfaceName eq "Location") {
        push(@implContent, <<END);

    // For security reasons, these functions are on the instance instead
    // of on the prototype object to ensure that they cannot be overwritten.
    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));
    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));
    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));
END
    }

    my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
    push(@implContent, <<END);

    // Custom toString template
    desc->Set(getToStringName(), getToStringTemplate());
    return desc;
}

v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate()
{
    V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
    V8BindingPerIsolateData::TemplateMap::iterator result = data->rawTemplateMap().find(&info);
    if (result != data->rawTemplateMap().end())
        return result->second;

    v8::HandleScope handleScope;
    v8::Persistent<v8::FunctionTemplate> templ = createRawTemplate();
    data->rawTemplateMap().add(&info, templ);
    return templ;
}

v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()
{
    V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
    V8BindingPerIsolateData::TemplateMap::iterator result = data->templateMap().find(&info);
    if (result != data->templateMap().end())
        return result->second;

    v8::HandleScope handleScope;
    v8::Persistent<v8::FunctionTemplate> templ =
        Configure${className}Template(GetRawTemplate());
    data->templateMap().add(&info, templ);
    return templ;
}

bool ${className}::HasInstance(v8::Handle<v8::Value> value)
{
    return GetRawTemplate()->HasInstance(value);
}

END

    if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
        # MessagePort is handled like an active dom object even though it doesn't inherit
        # from ActiveDOMObject, so don't try to cast it to ActiveDOMObject.
        my $returnValue = $interfaceName eq "MessagePort" ? "0" : "toNative(object)";
        push(@implContent, <<END);
ActiveDOMObject* ${className}::toActiveDOMObject(v8::Handle<v8::Object> object)
{
    return ${returnValue};
}      
END
    }

    if ($implClassName eq "DOMWindow") {
        push(@implContent, <<END);
v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate()
{
    static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObjectCache;
    if (V8DOMWindowShadowObjectCache.IsEmpty()) {
        V8DOMWindowShadowObjectCache = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
        ConfigureShadowObjectTemplate(V8DOMWindowShadowObjectCache);
    }
    return V8DOMWindowShadowObjectCache;
}
END
    }

    GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType);

    push(@implContent, <<END);

void ${className}::derefObject(void* object)
{
    static_cast<${nativeType}*>(object)->deref();
}

} // namespace WebCore
END

    my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
    push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
    
    # We've already added the header for this file in implFixedHeader, so remove
    # it from implIncludes to ensure we don't #include it twice.
    delete $implIncludes{"${className}.h"};
}

sub GenerateHeaderContentHeader
{
    my $dataNode = shift;
    my $className = "V8" . $dataNode->name;
    my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);

    my @headerContentHeader = split("\r", $headerTemplate);

    push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString;
    push(@headerContentHeader, "\n#ifndef ${className}" . "_h");
    push(@headerContentHeader, "\n#define ${className}" . "_h\n\n");
    return @headerContentHeader;
}

sub GenerateImplementationContentHeader
{
    my $dataNode = shift;
    my $className = "V8" . $dataNode->name;
    my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);

    my @implContentHeader = split("\r", $headerTemplate);

    push(@implContentHeader, "\n#include \"config.h\"\n");
    push(@implContentHeader, "#include \"${className}.h\"\n\n");
    push(@implContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
    return @implContentHeader;
}

sub GenerateCallbackHeader
{
    my $object = shift;
    my $dataNode = shift;

    my $interfaceName = $dataNode->name;
    my $className = "V8$interfaceName";


    # - Add default header template
    push(@headerContent, GenerateHeaderContentHeader($dataNode));

    my @unsortedIncludes = ();
    push(@unsortedIncludes, "#include \"ActiveDOMCallback.h\"");
    push(@unsortedIncludes, "#include \"$interfaceName.h\"");
    push(@unsortedIncludes, "#include \"WorldContextHandle.h\"");
    push(@unsortedIncludes, "#include <v8.h>");
    push(@unsortedIncludes, "#include <wtf/Forward.h>");
    push(@headerContent, join("\n", sort @unsortedIncludes));
    
    push(@headerContent, "\n\nnamespace WebCore {\n\n");
    push(@headerContent, "class ScriptExecutionContext;\n\n");
    push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");

    push(@headerContent, <<END);
public:
    static PassRefPtr<${className}> create(v8::Local<v8::Value> value, ScriptExecutionContext* context)
    {
        ASSERT(value->IsObject());
        ASSERT(context);
        return adoptRef(new ${className}(value->ToObject(), context));
    }

    virtual ~${className}();

END

    # Functions
    my $numFunctions = @{$dataNode->functions};
    if ($numFunctions > 0) {
        push(@headerContent, "    // Functions\n");
        foreach my $function (@{$dataNode->functions}) {
            my @params = @{$function->parameters};
            if (!$function->signature->extendedAttributes->{"Custom"} &&
                !(GetNativeType($function->signature->type) eq "bool")) {
                    push(@headerContent, "    COMPILE_ASSERT(false)");
            }

            push(@headerContent, "    virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "(");

            my @args = ();
            foreach my $param (@params) {
                push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
            }
            push(@headerContent, join(", ", @args));
            push(@headerContent, ");\n");
        }
    }

    push(@headerContent, <<END);

private:
    ${className}(v8::Local<v8::Object>, ScriptExecutionContext*);

    v8::Persistent<v8::Object> m_callback;
    WorldContextHandle m_worldContext;
};

END

    push(@headerContent, "}\n\n");
    push(@headerContent, "#endif // $className" . "_h\n\n");

    my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
    push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
}

sub GenerateCallbackImplementation
{
    my $object = shift;
    my $dataNode = shift;
    my $interfaceName = $dataNode->name;
    my $className = "V8$interfaceName";

    # - Add default header template
    push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
         
    AddToImplIncludes("ScriptExecutionContext.h");
    AddToImplIncludes("V8Binding.h");
    AddToImplIncludes("V8CustomVoidCallback.h");
    AddToImplIncludes("V8Proxy.h");

    push(@implContent, "#include <wtf/Assertions.h>\n\n");
    push(@implContent, "namespace WebCore {\n\n");
    push(@implContent, <<END);
${className}::${className}(v8::Local<v8::Object> callback, ScriptExecutionContext* context)
    : ActiveDOMCallback(context)
    , m_callback(v8::Persistent<v8::Object>::New(callback))
    , m_worldContext(UseCurrentWorld)
{
}

${className}::~${className}()
{
    m_callback.Dispose();
}

END

    # Functions
    my $numFunctions = @{$dataNode->functions};
    if ($numFunctions > 0) {
        push(@implContent, "// Functions\n");
        foreach my $function (@{$dataNode->functions}) {
            my @params = @{$function->parameters};
            if ($function->signature->extendedAttributes->{"Custom"} ||
                !(GetNativeTypeForCallbacks($function->signature->type) eq "bool")) {
                next;
            }

            AddIncludesForType($function->signature->type);
            push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "(");

            my @args = ();
            my @argsCheck = ();
            my $thisType = $function->signature->extendedAttributes->{"PassThisToCallback"};
            foreach my $param (@params) {
                my $paramName = $param->name;
                AddIncludesForType($param->type);
                push(@args, GetNativeTypeForCallbacks($param->type) . " " . $paramName);
                if ($thisType and $thisType eq $param->type) {
                    push(@argsCheck, <<END);
    ASSERT(${paramName});

END
                }
            }
            push(@implContent, join(", ", @args));

            push(@implContent, ")\n");
            push(@implContent, "{\n");
            push(@implContent, @argsCheck) if @argsCheck;
            push(@implContent, "    if (!canInvokeCallback())\n");
            push(@implContent, "        return true;\n\n");
            push(@implContent, "    v8::HandleScope handleScope;\n\n");
            push(@implContent, "    v8::Handle<v8::Context> v8Context = toV8Context(scriptExecutionContext(), m_worldContext);\n");
            push(@implContent, "    if (v8Context.IsEmpty())\n");
            push(@implContent, "        return true;\n\n");
            push(@implContent, "    v8::Context::Scope scope(v8Context);\n\n");

            @args = ();
            foreach my $param (@params) {
                my $paramName = $param->name;
                push(@implContent, "    v8::Handle<v8::Value> ${paramName}Handle = " . NativeToJSValue($param, $paramName, "0") . ";\n");
                push(@implContent, "    if (${paramName}Handle.IsEmpty()) {\n");
                push(@implContent, "        if (!isScriptControllerTerminating())\n");
                push(@implContent, "            CRASH();\n");
                push(@implContent, "        return true;\n");
                push(@implContent, "    }\n");
                push(@args, "        ${paramName}Handle");
            }

            if (scalar(@args) > 0) {
                push(@implContent, "\n    v8::Handle<v8::Value> argv[] = {\n");
                push(@implContent, join(",\n", @args));
                push(@implContent, "\n    };\n\n");
            } else {
                push(@implContent, "\n    v8::Handle<v8::Value> *argv = 0;\n\n");
            }
            push(@implContent, "    bool callbackReturnValue = false;\n");
            if ($thisType) {
                foreach my $param (@params) {
                    next if $param->type ne $thisType;
                    my $paramName = $param->name;
                    push(@implContent, "    return !invokeCallback(m_callback, v8::Handle<v8::Object>::Cast(${paramName}Handle), " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n");
                    last;
                }
            } else {
                push(@implContent, "    return !invokeCallback(m_callback, " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n");
            }
            push(@implContent, "}\n");
        }
    }

    push(@implContent, "\n} // namespace WebCore\n\n");

    my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
    push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
}

sub GenerateToV8Converters
{
    my $dataNode = shift;
    my $interfaceName = shift;
    my $className = shift;
    my $nativeType = shift;

    my $domMapName = GetDomMapName($dataNode, $interfaceName);
    my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
    my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
    my $wrapSlowArgumentType = GetPassRefPtrType($nativeType);

    push(@implContent, <<END);

v8::Handle<v8::Object> ${className}::wrapSlow(${wrapSlowArgumentType} impl, v8::Isolate* isolate)
{
    v8::Handle<v8::Object> wrapper;
END

    my $proxyInit;
    if (IsNodeSubType($dataNode)) {
        $proxyInit = "V8Proxy::retrieve(impl->document()->frame())";
        # DocumentType nodes are the only nodes that may have a NULL document.
        if ($interfaceName eq "DocumentType") {
            $proxyInit = "impl->document() ? $proxyInit : 0";
        }
    } else {
        $proxyInit = "0";
    }
    push(@implContent, <<END);
    V8Proxy* proxy = $proxyInit;
END

    if (IsSubType($dataNode, "Document")) {
        push(@implContent, <<END);
    if (proxy && proxy->windowShell()->context().IsEmpty() && proxy->windowShell()->initContextIfNeeded()) {
        // initContextIfNeeded may have created a wrapper for the object, retry from the start.
        return ${className}::wrap(impl.get(), isolate);
    }
END
    }

    # FIXME: We need a better way of recovering the correct prototype chain
    # for every sort of object. For now, we special-case cross-origin visible
    # objects (i.e., those with CheckSecurity).
    if (IsVisibleAcrossOrigins($dataNode)) {
        push(@implContent, <<END);
    if (impl->frame()) {
        proxy = V8Proxy::retrieve(impl->frame());
        if (proxy)
            proxy->windowShell()->initContextIfNeeded();
    }
END
    }

    if (IsNodeSubType($dataNode) || IsVisibleAcrossOrigins($dataNode)) {
        push(@implContent, <<END);

    // Enter the node's context and create the wrapper in that context.
    v8::Handle<v8::Context> context;
    if (proxy && !proxy->matchesCurrentContext()) {
        // For performance, we enter the context only if the currently running context
        // is different from the context that we are about to enter.
        context = proxy->context();
        if (!context.IsEmpty())
            context->Enter();
    }
END
    }

    push(@implContent, <<END);
    wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl.get());
END
    if (IsNodeSubType($dataNode) || IsVisibleAcrossOrigins($dataNode)) {
        push(@implContent, <<END);
    // Exit the node's context if it was entered.
    if (!context.IsEmpty())
        context->Exit();
END
    }

    push(@implContent, <<END);
    if (UNLIKELY(wrapper.IsEmpty()))
        return wrapper;

    v8::Persistent<v8::Object> wrapperHandle = v8::Persistent<v8::Object>::New(wrapper);

    if (!hasDependentLifetime)
        wrapperHandle.MarkIndependent();
END
    if (IsNodeSubType($dataNode)) {
        push(@implContent, <<END);
    wrapperHandle.SetWrapperClassId(v8DOMSubtreeClassId);
END
    }
    push(@implContent, <<END);
    V8DOMWrapper::setJSWrapperFor${domMapName}(impl, wrapperHandle, isolate);
    return wrapper;
}
END
}

sub GetDomMapFunction
{
    return "get" . GetDomMapName(@_) . "Map()";
}

sub GetDomMapName
{
    my $dataNode = shift;
    my $type = shift;

    return "ActiveDOMNode" if (IsNodeSubType($dataNode) && $dataNode->extendedAttributes->{"ActiveDOMObject"});
    return "DOMNode" if IsNodeSubType($dataNode);
    return "ActiveDOMObject" if $dataNode->extendedAttributes->{"ActiveDOMObject"};
    return "DOMObject";
}

sub GetNativeTypeForConversions
{
    my $dataNode = shift;
    my $type = shift;

    $type = $codeGenerator->GetSVGTypeNeedingTearOff($type) if $codeGenerator->IsSVGTypeNeedingTearOff($type); 
    return $type;
}

sub GenerateFunctionCallString()
{
    my $function = shift;
    my $numberOfParameters = shift;
    my $indent = shift;
    my $implClassName = shift;
    my %replacements = @_;

    my $name = $function->signature->name;
    my $returnType = GetTypeFromSignature($function->signature);
    my $nativeReturnType = GetNativeType($returnType, 0);
    my $result = "";

    my $isSVGTearOffType = ($codeGenerator->IsSVGTypeNeedingTearOff($returnType) and not $implClassName =~ /List$/);
    $nativeReturnType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($returnType) if $isSVGTearOffType;

    if ($function->signature->extendedAttributes->{"ImplementedAs"}) {
        $name = $function->signature->extendedAttributes->{"ImplementedAs"};
    }

    my $index = 0;
    my $hasScriptState = 0;

    my @arguments;
    my $functionName;
    my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
    if ($implementedBy) {
        AddToImplIncludes("${implementedBy}.h");
        unshift(@arguments, "imp") if !$function->isStatic;
        $functionName = "${implementedBy}::${name}";
    } elsif ($function->isStatic) {
        $functionName = "${implClassName}::${name}";
    } else {
        $functionName = "imp->${name}";
    }

    my $callWith = $function->signature->extendedAttributes->{"CallWith"};
    my @callWithOutput = ();
    my @callWithArgs = GenerateCallWith($callWith, \@callWithOutput, $indent, 0, 1, $function);
    $result .= join("", @callWithOutput);
    push(@arguments, @callWithArgs);
    $index += @callWithArgs;
    $numberOfParameters += @callWithArgs;

    foreach my $parameter (@{$function->parameters}) {
        if ($index eq $numberOfParameters) {
            last;
        }
        my $paramName = $parameter->name;
        my $paramType = $parameter->type;

        if ($replacements{$paramName}) {
            push @arguments, $replacements{$paramName};
        } elsif ($parameter->type eq "IDBKey" || $parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") {
            push @arguments, "$paramName.get()";
        } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($parameter->type) and not $implClassName =~ /List$/) {
            push @arguments, "$paramName->propertyReference()";
            $result .= $indent . "if (!$paramName) {\n";
            $result .= $indent . "    V8Proxy::setDOMException(WebCore::TYPE_MISMATCH_ERR, args.GetIsolate());\n";
            $result .= $indent . "    return v8::Handle<v8::Value>();\n";
            $result .= $indent . "}\n";
        } elsif ($parameter->type eq "SVGMatrix" and $implClassName eq "SVGTransformList") {
            push @arguments, "$paramName.get()";
        } else {
            push @arguments, $paramName;
        }
        $index++;
    }

    if (@{$function->raisesExceptions}) {
        push @arguments, "ec";
    }

    my $functionString = "$functionName(" . join(", ", @arguments) . ")";

    my $return = "result";
    my $returnIsRef = IsRefPtrType($returnType);

    if ($returnType eq "void") {
        $result .= $indent . "$functionString;\n";
    } elsif ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState") or @{$function->raisesExceptions}) {
        $result .= $indent . $nativeReturnType . " result = $functionString;\n";
    } else {
        # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
        $return = $functionString;
        $returnIsRef = 0;

        if ($implClassName eq "SVGTransformList" and IsRefPtrType($returnType)) {
            $return = "WTF::getPtr(" . $return . ")";
        }
    }

    if (@{$function->raisesExceptions}) {
        $result .= $indent . "if (UNLIKELY(ec))\n";
        $result .= $indent . "    goto fail;\n";
    }

    if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
        $result .= $indent . "if (state.hadException())\n";
        $result .= $indent . "    return throwError(state.exception());\n"
    }

    if ($isSVGTearOffType) {
        AddToImplIncludes("V8$returnType.h");
        AddToImplIncludes("SVGPropertyTearOff.h");
        my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($returnType);
        $result .= $indent . "return toV8(WTF::getPtr(${svgNativeType}::create($return)), args.GetIsolate());\n";
        return $result;
    }

    # If the implementing class is a POD type, commit changes
    if ($codeGenerator->IsSVGTypeNeedingTearOff($implClassName) and not $implClassName =~ /List$/) {
        $result .= $indent . "wrapper->commitChange();\n";
    }

    $return .= ".release()" if ($returnIsRef);
    $result .= $indent . ReturnNativeToJSValue($function->signature, $return, "args.GetIsolate()") . ";\n";

    return $result;
}


sub GetTypeFromSignature
{
    my $signature = shift;

    return $codeGenerator->StripModule($signature->type);
}


sub GetNativeTypeFromSignature
{
    my $signature = shift;
    my $parameterIndex = shift;

    my $type = GetTypeFromSignature($signature);

    if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
        # Special-case index arguments because we need to check that they aren't < 0.
        return "int";
    }

    $type = GetNativeType($type, $parameterIndex >= 0 ? 1 : 0);

    if ($parameterIndex >= 0 && $type eq "V8Parameter") {
        # FIXME: This implements [TreatNullAs=NullString] and [TreatUndefinedAs=NullString],
        # but the Web IDL spec requires [TreatNullAs=EmptyString] and [TreatUndefinedAs=EmptyString].
        my $mode = "";
        if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") and ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString")) {
            $mode = "WithUndefinedOrNullCheck";
        } elsif (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") or $signature->extendedAttributes->{"Reflect"}) {
            $mode = "WithNullCheck";
        }
        # FIXME: Add the case for 'elsif ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString"))'.
        $type .= "<$mode>";
    }

    return $type;
}

sub IsRefPtrType
{
    my $type = shift;

    return 0 if $type eq "boolean";
    return 0 if $type eq "float";
    return 0 if $type eq "int";
    return 0 if $type eq "Date";
    return 0 if $type eq "DOMString";
    return 0 if $type eq "double";
    return 0 if $type eq "short";
    return 0 if $type eq "long";
    return 0 if $type eq "unsigned";
    return 0 if $type eq "unsigned long";
    return 0 if $type eq "unsigned short";
    return 0 if $type eq "float[]";
    return 0 if $type eq "double[]";

    return 1;
}

sub GetNativeType
{
    my $type = shift;
    my $isParameter = shift;

    my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
    if ($svgNativeType) {
        if ($svgNativeType =~ /List$/) {
            return "${svgNativeType}*";
        } else {
            return "RefPtr<${svgNativeType} >";
        }
    }

    if ($type eq "float" or $type eq "double") {
        return $type;
    }

    return "V8Parameter" if ($type eq "DOMString" or $type eq "DOMUserData") and $isParameter;
    return "int" if $type eq "int";
    return "int" if $type eq "short" or $type eq "unsigned short";
    return "unsigned" if $type eq "unsigned long";
    return "int" if $type eq "long";
    return "long long" if $type eq "long long";
    return "unsigned long long" if $type eq "unsigned long long";
    return "bool" if $type eq "boolean";
    return "String" if $type eq "DOMString";
    return "Range::CompareHow" if $type eq "CompareHow";
    return "DOMTimeStamp" if $type eq "DOMTimeStamp";
    return "unsigned" if $type eq "unsigned int";
    return "Node*" if $type eq "EventTarget" and $isParameter;
    return "double" if $type eq "Date";
    return "ScriptValue" if $type eq "DOMObject";
    return "Dictionary" if $type eq "Dictionary";

    return "String" if $type eq "DOMUserData";  # FIXME: Temporary hack?

    # temporary hack
    return "RefPtr<NodeFilter>" if $type eq "NodeFilter";

    return "RefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue";

    return "RefPtr<IDBKey>" if $type eq "IDBKey";

    # necessary as resolvers could be constructed on fly.
    return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver";

    return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter;

    return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener";

    # FIXME: Support T[], T[]?, sequence<T> generically
    return "Vector<float>" if $type eq "float[]";
    return "Vector<double>" if $type eq "double[]";
    return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
    return "RefPtr<DOMStringList>" if $type eq "DOMString[]";

    # Default, assume native type is a pointer with same type name as idl type
    return "${type}*";
}

sub GetNativeTypeForCallbacks
{
    my $type = shift;
    return "const String&" if $type eq "DOMString";
    return "SerializedScriptValue*" if $type eq "SerializedScriptValue";

    # Callbacks use raw pointers, so pass isParameter = 1
    return GetNativeType($type, 1);
}

sub TranslateParameter
{
    my $signature = shift;

    # The IDL uses some pseudo-types which don't really exist.
    if ($signature->type eq "TimeoutHandler") {
      $signature->type("DOMString");
    }
}

sub TypeCanFailConversion
{
    my $signature = shift;

    my $type = GetTypeFromSignature($signature);

    AddToImplIncludes("ExceptionCode.h") if $type eq "Attr";
    return 1 if $type eq "Attr";
    return 1 if $type eq "VoidCallback";
    return 0;
}

sub JSValueToNative
{
    my $signature = shift;
    my $value = shift;
    my $getIsolate = shift;

    my $type = GetTypeFromSignature($signature);

    return "$value" if $type eq "JSObject";
    return "$value->BooleanValue()" if $type eq "boolean";
    return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double";

    return "toInt32($value)" if $type eq "long" or $type eq "short";
    return "toUInt32($value)" if $type eq "unsigned long" or $type eq "unsigned short";
    return "toInt64($value)" if $type eq "unsigned long long" or $type eq "long long";
    return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow";
    return "toWebCoreDate($value)" if $type eq "Date";
    return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMStringList";
    # FIXME: Add proper support for T[], T[]? and sequence<T>.
    return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMString[]";
    if ($type eq "float[]") {
        AddToImplIncludes("wtf/Vector.h");
        return "v8NumberArrayToVector<float>($value)";
    }
    if ($type eq "double[]") {
        AddToImplIncludes("wtf/Vector.h");
        return "v8NumberArrayToVector<double>($value)";
    }

    if ($type eq "DOMString" or $type eq "DOMUserData") {
        return $value;
    }

    if ($type eq "SerializedScriptValue") {
        AddToImplIncludes("SerializedScriptValue.h");
        return "SerializedScriptValue::create($value, $getIsolate)";
    }

    if ($type eq "IDBKey") {
        AddToImplIncludes("IDBBindingUtilities.h");
        AddToImplIncludes("IDBKey.h");
        return "createIDBKeyFromValue($value)";
    }

    if ($type eq "Dictionary") {
        AddToImplIncludes("Dictionary.h");
        return $value;
    }

    if ($type eq "DOMObject") {
        AddToImplIncludes("ScriptValue.h");
        return "ScriptValue($value)";
    }

    if ($type eq "NodeFilter") {
        return "V8DOMWrapper::wrapNativeNodeFilter($value)";
    }

    if ($type eq "MediaQueryListListener") {
        AddToImplIncludes("MediaQueryListListener.h");
        return "MediaQueryListListener::create(" . $value . ")";
    }

    # Default, assume autogenerated type conversion routines
    if ($type eq "EventTarget") {
        AddToImplIncludes("V8Node.h");

        # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget.
        return "V8Node::HasInstance($value) ? V8Node::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
    }

    if ($type eq "XPathNSResolver") {
        return "V8DOMWrapper::getXPathNSResolver($value)";
    }

    my $arrayType = $codeGenerator->GetArrayType($type);
    if ($arrayType) {
        return "toNativeArray<$arrayType>($value)";
    }

    AddIncludesForType($type);

    if (IsDOMNodeType($type)) {
        AddToImplIncludes("V8${type}.h");

        # Perform type checks on the parameter, if it is expected Node type,
        # return NULL.
        return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
    } else {
        AddToImplIncludes("V8$type.h");

        # Perform type checks on the parameter, if it is expected Node type,
        # return NULL.
        return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
    }
}

sub GetV8HeaderName
{
    my $type = shift;
    return "V8Event.h" if $type eq "DOMTimeStamp";
    return "EventListener.h" if $type eq "EventListener";
    return "EventTarget.h" if $type eq "EventTarget";
    return "SerializedScriptValue.h" if $type eq "SerializedScriptValue";
    return "ScriptValue.h" if $type eq "DOMObject";
    return "V8DOMStringList.h" if $type eq "DOMString[]";
    return "V8${type}.h";
}

sub CreateCustomSignature
{
    my $function = shift;
    my $count = @{$function->parameters};
    my $name = $function->signature->name;
    my $result = "    const int ${name}Argc = ${count};\n" .
      "    v8::Handle<v8::FunctionTemplate> ${name}Argv[${name}Argc] = { ";
    my $first = 1;
    foreach my $parameter (@{$function->parameters}) {
        if ($first) { $first = 0; }
        else { $result .= ", "; }
        if (IsWrapperType($parameter->type)) {
            if ($parameter->type eq "XPathNSResolver") {
                # Special case for XPathNSResolver.  All other browsers accepts a callable,
                # so, even though it's against IDL, accept objects here.
                $result .= "v8::Handle<v8::FunctionTemplate>()";
            } else {
                my $type = $parameter->type;
                my $arrayType = $codeGenerator->GetArrayType($type);
                if ($arrayType) {
                    AddToImplIncludes("$arrayType.h");
                } else {
                    my $header = GetV8HeaderName($type);
                    AddToImplIncludes($header);
                }
                $result .= "V8${type}::GetRawTemplate()";
            }
        } else {
            $result .= "v8::Handle<v8::FunctionTemplate>()";
        }
    }
    $result .= " };\n";
    $result .= "    v8::Handle<v8::Signature> ${name}Signature = v8::Signature::New(desc, ${name}Argc, ${name}Argv);\n";
    return $result;
}


sub RequiresCustomSignature
{
    my $function = shift;
    # No signature needed for Custom function
    if ($function->signature->extendedAttributes->{"Custom"} ||
        $function->signature->extendedAttributes->{"V8Custom"}) {
        return 0;
    }
    # No signature needed for overloaded function
    if (@{$function->{overloads}} > 1) {
        return 0;
    }
    if ($function->isStatic) {
        return 0;
    }
    # Type checking is performed in the generated code
    if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
      return 0;
    }
    foreach my $parameter (@{$function->parameters}) {
        my $optional = $parameter->extendedAttributes->{"Optional"};
        if (($optional && $optional ne "DefaultIsUndefined" && $optional ne "DefaultIsNullString") || $parameter->extendedAttributes->{"Callback"}) {
            return 0;
        }
    }

    foreach my $parameter (@{$function->parameters}) {
        if (IsWrapperType($parameter->type)) {
            return 1;
        }
    }
    return 0;
}


# FIXME: Sort this array.
my %non_wrapper_types = (
    'float' => 1,
    'double' => 1,
    'int' => 1,
    'unsigned int' => 1,
    'short' => 1,
    'unsigned short' => 1,
    'long' => 1,
    'unsigned long' => 1,
    'boolean' => 1,
    'long long' => 1,
    'unsigned long long' => 1,
    'float[]' => 1,
    'double[]' => 1,
    'DOMString' => 1,
    'CompareHow' => 1,
    'SerializedScriptValue' => 1,
    'DOMTimeStamp' => 1,
    'JSObject' => 1,
    'DOMObject' => 1,
    'EventTarget' => 1,
    'NodeFilter' => 1,
    'EventListener' => 1,
    'IDBKey' => 1,
    'Dictionary' => 1,
    'Date' => 1,
    'MediaQueryListListener' => 1
);


sub IsWrapperType
{
    my $type = $codeGenerator->StripModule(shift);
    return !($non_wrapper_types{$type});
}

sub IsArrayType
{
    my $type = $codeGenerator->StripModule(shift);
    # FIXME: Add proper support for T[], T[]?, sequence<T>.
    return $type =~ m/\[\]$/;
}

sub IsDOMNodeType
{
    my $type = shift;

    return 1 if $type eq 'Attr';
    return 1 if $type eq 'CDATASection';
    return 1 if $type eq 'Comment';
    return 1 if $type eq 'Document';
    return 1 if $type eq 'DocumentFragment';
    return 1 if $type eq 'DocumentType';
    return 1 if $type eq 'Element';
    return 1 if $type eq 'EntityReference';
    return 1 if $type eq 'HTMLCanvasElement';
    return 1 if $type eq 'HTMLDocument';
    return 1 if $type eq 'HTMLElement';
    return 1 if $type eq 'HTMLUnknownElement';
    return 1 if $type eq 'HTMLFormElement';
    return 1 if $type eq 'HTMLTableCaptionElement';
    return 1 if $type eq 'HTMLTableSectionElement';
    return 1 if $type eq 'Node';
    return 1 if $type eq 'ProcessingInstruction';
    return 1 if $type eq 'SVGElement';
    return 1 if $type eq 'SVGDocument';
    return 1 if $type eq 'SVGSVGElement';
    return 1 if $type eq 'SVGUseElement';
    return 1 if $type eq 'Text';

    return 0;
}


sub NativeToJSValue
{
    my $signature = shift;
    my $value = shift;
    my $getIsolate = shift;
    my $type = GetTypeFromSignature($signature);

    return "v8Boolean($value)" if $type eq "boolean";
    return "v8::Handle<v8::Value>()" if $type eq "void";     # equivalent to v8::Undefined()

    # HTML5 says that unsigned reflected attributes should be in the range
    # [0, 2^31). When a value isn't in this range, a default value (or 0)
    # should be returned instead.
    if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) {
        $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g;
        return "v8::Integer::NewFromUnsigned(std::max(0, " . $value . "))";
    }

    # For all the types where we use 'int' as the representation type,
    # we use Integer::New which has a fast Smi conversion check.
    my $nativeType = GetNativeType($type);
    return "v8::Integer::New($value)" if $nativeType eq "int";
    return "v8::Integer::NewFromUnsigned($value)" if $nativeType eq "unsigned";

    return "v8DateOrNull($value)" if $type eq "Date";
    # long long and unsigned long long are not representable in ECMAScript.
    return "v8::Number::New(static_cast<double>($value))" if $type eq "long long" or $type eq "unsigned long long" or $type eq "DOMTimeStamp";
    return "v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type);
    return "$value.v8Value()" if $nativeType eq "ScriptValue";

    return "v8NumberArray($value)" if $type eq "float[]";
    return "v8NumberArray($value)" if $type eq "double[]";

    if ($codeGenerator->IsStringType($type)) {
        my $conv = $signature->extendedAttributes->{"TreatReturnedNullStringAs"};
        if (defined $conv) {
            return "v8StringOrNull($value, $getIsolate)" if $conv eq "Null";
            return "v8StringOrUndefined($value, $getIsolate)" if $conv eq "Undefined";
            return "v8StringOrFalse($value, $getIsolate)" if $conv eq "False";

            die "Unknown value for TreatReturnedNullStringAs extended attribute";
        }
        return "v8String($value, $getIsolate)";
    }

    my $arrayType = $codeGenerator->GetArrayType($type);
    if ($arrayType) {
        if (!$codeGenerator->SkipIncludeHeader($arrayType)) {
            AddToImplIncludes("V8$arrayType.h");
            AddToImplIncludes("$arrayType.h");
        }
        return "v8Array($value, $getIsolate)";
    }

    AddIncludesForType($type);

    # special case for non-DOM node interfaces
    if (IsDOMNodeType($type)) {
        return "toV8(${value}" . ($signature->extendedAttributes->{"ReturnNewObject"} ? ", $getIsolate, true)" : ")");
    }

    if ($type eq "EventTarget") {
        return "V8DOMWrapper::convertEventTargetToV8Object($value)";
    }

    if ($type eq "EventListener") {
        AddToImplIncludes("V8AbstractEventListener.h");
        return "${value} ? v8::Handle<v8::Value>(static_cast<V8AbstractEventListener*>(${value})->getListenerObject(imp->scriptExecutionContext())) : v8::Handle<v8::Value>(v8::Null())";
    }

    if ($type eq "SerializedScriptValue") {
        AddToImplIncludes("$type.h");
        return "$value ? $value->deserialize() : v8::Handle<v8::Value>(v8::Null())";
    }

    AddToImplIncludes("wtf/RefCounted.h");
    AddToImplIncludes("wtf/RefPtr.h");
    AddToImplIncludes("wtf/GetPtr.h");

    return "toV8($value, $getIsolate)";
}

sub ReturnNativeToJSValue
{
    return "return " . NativeToJSValue(@_);
}

# Internal helper
sub WriteData
{
    my $object = shift;
    my $dataNode = shift;

    my $name = $dataNode->name;
    my $prefix = FileNamePrefix;
    my $headerFileName = "$outputHeadersDir/$prefix$name.h";
    my $implFileName = "$outputDir/$prefix$name.cpp";

    # Update a .cpp file if the contents are changed.
    my $contents = join "", @implContentHeader, @implFixedHeader;

    my @includes = ();
    my %implIncludeConditions = ();
    foreach my $include (keys %implIncludes) {
        my $condition = $implIncludes{$include};
        my $checkType = $include;
        $checkType =~ s/\.h//;
        next if $codeGenerator->IsSVGAnimatedType($checkType);

        if ($include =~ /wtf/) {
            $include = "\<$include\>";
        } else {
            $include = "\"$include\"";
        }

        if ($condition eq 1) {
            push @includes, $include;
        } else {
            push @{$implIncludeConditions{$condition}}, $include;
        }
    }
    foreach my $include (sort @includes) {
        $contents .= "#include $include\n";
    }
    foreach my $condition (sort keys %implIncludeConditions) {
        $contents .= "\n#if " . $codeGenerator->GenerateConditionalStringFromAttributeValue($condition) . "\n";
        foreach my $include (sort @{$implIncludeConditions{$condition}}) {
            $contents .= "#include $include\n";
        }
        $contents .= "#endif\n";
    }

    $contents .= "\n";
    $contents .= join "", @implContentDecls, @implContent;
    $codeGenerator->UpdateFile($implFileName, $contents);

    %implIncludes = ();
    @implFixedHeader = ();
    @implContentDecls = ();
    @implContent = ();

    # Update a .h file if the contents are changed.
    $contents = join "", @headerContent;
    $codeGenerator->UpdateFile($headerFileName, $contents);

    @headerContent = ();
}

sub GetCallbackClassName
{
    my $interfaceName = shift;

    return "V8CustomVoidCallback" if $interfaceName eq "VoidCallback";
    return "V8$interfaceName";
}

sub ConvertToV8Parameter
{
    my $signature = shift;
    my $nativeType = shift;
    my $variableName = shift;
    my $value = shift;
    my $suffix = shift;

    die "Wrong native type passed: $nativeType" unless $nativeType =~ /^V8Parameter/;
    if ($signature->type eq "DOMString") {
        AddToImplIncludes("V8BindingMacros.h");
        my $macro = "STRING_TO_V8PARAMETER_EXCEPTION_BLOCK";
        $macro .= "_$suffix" if $suffix;
        return "$macro($nativeType, $variableName, $value);"
    } else {
        # Don't know how to properly check for conversion exceptions when $parameter->type is "DOMUserData"
        return "$nativeType $variableName($value, true);";
    }
}

# Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
sub GetRuntimeEnableFunctionName
{
    my $signature = shift;

    # If a parameter is given (e.g. "V8EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method.
    return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->extendedAttributes->{"V8EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"V8EnabledAtRuntime"} && $signature->extendedAttributes->{"V8EnabledAtRuntime"} ne "VALUE_IS_MISSING");

    # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled().
    return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->name) . "Enabled";
}

sub GetPassRefPtrType
{
    my $className = shift;

    my $angleBracketSpace = $className =~ />$/ ? " " : "";
    return "PassRefPtr<${className}${angleBracketSpace}>";
}

sub DebugPrint
{
    my $output = shift;

    print $output;
    print "\n";
}

1;