summaryrefslogtreecommitdiff
path: root/Source/WebCore/bindings/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/bindings/scripts')
-rw-r--r--Source/WebCore/bindings/scripts/CodeGenerator.pm926
-rw-r--r--Source/WebCore/bindings/scripts/CodeGeneratorGObject.pm1694
-rw-r--r--Source/WebCore/bindings/scripts/CodeGeneratorJS.pm7226
-rw-r--r--Source/WebCore/bindings/scripts/IDLAttributes.txt85
-rw-r--r--Source/WebCore/bindings/scripts/IDLParser.pm1245
-rw-r--r--Source/WebCore/bindings/scripts/InFilesCompiler.pm25
-rw-r--r--Source/WebCore/bindings/scripts/InFilesParser.pm4
-rw-r--r--Source/WebCore/bindings/scripts/StaticString.pm35
-rwxr-xr-xSource/WebCore/bindings/scripts/generate-bindings-all.pl245
-rwxr-xr-xSource/WebCore/bindings/scripts/generate-bindings.pl69
-rw-r--r--Source/WebCore/bindings/scripts/gobject-generate-headers.pl98
-rw-r--r--Source/WebCore/bindings/scripts/preprocess-idls.pl111
-rw-r--r--Source/WebCore/bindings/scripts/preprocessor.pm29
13 files changed, 6512 insertions, 5280 deletions
diff --git a/Source/WebCore/bindings/scripts/CodeGenerator.pm b/Source/WebCore/bindings/scripts/CodeGenerator.pm
index 943959f54..6f77d7de5 100644
--- a/Source/WebCore/bindings/scripts/CodeGenerator.pm
+++ b/Source/WebCore/bindings/scripts/CodeGenerator.pm
@@ -28,14 +28,16 @@ package CodeGenerator;
use strict;
+use File::Basename;
use File::Find;
+use Carp qw<longmess>;
+use Data::Dumper;
my $useDocument = "";
my $useGenerator = "";
my $useOutputDir = "";
my $useOutputHeadersDir = "";
my $useDirectories = "";
-my $useLayerOnTop = 0;
my $preprocessor;
my $writeDependencies = 0;
my $defines = "";
@@ -45,59 +47,88 @@ my $codeGenerator = 0;
my $verbose = 0;
-my %numericTypeHash = ("int" => 1, "short" => 1, "long" => 1, "long long" => 1,
- "unsigned int" => 1, "unsigned short" => 1,
- "unsigned long" => 1, "unsigned long long" => 1,
- "float" => 1, "double" => 1, "byte" => 1,
- "octet" => 1);
+my %integerTypeHash = (
+ "byte" => 1,
+ "long long" => 1,
+ "long" => 1,
+ "octet" => 1,
+ "short" => 1,
+ "unsigned long long" => 1,
+ "unsigned long" => 1,
+ "unsigned short" => 1,
+);
-my %primitiveTypeHash = ( "boolean" => 1, "void" => 1, "Date" => 1);
+my %floatingPointTypeHash = (
+ "float" => 1,
+ "unrestricted float" => 1,
+ "double" => 1,
+ "unrestricted double" => 1,
+);
-my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1);
+my %stringTypeHash = (
+ "ByteString" => 1,
+ "DOMString" => 1,
+ "USVString" => 1,
+);
-# WebCore types used directly in IDL files.
-my %webCoreTypeHash = (
- "CompareHow" => 1,
- "SerializedScriptValue" => 1,
- "Dictionary" => 1
+my %typedArrayTypes = (
+ "ArrayBuffer" => 1,
+ "ArrayBufferView" => 1,
+ "DataView" => 1,
+ "Float32Array" => 1,
+ "Float64Array" => 1,
+ "Int16Array" => 1,
+ "Int32Array" => 1,
+ "Int8Array" => 1,
+ "Uint16Array" => 1,
+ "Uint32Array" => 1,
+ "Uint8Array" => 1,
+ "Uint8ClampedArray" => 1,
);
-my %enumTypeHash = ();
-
-my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1);
-
-my %svgAttributesInHTMLHash = ("class" => 1, "id" => 1, "onabort" => 1, "onclick" => 1,
- "onerror" => 1, "onload" => 1, "onmousedown" => 1,
- "onmouseenter" => 1, "onmouseleave" => 1,
- "onmousemove" => 1, "onmouseout" => 1, "onmouseover" => 1,
- "onmouseup" => 1, "onresize" => 1, "onscroll" => 1,
- "onunload" => 1);
-
-my %svgTypeNeedingTearOff = (
- "SVGAngle" => "SVGPropertyTearOff<SVGAngle>",
- "SVGLength" => "SVGPropertyTearOff<SVGLength>",
- "SVGLengthList" => "SVGListPropertyTearOff<SVGLengthList>",
- "SVGMatrix" => "SVGPropertyTearOff<SVGMatrix>",
- "SVGNumber" => "SVGPropertyTearOff<float>",
- "SVGNumberList" => "SVGListPropertyTearOff<SVGNumberList>",
- "SVGPathSegList" => "SVGPathSegListPropertyTearOff",
- "SVGPoint" => "SVGPropertyTearOff<SVGPoint>",
- "SVGPointList" => "SVGListPropertyTearOff<SVGPointList>",
- "SVGPreserveAspectRatio" => "SVGPropertyTearOff<SVGPreserveAspectRatio>",
- "SVGRect" => "SVGPropertyTearOff<FloatRect>",
- "SVGStringList" => "SVGStaticListPropertyTearOff<SVGStringList>",
- "SVGTransform" => "SVGPropertyTearOff<SVGTransform>",
- "SVGTransformList" => "SVGTransformListPropertyTearOff"
+my %primitiveTypeHash = (
+ "boolean" => 1,
+ "void" => 1,
+ "Date" => 1
);
-my %svgTypeWithWritablePropertiesNeedingTearOff = (
- "SVGPoint" => 1,
- "SVGMatrix" => 1
+my %dictionaryTypeImplementationNameOverrides = ();
+my %enumTypeImplementationNameOverrides = ();
+
+my %svgAttributesInHTMLHash = (
+ "class" => 1,
+ "id" => 1,
+ "onabort" => 1,
+ "onclick" => 1,
+ "onerror" => 1,
+ "onload" => 1,
+ "onmousedown" => 1,
+ "onmouseenter" => 1,
+ "onmouseleave" => 1,
+ "onmousemove" => 1,
+ "onmouseout" => 1,
+ "onmouseover" => 1,
+ "onmouseup" => 1,
+ "onresize" => 1,
+ "onscroll" => 1,
+ "onunload" => 1,
);
# Cache of IDL file pathnames.
my $idlFiles;
my $cachedInterfaces = {};
+my $cachedExternalDictionaries = {};
+my $cachedExternalEnumerations = {};
+
+sub assert
+{
+ my $message = shift;
+
+ my $mess = longmess();
+ print Dumper($mess);
+
+ die $message;
+}
# Default constructor
sub new
@@ -109,7 +140,6 @@ sub new
$useGenerator = shift;
$useOutputDir = shift;
$useOutputHeadersDir = shift;
- $useLayerOnTop = shift;
$preprocessor = shift;
$writeDependencies = shift;
$verbose = shift;
@@ -128,24 +158,86 @@ sub ProcessDocument
my $ifaceName = "CodeGenerator" . $useGenerator;
require $ifaceName . ".pm";
- %enumTypeHash = map { $_->name => $_->values } @{$useDocument->enumerations};
+ foreach my $dictionary (@{$useDocument->dictionaries}) {
+ if ($dictionary->extendedAttributes->{"ImplementedAs"}) {
+ $dictionaryTypeImplementationNameOverrides{$dictionary->type->name} = $dictionary->extendedAttributes->{"ImplementedAs"};
+ }
+ }
+
+ foreach my $enumeration (@{$useDocument->enumerations}) {
+ if ($enumeration->extendedAttributes->{"ImplementedAs"}) {
+ $enumTypeImplementationNameOverrides{$enumeration->type->name} = $enumeration->extendedAttributes->{"ImplementedAs"};
+ }
+ }
# Dynamically load external code generation perl module
- $codeGenerator = $ifaceName->new($object, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose, $targetIdlFilePath);
+ $codeGenerator = $ifaceName->new($object, $writeDependencies, $verbose, $targetIdlFilePath);
unless (defined($codeGenerator)) {
my $interfaces = $useDocument->interfaces;
foreach my $interface (@$interfaces) {
- print "Skipping $useGenerator code generation for IDL interface \"" . $interface->name . "\".\n" if $verbose;
+ print "Skipping $useGenerator code generation for IDL interface \"" . $interface->type->name . "\".\n" if $verbose;
}
return;
}
my $interfaces = $useDocument->interfaces;
- foreach my $interface (@$interfaces) {
- print "Generating $useGenerator bindings code for IDL interface \"" . $interface->name . "\"...\n" if $verbose;
- $codeGenerator->GenerateInterface($interface, $defines);
+ if (@$interfaces) {
+ die "Multiple interfaces per document are not supported" if @$interfaces > 1;
+
+ my $interface = @$interfaces[0];
+ print "Generating $useGenerator bindings code for IDL interface \"" . $interface->type->name . "\"...\n" if $verbose;
+ $codeGenerator->GenerateInterface($interface, $defines, $useDocument->enumerations, $useDocument->dictionaries);
$codeGenerator->WriteData($interface, $useOutputDir, $useOutputHeadersDir);
+ return;
+ }
+
+ my $callbackFunctions = $useDocument->callbackFunctions;
+ if (@$callbackFunctions) {
+ die "Multiple standalone callback functions per document are not supported" if @$callbackFunctions > 1;
+
+ my $callbackFunction = @$callbackFunctions[0];
+ print "Generating $useGenerator bindings code for IDL callback function \"" . $callbackFunction->type->name . "\"...\n" if $verbose;
+ $codeGenerator->GenerateCallbackFunction($callbackFunction, $useDocument->enumerations, $useDocument->dictionaries);
+ $codeGenerator->WriteData($callbackFunction, $useOutputDir, $useOutputHeadersDir);
+ return;
+ }
+
+ my $dictionaries = $useDocument->dictionaries;
+ if (@$dictionaries) {
+ my $dictionary;
+ my $otherDictionaries;
+ if (@$dictionaries == 1) {
+ $dictionary = @$dictionaries[0];
+ } else {
+ my $primaryDictionaryName = fileparse($targetIdlFilePath, ".idl");
+ for my $candidate (@$dictionaries) {
+ if ($candidate->type->name eq $primaryDictionaryName) {
+ $dictionary = $candidate;
+ } else {
+ push @$otherDictionaries, $candidate;
+ }
+ }
+ die "Multiple dictionaries per document are only supported if one matches the filename" unless $dictionary;
+ }
+
+ print "Generating $useGenerator bindings code for IDL dictionary \"" . $dictionary->type->name . "\"...\n" if $verbose;
+ $codeGenerator->GenerateDictionary($dictionary, $useDocument->enumerations, $otherDictionaries);
+ $codeGenerator->WriteData($dictionary, $useOutputDir, $useOutputHeadersDir);
+ return;
}
+
+ my $enumerations = $useDocument->enumerations;
+ if (@$enumerations) {
+ die "Multiple standalone enumerations per document are not supported" if @$enumerations > 1;
+
+ my $enumeration = @$enumerations[0];
+ print "Generating $useGenerator bindings code for IDL enumeration \"" . $enumeration->type->name . "\"...\n" if $verbose;
+ $codeGenerator->GenerateEnumeration($enumeration);
+ $codeGenerator->WriteData($enumeration, $useOutputDir, $useOutputHeadersDir);
+ return;
+ }
+
+ die "Processing document " . $useDocument->fileName . " did not generate anything"
}
sub FileNamePrefix
@@ -156,7 +248,7 @@ sub FileNamePrefix
require $ifaceName . ".pm";
# Dynamically load external code generation perl module
- $codeGenerator = $ifaceName->new($object, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose);
+ $codeGenerator = $ifaceName->new($object, $writeDependencies, $verbose);
return $codeGenerator->FileNamePrefix();
}
@@ -166,7 +258,9 @@ sub UpdateFile
my $fileName = shift;
my $contents = shift;
- open FH, "> $fileName" or die "Couldn't open $fileName: $!\n";
+ # FIXME: We should only write content if it is different from what is in the file.
+ # But that would mean running more often the binding generator, see https://bugs.webkit.org/show_bug.cgi?id=131756
+ open FH, ">", $fileName or die "Couldn't open $fileName: $!\n";
print FH $contents;
close FH;
}
@@ -183,8 +277,8 @@ sub ForAllParents
my $outerInterface = shift;
my $currentInterface = shift;
- for (@{$currentInterface->parents}) {
- my $interfaceName = $_;
+ if ($currentInterface->parentType) {
+ my $interfaceName = $currentInterface->parentType->name;
my $parentInterface = $object->ParseInterface($outerInterface, $interfaceName);
if ($beforeRecursion) {
@@ -198,22 +292,6 @@ sub ForAllParents
&$recurse($interface, $interface);
}
-sub FindSuperMethod
-{
- my ($object, $interface, $functionName) = @_;
- my $indexer;
- $object->ForAllParents($interface, undef, sub {
- my $currentInterface = shift;
- foreach my $function (@{$currentInterface->functions}) {
- if ($function->signature->name eq $functionName) {
- $indexer = $function->signature;
- return 'prune';
- }
- }
- });
- return $indexer;
-}
-
sub IDLFileForInterface
{
my $object = shift;
@@ -236,6 +314,26 @@ sub IDLFileForInterface
return $idlFiles->{$interfaceName};
}
+sub GetInterfaceForAttribute
+{
+ my ($object, $currentInterface, $attribute) = @_;
+
+ return undef unless $object->IsInterfaceType($attribute->type);
+
+ return $object->ParseInterface($currentInterface, $attribute->type->name);
+}
+
+sub GetAttributeFromInterface
+{
+ my ($object, $outerInterface, $interfaceName, $attributeName) = @_;
+
+ my $interface = $object->ParseInterface($outerInterface, $interfaceName);
+ for my $attribute (@{$interface->attributes}) {
+ return $attribute if $attribute->name eq $attributeName;
+ }
+ die("Could not find attribute '$attributeName' on interface '$interfaceName'.");
+}
+
sub ParseInterface
{
my $object = shift;
@@ -243,6 +341,7 @@ sub ParseInterface
my $interfaceName = shift;
return undef if $interfaceName eq 'Object';
+ return undef if $interfaceName eq 'UNION';
if (exists $cachedInterfaces->{$interfaceName}) {
return $cachedInterfaces->{$interfaceName};
@@ -250,7 +349,7 @@ sub ParseInterface
# Step #1: Find the IDL file associated with 'interface'
my $filename = $object->IDLFileForInterface($interfaceName)
- or die("Could NOT find IDL file for interface \"$interfaceName\", reachable from \"" . $outerInterface->name . "\"!\n");
+ or assert("Could NOT find IDL file for interface \"$interfaceName\", reachable from \"" . $outerInterface->type->name . "\"!\n");
print " | |> Parsing parent IDL \"$filename\" for interface \"$interfaceName\"\n" if $verbose;
@@ -259,7 +358,7 @@ sub ParseInterface
my $document = $parser->Parse($filename, $defines, $preprocessor);
foreach my $interface (@{$document->interfaces}) {
- if ($interface->name eq $interfaceName) {
+ if ($interface->type->name eq $interfaceName) {
$cachedInterfaces->{$interfaceName} = $interface;
return $interface;
}
@@ -270,197 +369,330 @@ sub ParseInterface
# Helpers for all CodeGenerator***.pm modules
-sub SkipIncludeHeader
+sub IsNumericType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
- return 1 if $object->IsPrimitiveType($type);
+ assert("Not a type") if ref($type) ne "IDLType";
- # Special case: SVGNumber.h does not exist.
- return 1 if $type eq "SVGNumber";
-
- # Typed arrays already included by JSDOMBinding.h.
- return 1 if $object->IsTypedArrayType($type);
+ return 1 if $integerTypeHash{$type->name};
+ return 1 if $floatingPointTypeHash{$type->name};
+ return 0;
+}
+
+sub IsStringOrEnumType
+{
+ my ($object, $type) = @_;
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if $object->IsStringType($type);
+ return 1 if $object->IsEnumType($type);
return 0;
}
-sub IsConstructorTemplate
+sub IsIntegerType
{
- my $object = shift;
- my $interface = shift;
- my $template = shift;
+ my ($object, $type) = @_;
- return $interface->extendedAttributes->{"ConstructorTemplate"} && $interface->extendedAttributes->{"ConstructorTemplate"} eq $template;
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if $integerTypeHash{$type->name};
+ return 0;
}
-sub IsNumericType
+sub IsFloatingPointType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
- return 1 if $numericTypeHash{$type};
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if $floatingPointTypeHash{$type->name};
return 0;
}
sub IsPrimitiveType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
- return 1 if $primitiveTypeHash{$type};
- return 1 if $numericTypeHash{$type};
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if $primitiveTypeHash{$type->name};
+ return 1 if $object->IsNumericType($type);
return 0;
}
sub IsStringType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
- return 1 if $stringTypeHash{$type};
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if $stringTypeHash{$type->name};
return 0;
}
sub IsEnumType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
- return 1 if exists $enumTypeHash{$type};
- return 0;
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return defined($object->GetEnumByType($type));
}
-sub ValidEnumValues
+sub GetEnumByType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ my $name = $type->name;
+
+ die "GetEnumByType() was called with an undefined enumeration name" unless defined($name);
+
+ for my $enumeration (@{$useDocument->enumerations}) {
+ return $enumeration if $enumeration->type->name eq $name;
+ }
+
+ return $cachedExternalEnumerations->{$name} if exists($cachedExternalEnumerations->{$name});
- return @{$enumTypeHash{$type}};
+ # Find the IDL file associated with the dictionary.
+ my $filename = $object->IDLFileForInterface($name) or return;
+
+ # Do a fast check to see if it seems to contain a dictionary.
+ my $fileContents = slurp($filename);
+
+ if ($fileContents =~ /\benum\s+$name/gs) {
+ # Parse the IDL.
+ my $parser = IDLParser->new(1);
+ my $document = $parser->Parse($filename, $defines, $preprocessor);
+
+ foreach my $enumeration (@{$document->enumerations}) {
+ next unless $enumeration->type->name eq $name;
+
+ $cachedExternalEnumerations->{$name} = $enumeration;
+ my $implementedAs = $enumeration->extendedAttributes->{ImplementedAs};
+ $enumTypeImplementationNameOverrides{$enumeration->type->name} = $implementedAs if $implementedAs;
+ return $enumeration;
+ }
+ }
+ $cachedExternalEnumerations->{$name} = undef;
}
-sub IsNonPointerType
+# An enumeration defined in its own IDL file.
+sub IsExternalEnumType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
- return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type} or $numericTypeHash{$type};
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $object->IsEnumType($type) && defined($cachedExternalEnumerations->{$type->name});
+}
+
+sub HasEnumImplementationNameOverride
+{
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if exists $enumTypeImplementationNameOverrides{$type->name};
return 0;
}
-sub IsSVGTypeNeedingTearOff
+sub GetEnumImplementationNameOverride
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $enumTypeImplementationNameOverrides{$type->name};
+}
+
+sub GetDictionaryByType
+{
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ my $name = $type->name;
+
+ die "GetDictionaryByType() was called with an undefined dictionary name" unless defined($name);
+
+ for my $dictionary (@{$useDocument->dictionaries}) {
+ return $dictionary if $dictionary->type->name eq $name;
+ }
- return 1 if exists $svgTypeNeedingTearOff{$type};
+ return $cachedExternalDictionaries->{$name} if exists($cachedExternalDictionaries->{$name});
+
+ # Find the IDL file associated with the dictionary.
+ my $filename = $object->IDLFileForInterface($name) or return;
+
+ # Do a fast check to see if it seems to contain a dictionary.
+ my $fileContents = slurp($filename);
+
+ if ($fileContents =~ /\bdictionary\s+$name/gs) {
+ # Parse the IDL.
+ my $parser = IDLParser->new(1);
+ my $document = $parser->Parse($filename, $defines, $preprocessor);
+
+ foreach my $dictionary (@{$document->dictionaries}) {
+ next unless $dictionary->type->name eq $name;
+
+ $cachedExternalDictionaries->{$name} = $dictionary;
+ my $implementedAs = $dictionary->extendedAttributes->{ImplementedAs};
+ $dictionaryTypeImplementationNameOverrides{$dictionary->type->name} = $implementedAs if $implementedAs;
+ return $dictionary;
+ }
+ }
+ $cachedExternalDictionaries->{$name} = undef;
+}
+
+sub IsDictionaryType
+{
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $type->name =~ /^[A-Z]/ && defined($object->GetDictionaryByType($type));
+}
+
+# A dictionary defined in its own IDL file.
+sub IsExternalDictionaryType
+{
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $object->IsDictionaryType($type) && defined($cachedExternalDictionaries->{$type->name});
+}
+
+sub HasDictionaryImplementationNameOverride
+{
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if exists $dictionaryTypeImplementationNameOverrides{$type->name};
return 0;
}
-sub IsSVGTypeWithWritablePropertiesNeedingTearOff
+sub GetDictionaryImplementationNameOverride
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $dictionaryTypeImplementationNameOverrides{$type->name};
+}
- return 1 if $svgTypeWithWritablePropertiesNeedingTearOff{$type};
+sub IsNonPointerType
+{
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if $object->IsPrimitiveType($type);
return 0;
}
sub IsTypedArrayType
{
- my $object = shift;
- 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") or ($type eq "DataView"));
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if $typedArrayTypes{$type->name};
return 0;
}
sub IsRefPtrType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
return 0 if $object->IsPrimitiveType($type);
- return 0 if $object->GetArrayType($type);
- return 0 if $object->GetSequenceType($type);
- return 0 if $type eq "DOMString";
+ return 0 if $object->IsDictionaryType($type);
return 0 if $object->IsEnumType($type);
+ return 0 if $object->IsSequenceOrFrozenArrayType($type);
+ return 0 if $object->IsRecordType($type);
+ return 0 if $object->IsStringType($type);
+ return 0 if $type->isUnion;
+ return 0 if $type->name eq "any";
+ return 0 if $type->name eq "object";
return 1;
}
-sub GetSVGTypeNeedingTearOff
+sub IsSVGAnimatedTypeName
{
- my $object = shift;
- my $type = shift;
+ my ($object, $typeName) = @_;
- return $svgTypeNeedingTearOff{$type} if exists $svgTypeNeedingTearOff{$type};
- return undef;
+ return $typeName =~ /^SVGAnimated/;
}
-sub GetSVGWrappedTypeNeedingTearOff
+sub IsSVGAnimatedType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
- my $svgTypeNeedingTearOff = $object->GetSVGTypeNeedingTearOff($type);
- return $svgTypeNeedingTearOff if not $svgTypeNeedingTearOff;
+ return $object->IsSVGAnimatedTypeName($type->name);
+}
- if ($svgTypeNeedingTearOff =~ /SVGPropertyTearOff/) {
- $svgTypeNeedingTearOff =~ s/SVGPropertyTearOff<//;
- } elsif ($svgTypeNeedingTearOff =~ /SVGListPropertyTearOff/) {
- $svgTypeNeedingTearOff =~ s/SVGListPropertyTearOff<//;
- } elsif ($svgTypeNeedingTearOff =~ /SVGStaticListPropertyTearOff/) {
- $svgTypeNeedingTearOff =~ s/SVGStaticListPropertyTearOff<//;
- } elsif ($svgTypeNeedingTearOff =~ /SVGTransformListPropertyTearOff/) {
- $svgTypeNeedingTearOff =~ s/SVGTransformListPropertyTearOff<//;
- }
+sub IsConstructorType
+{
+ my ($object, $type) = @_;
- $svgTypeNeedingTearOff =~ s/>//;
- return $svgTypeNeedingTearOff;
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $type->name =~ /Constructor$/;
}
-sub IsSVGAnimatedType
+sub IsSequenceType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
- return $type =~ /^SVGAnimated/;
+ return $type->name eq "sequence";
}
-sub GetSequenceType
+sub IsFrozenArrayType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
- return $1 if $type =~ /^sequence<([\w\d_\s]+)>.*/;
- return "";
+ return $type->name eq "FrozenArray";
}
-sub GetArrayType
+sub IsSequenceOrFrozenArrayType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
- return $1 if $type =~ /^([\w\d_\s]+)\[\]/;
- return "";
+ return $object->IsSequenceType($type) || $object->IsFrozenArrayType($type);
}
-sub AssertNotSequenceType
+sub IsRecordType
{
- my $object = shift;
- my $type = shift;
- die "Sequences must not be used as the type of an attribute, constant or exception field." if $object->GetSequenceType($type);
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $type->name eq "record";
}
+# These match WK_lcfirst and WK_ucfirst defined in builtins_generator.py.
# Uppercase the first letter while respecting WebKit style guidelines.
# E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang.
sub WK_ucfirst
{
my ($object, $param) = @_;
+
my $ret = ucfirst($param);
$ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/;
$ret =~ s/Svg/SVG/ if $ret =~ /^Svg/;
@@ -473,13 +705,16 @@ sub WK_ucfirst
sub WK_lcfirst
{
my ($object, $param) = @_;
+
my $ret = lcfirst($param);
+ $ret =~ s/dOM/dom/ if $ret =~ /^dOM/;
$ret =~ s/hTML/html/ if $ret =~ /^hTML/;
$ret =~ s/uRL/url/ if $ret =~ /^uRL/;
$ret =~ s/jS/js/ if $ret =~ /^jS/;
$ret =~ s/xML/xml/ if $ret =~ /^xML/;
$ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
$ret =~ s/cSS/css/ if $ret =~ /^cSS/;
+ $ret =~ s/rTC/rtc/ if $ret =~ /^rTC/;
# For HTML5 FileSystem API Flags attributes.
# (create is widely used to instantiate an object and must be avoided.)
@@ -489,10 +724,30 @@ sub WK_lcfirst
return $ret;
}
+sub slurp
+{
+ my $file = shift;
+
+ open my $fh, '<', $file or die;
+ local $/ = undef;
+ my $content = <$fh>;
+ close $fh;
+ return $content;
+}
+
+sub trim
+{
+ my $string = shift;
+
+ $string =~ s/^\s+|\s+$//g;
+ return $string;
+}
+
# Return the C++ namespace that a given attribute name string is defined in.
sub NamespaceForAttributeName
{
my ($object, $interfaceName, $attributeName) = @_;
+
return "SVGNames" if $interfaceName =~ /^SVG/ && !$svgAttributesInHTMLHash{$attributeName};
return "HTMLNames";
}
@@ -505,23 +760,30 @@ sub LinkOverloadedFunctions
my %nameToFunctionsMap = ();
foreach my $function (@{$interface->functions}) {
- my $name = $function->signature->name;
+ my $name = $function->name;
$nameToFunctionsMap{$name} = [] if !exists $nameToFunctionsMap{$name};
push(@{$nameToFunctionsMap{$name}}, $function);
$function->{overloads} = $nameToFunctionsMap{$name};
$function->{overloadIndex} = @{$nameToFunctionsMap{$name}};
}
+
+ my $index = 1;
+ foreach my $constructor (@{$interface->constructors}) {
+ $constructor->{overloads} = $interface->constructors;
+ $constructor->{overloadIndex} = $index;
+ $index++;
+ }
}
sub AttributeNameForGetterAndSetter
{
my ($generator, $attribute) = @_;
- my $attributeName = $attribute->signature->name;
- if ($attribute->signature->extendedAttributes->{"ImplementedAs"}) {
- $attributeName = $attribute->signature->extendedAttributes->{"ImplementedAs"};
+ my $attributeName = $attribute->name;
+ if ($attribute->extendedAttributes->{"ImplementedAs"}) {
+ $attributeName = $attribute->extendedAttributes->{"ImplementedAs"};
}
- my $attributeType = $attribute->signature->type;
+ my $attributeType = $attribute->type;
# SVG animated types need to use a special attribute name.
# The rest of the special casing for SVG animated types is handled in the language-specific code generators.
@@ -534,7 +796,7 @@ sub ContentAttributeName
{
my ($generator, $implIncludes, $interfaceName, $attribute) = @_;
- my $contentAttributeName = $attribute->signature->extendedAttributes->{"Reflect"};
+ my $contentAttributeName = $attribute->extendedAttributes->{"Reflect"};
return undef if !$contentAttributeName;
$contentAttributeName = lc $generator->AttributeNameForGetterAndSetter($attribute) if $contentAttributeName eq "VALUE_IS_MISSING";
@@ -555,16 +817,16 @@ sub GetterExpression
return ($generator->WK_lcfirst($generator->AttributeNameForGetterAndSetter($attribute)));
}
- my $attributeType = $attribute->signature->type;
+ my $attributeType = $attribute->type;
my $functionName;
- if ($attribute->signature->extendedAttributes->{"URL"}) {
+ if ($attribute->extendedAttributes->{"URL"}) {
$functionName = "getURLAttribute";
- } elsif ($attributeType eq "boolean") {
- $functionName = "fastHasAttribute";
- } elsif ($attributeType eq "long") {
+ } elsif ($attributeType->name eq "boolean") {
+ $functionName = "hasAttributeWithoutSynchronization";
+ } elsif ($attributeType->name eq "long") {
$functionName = "getIntegralAttribute";
- } elsif ($attributeType eq "unsigned long") {
+ } elsif ($attributeType->name eq "unsigned long") {
$functionName = "getUnsignedIntegralAttribute";
} else {
if ($contentAttributeName eq "WebCore::HTMLNames::idAttr") {
@@ -576,7 +838,7 @@ sub GetterExpression
} elsif ($generator->IsSVGAnimatedType($attributeType)) {
$functionName = "getAttribute";
} else {
- $functionName = "fastGetAttribute";
+ $functionName = "attributeWithoutSynchronization";
}
}
@@ -593,74 +855,209 @@ sub SetterExpression
return ("set" . $generator->WK_ucfirst($generator->AttributeNameForGetterAndSetter($attribute)));
}
+ my $attributeType = $attribute->type;
+
my $functionName;
- if ($attribute->signature->type eq "boolean") {
+ if ($attributeType->name eq "boolean") {
$functionName = "setBooleanAttribute";
- } elsif ($attribute->signature->type eq "long") {
+ } elsif ($attributeType->name eq "long") {
$functionName = "setIntegralAttribute";
- } elsif ($attribute->signature->type eq "unsigned long") {
+ } elsif ($attributeType->name eq "unsigned long") {
$functionName = "setUnsignedIntegralAttribute";
- } else {
+ } elsif ($generator->IsSVGAnimatedType($attributeType)) {
$functionName = "setAttribute";
+ } else {
+ $functionName = "setAttributeWithoutSynchronization";
}
return ($functionName, $contentAttributeName);
}
-sub IsWrapperType
+sub IsBuiltinType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
- return 0 if $object->IsPrimitiveType($type);
- return 0 if $object->GetArrayType($type);
- return 0 if $object->GetSequenceType($type);
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 1 if $object->IsPrimitiveType($type);
+ return 1 if $object->IsSequenceOrFrozenArrayType($type);
+ return 1 if $object->IsRecordType($type);
+ return 1 if $object->IsStringType($type);
+ return 1 if $object->IsTypedArrayType($type);
+ return 1 if $type->isUnion;
+ return 1 if $type->name eq "BufferSource";
+ return 1 if $type->name eq "EventListener";
+ return 1 if $type->name eq "JSON";
+ return 1 if $type->name eq "Promise";
+ return 1 if $type->name eq "SerializedScriptValue";
+ return 1 if $type->name eq "XPathNSResolver";
+ return 1 if $type->name eq "any";
+ return 1 if $type->name eq "object";
+
+ return 0;
+}
+
+sub IsInterfaceType
+{
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 0 if $object->IsBuiltinType($type);
+ return 0 if $object->IsDictionaryType($type);
return 0 if $object->IsEnumType($type);
- return 0 if $object->IsStringType($type);
- return 0 if $object->IsTypedArrayType($type);
- return 0 if $webCoreTypeHash{$type};
- return 0 if $type eq "any";
return 1;
}
-sub IsCallbackInterface
+sub IsWrapperType
{
- my $object = shift;
- my $type = shift;
+ my ($object, $type) = @_;
- return 0 unless $object->IsWrapperType($type);
+ assert("Not a type") if ref($type) ne "IDLType";
- my $idlFile = $object->IDLFileForInterface($type)
- or die("Could NOT find IDL file for interface \"$type\"!\n");
+ return 1 if $object->IsInterfaceType($type);
+ return 1 if $type->name eq "XPathNSResolver";
- open FILE, "<", $idlFile;
- my @lines = <FILE>;
- close FILE;
+ return 0;
+}
+
+sub IsSerializableAttribute
+{
+ my ($object, $currentInterface, $attribute) = @_;
+
+ # https://heycam.github.io/webidl/#dfn-serializable-type
+
+ my $type = $attribute->type;
+ return 1 if $type->name eq "boolean";
+ return 1 if $object->IsNumericType($type);
+ return 1 if $object->IsEnumType($type);
+ return 1 if $object->IsStringType($type);
+ return 0 if $type->name eq "EventHandler";
+
+ if ($type->isUnion || $object->IsSequenceType($type) || $object->IsDictionaryType($type)) {
+ die "Serializer for non-primitive types is not currently supported\n";
+ }
- my $fileContents = join('', @lines);
- return ($fileContents =~ /callback\s+interface\s+(\w+)/gs);
+ my $interface = GetInterfaceForAttribute($object, $currentInterface, $attribute);
+ if ($interface && $interface->serializable) {
+ die "Serializer for non-primitive types is not currently supported\n";
+ }
+
+ return 0;
}
-sub GenerateConditionalString
+sub GetInterfaceExtendedAttributesFromName
{
- my $generator = shift;
- my $node = shift;
+ # FIXME: It's bad to have a function like this that opens another IDL file to answer a question.
+ # Overusing this kind of function can make things really slow. Lets avoid these if we can.
- my $conditional = $node->extendedAttributes->{"Conditional"};
- if ($conditional) {
- return $generator->GenerateConditionalStringFromAttributeValue($conditional);
- } else {
- return "";
+ my ($object, $interfaceName) = @_;
+
+ my $idlFile = $object->IDLFileForInterface($interfaceName) or assert("Could NOT find IDL file for interface \"$interfaceName\"!\n");
+
+ open FILE, "<", $idlFile or die;
+ my @lines = <FILE>;
+ close FILE;
+
+ my $fileContents = join('', @lines);
+
+ my $extendedAttributes = {};
+
+ if ($fileContents =~ /\[(.*)\]\s+(callback interface|interface|exception)\s+(\w+)/gs) {
+ my @parts = split(',', $1);
+ foreach my $part (@parts) {
+ my @keyValue = split('=', $part);
+ my $key = trim($keyValue[0]);
+ next unless length($key);
+ my $value = "VALUE_IS_MISSING";
+ $value = trim($keyValue[1]) if @keyValue > 1;
+ $extendedAttributes->{$key} = $value;
+ }
}
+
+ return $extendedAttributes;
+}
+
+sub ComputeIsCallbackInterface
+{
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 0 unless $object->IsInterfaceType($type);
+
+ my $typeName = $type->name;
+ my $idlFile = $object->IDLFileForInterface($typeName) or assert("Could NOT find IDL file for interface \"$typeName\"!\n");
+
+ open FILE, "<", $idlFile or die;
+ my @lines = <FILE>;
+ close FILE;
+
+ my $fileContents = join('', @lines);
+ return ($fileContents =~ /callback\s+interface\s+(\w+)/gs);
+}
+
+my %isCallbackInterface = ();
+
+sub IsCallbackInterface
+{
+ # FIXME: It's bad to have a function like this that opens another IDL file to answer a question.
+ # Overusing this kind of function can make things really slow. Lets avoid these if we can.
+ # To mitigate that, lets cache what we learn in a hash so we don't open the same file over and over.
+
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $isCallbackInterface{$type->name} if exists $isCallbackInterface{$type->name};
+ my $result = $object->ComputeIsCallbackInterface($type);
+ $isCallbackInterface{$type->name} = $result;
+ return $result;
}
-sub GenerateConstructorConditionalString
+sub ComputeIsCallbackFunction
{
- my $generator = shift;
- my $node = shift;
+ my ($object, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return 0 unless $object->IsInterfaceType($type);
+
+ my $typeName = $type->name;
+ my $idlFile = $object->IDLFileForInterface($typeName) or assert("Could NOT find IDL file for interface \"$typeName\"!\n");
+
+ open FILE, "<", $idlFile or die;
+ my @lines = <FILE>;
+ close FILE;
+
+ my $fileContents = join('', @lines);
+ return ($fileContents =~ /(.*)callback\s+(\w+)\s+=/gs);
+}
+
+my %isCallbackFunction = ();
+
+sub IsCallbackFunction
+{
+ # FIXME: It's bad to have a function like this that opens another IDL file to answer a question.
+ # Overusing this kind of function can make things really slow. Lets avoid these if we can.
+ # To mitigate that, lets cache what we learn in a hash so we don't open the same file over and over.
+
+ my ($object, $type) = @_;
- my $conditional = $node->extendedAttributes->{"ConstructorConditional"};
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ return $isCallbackFunction{$type->name} if exists $isCallbackFunction{$type->name};
+ my $result = $object->ComputeIsCallbackFunction($type);
+ $isCallbackFunction{$type->name} = $result;
+ return $result;
+}
+
+sub GenerateConditionalString
+{
+ my ($generator, $node) = @_;
+
+ my $conditional = $node->extendedAttributes->{"Conditional"};
if ($conditional) {
return $generator->GenerateConditionalStringFromAttributeValue($conditional);
} else {
@@ -670,51 +1067,49 @@ sub GenerateConstructorConditionalString
sub GenerateConditionalStringFromAttributeValue
{
- my $generator = shift;
- my $conditional = shift;
-
- my $operator = ($conditional =~ /&/ ? '&' : ($conditional =~ /\|/ ? '|' : ''));
- if ($operator) {
- # Avoid duplicated conditions.
- my %conditions;
- map { $conditions{$_} = 1 } split('\\' . $operator, $conditional);
- return "ENABLE(" . join(") $operator$operator ENABLE(", sort keys %conditions) . ")";
- } else {
- return "ENABLE(" . $conditional . ")";
- }
+ my ($generator, $conditional) = @_;
+
+ my %disjunction;
+ map {
+ my $expression = $_;
+ my %conjunction;
+ map { $conjunction{$_} = 1; } split(/&/, $expression);
+ $expression = "ENABLE(" . join(") && ENABLE(", sort keys %conjunction) . ")";
+ $disjunction{$expression} = 1
+ } split(/\|/, $conditional);
+
+ return "1" if keys %disjunction == 0;
+ return (%disjunction)[0] if keys %disjunction == 1;
+
+ my @parenthesized;
+ map {
+ my $expression = $_;
+ $expression = "($expression)" if $expression =~ / /;
+ push @parenthesized, $expression;
+ } sort keys %disjunction;
+
+ return join(" || ", @parenthesized);
}
sub GenerateCompileTimeCheckForEnumsIfNeeded
{
my ($generator, $interface) = @_;
- my $interfaceName = $interface->name;
- my @checks = ();
- # If necessary, check that all constants are available as enums with the same value.
- if (!$interface->extendedAttributes->{"DoNotCheckConstants"} && @{$interface->constants}) {
- push(@checks, "\n");
- foreach my $constant (@{$interface->constants}) {
- my $reflect = $constant->extendedAttributes->{"Reflect"};
- my $name = $reflect ? $reflect : $constant->name;
- my $value = $constant->value;
- my $conditional = $constant->extendedAttributes->{"Conditional"};
-
- if ($conditional) {
- my $conditionalString = $generator->GenerateConditionalStringFromAttributeValue($conditional);
- push(@checks, "#if ${conditionalString}\n");
- }
- if ($constant->extendedAttributes->{"ImplementedBy"}) {
- push(@checks, "COMPILE_ASSERT($value == " . $constant->extendedAttributes->{"ImplementedBy"} . "::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n");
- } else {
- push(@checks, "COMPILE_ASSERT($value == ${interfaceName}::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n");
- }
+ return () if $interface->extendedAttributes->{"DoNotCheckConstants"} || !@{$interface->constants};
- if ($conditional) {
- push(@checks, "#endif\n");
- }
- }
- push(@checks, "\n");
+ my $baseScope = $interface->extendedAttributes->{"ConstantsScope"} || $interface->type->name;
+
+ my @checks = ();
+ foreach my $constant (@{$interface->constants}) {
+ my $scope = $constant->extendedAttributes->{"ImplementedBy"} || $baseScope;
+ my $name = $constant->extendedAttributes->{"Reflect"} || $constant->name;
+ my $value = $constant->value;
+ my $conditional = $constant->extendedAttributes->{"Conditional"};
+ push(@checks, "#if " . $generator->GenerateConditionalStringFromAttributeValue($conditional) . "\n") if $conditional;
+ push(@checks, "static_assert(${scope}::${name} == ${value}, \"${name} in ${scope} does not match value from IDL\");\n");
+ push(@checks, "#endif\n") if $conditional;
}
+ push(@checks, "\n");
return @checks;
}
@@ -733,23 +1128,22 @@ sub ExtendedAttributeContains
# should use the real interface name in the IDL files and then use ImplementedAs to map this to the implementation name.
sub GetVisibleInterfaceName
{
- my $object = shift;
- my $interface = shift;
+ my ($object, $interface) = @_;
+
my $interfaceName = $interface->extendedAttributes->{"InterfaceName"};
- return $interfaceName ? $interfaceName : $interface->name;
+ return $interfaceName ? $interfaceName : $interface->type->name;
}
sub InheritsInterface
{
- my $object = shift;
- my $interface = shift;
- my $interfaceName = shift;
- my $found = 0;
+ my ($object, $interface, $interfaceName) = @_;
- return 1 if $interfaceName eq $interface->name;
+ return 1 if $interfaceName eq $interface->type->name;
+
+ my $found = 0;
$object->ForAllParents($interface, sub {
my $currentInterface = shift;
- if ($currentInterface->name eq $interfaceName) {
+ if ($currentInterface->type->name eq $interfaceName) {
$found = 1;
}
return 1 if $found;
@@ -760,12 +1154,11 @@ sub InheritsInterface
sub InheritsExtendedAttribute
{
- my $object = shift;
- my $interface = shift;
- my $extendedAttribute = shift;
- my $found = 0;
+ my ($object, $interface, $extendedAttribute) = @_;
return 1 if $interface->extendedAttributes->{$extendedAttribute};
+
+ my $found = 0;
$object->ForAllParents($interface, sub {
my $currentInterface = shift;
if ($currentInterface->extendedAttributes->{$extendedAttribute}) {
@@ -777,4 +1170,5 @@ sub InheritsExtendedAttribute
return $found;
}
+
1;
diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorGObject.pm b/Source/WebCore/bindings/scripts/CodeGeneratorGObject.pm
deleted file mode 100644
index b5b1d8e43..000000000
--- a/Source/WebCore/bindings/scripts/CodeGeneratorGObject.pm
+++ /dev/null
@@ -1,1694 +0,0 @@
-# Copyright (C) 2008 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
-# Copyright (C) 2008 Martin Soto <soto@freedesktop.org>
-# Copyright (C) 2008 Alp Toker <alp@atoker.com>
-# Copyright (C) 2009 Adam Dingle <adam@yorba.org>
-# Copyright (C) 2009 Jim Nelson <jim@yorba.org>
-# Copyright (C) 2009, 2010 Igalia S.L.
-#
-# 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 CodeGeneratorGObject;
-
-use constant FileNamePrefix => "WebKitDOM";
-
-# Global Variables
-my %implIncludes = ();
-my %hdrIncludes = ();
-
-my $defineTypeMacro = "G_DEFINE_TYPE";
-my $defineTypeInterfaceImplementation = ")";
-my @txtEventListeners = ();
-my @txtInstallProps = ();
-my @txtSetProps = ();
-my @txtGetProps = ();
-
-my $className = "";
-
-# FIXME: this should be replaced with a function that recurses up the tree
-# to find the actual base type.
-my %baseTypeHash = ("Object" => 1, "Node" => 1, "NodeList" => 1, "NamedNodeMap" => 1, "DOMImplementation" => 1,
- "Event" => 1, "CSSRule" => 1, "CSSValue" => 1, "StyleSheet" => 1, "MediaList" => 1,
- "Counter" => 1, "Rect" => 1, "RGBColor" => 1, "XPathExpression" => 1, "XPathResult" => 1,
- "NodeIterator" => 1, "TreeWalker" => 1, "AbstractView" => 1, "Blob" => 1, "DOMTokenList" => 1,
- "HTMLCollection" => 1);
-
-# Only objects derived from Node are released by the DOM object cache and can be
-# transfer none. Ideally we could use GetBaseClass with the parent type to check
-# whether it's Node, but unfortunately we only have the name of the return type,
-# and we can't know its parent base class. Since there are fewer classes in the
-# API that are not derived from Node, we will list them here to decide the
-# transfer type.
-my %transferFullTypeHash = ("AudioTrack" => 1, "AudioTrackList" => 1, "BarProp" => 1, "BatteryManager" => 1,
- "CSSRuleList" => 1, "CSSStyleDeclaration" => 1, "CSSStyleSheet" => 1,
- "DOMApplicationCache" => 1, "DOMMimeType" => 1, "DOMMimeTypeArray" => 1, "DOMNamedFlowCollection" => 1,
- "DOMPlugin" => 1, "DOMPluginArray" => 1, "DOMSecurityPolicy" => 1,
- "DOMSelection" => 1, "DOMSettableTokenList" => 1, "DOMStringList" => 1,
- "DOMWindow" => 1, "DOMWindowCSS" => 1, "EventTarget" => 1,
- "File" => 1, "FileList" => 1, "Gamepad" => 1, "GamepadList" => 1,
- "Geolocation" => 1, "HTMLOptionsCollection" => 1, "History" => 1,
- "KeyboardEvent" => 1, "MediaError" => 1, "MediaController" => 1,
- "MouseEvent" => 1, "MediaQueryList" => 1, "Navigator" => 1, "NodeFilter" => 1,
- "Performance" => 1, "PerformanceEntry" => 1, "PerformanceEntryList" => 1, "PerformanceNavigation" => 1, "PerformanceTiming" => 1,
- "Range" => 1, "Screen" => 1, "SpeechSynthesis" => 1, "SpeechSynthesisVoice" => 1,
- "Storage" => 1, "StyleMedia" => 1, "TextTrack" => 1, "TextTrackCueList" => 1,
- "TimeRanges" => 1, "Touch" => 1, "UIEvent" => 1, "UserMessageHandler" => 1, "UserMessageHandlersNamespace" => 1,
- "ValidityState" => 1, "VideoTrack" => 1, "WebKitNamedFlow" => 1,
- "WebKitNamespace" => 1, "WebKitPoint" => 1, "WheelEvent" => 1, "XPathNSResolver" => 1);
-
-# List of function parameters that are allowed to be NULL
-my $canBeNullParams = {
- 'webkit_dom_document_create_attribute_ns' => ['namespaceURI'],
- 'webkit_dom_document_create_element_ns' => ['namespaceURI'],
- 'webkit_dom_document_create_entity_reference' => ['name'],
- 'webkit_dom_document_evaluate' => ['inResult', 'resolver'],
- 'webkit_dom_document_get_override_style' => ['pseudoElement'],
- 'webkit_dom_dom_implementation_create_document' => ['namespaceURI', 'doctype'],
- 'webkit_dom_dom_window_get_computed_style' => ['pseudoElement'],
- 'webkit_dom_element_set_attribute_ns' => ['namespaceURI'],
- 'webkit_dom_node_insert_before' => ['refChild'],
-};
-
-# Default constructor
-sub new {
- my $object = shift;
- my $reference = { };
-
- $codeGenerator = shift;
-
- bless($reference, $object);
-}
-
-my $licenceTemplate = << "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., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-EOF
-
-sub GetParentClassName {
- my $interface = shift;
-
- return "WebKitDOMObject" unless $interface->parent;
- return "WebKitDOM" . $interface->parent;
-}
-
-sub GetParentImplClassName {
- my $interface = shift;
-
- return "Object" unless $interface->parent;
- return $interface->parent;
-}
-
-sub IsBaseType
-{
- my $type = shift;
-
- return 1 if $baseTypeHash{$type};
- return 0;
-}
-
-sub GetBaseClass
-{
- $parent = shift;
- $interface = shift;
-
- return $parent if $parent eq "Object" or IsBaseType($parent);
- return "Event" if $codeGenerator->InheritsInterface($interface, "Event");
- return "CSSValue" if $parent eq "SVGColor" or $parent eq "CSSValueList";
- return "Node";
-}
-
-
-# From String::CamelCase 0.01
-sub camelize
-{
- my $s = shift;
- join('', map{ ucfirst $_ } split(/(?<=[A-Za-z])_(?=[A-Za-z])|\b/, $s));
-}
-
-sub decamelize
-{
- my $s = shift;
- $s =~ s{([^a-zA-Z]?)([A-Z]*)([A-Z])([a-z]?)}{
- my $fc = pos($s)==0;
- my ($p0,$p1,$p2,$p3) = ($1,lc$2,lc$3,$4);
- my $t = $p0 || $fc ? $p0 : '_';
- $t .= $p3 ? $p1 ? "${p1}_$p2$p3" : "$p2$p3" : "$p1$p2";
- $t;
- }ge;
-
- # Some strings are not correctly decamelized, apply fix ups
- for ($s) {
- s/domcss/dom_css/;
- s/domhtml/dom_html/;
- s/domdom/dom_dom/;
- s/domcdata/dom_cdata/;
- s/domui/dom_ui/;
- s/x_path/xpath/;
- s/web_kit/webkit/;
- s/htmli_frame/html_iframe/;
- }
- return $s;
-}
-
-sub HumanReadableConditional {
- my @conditional = split('_', shift);
- my @upperCaseExceptions = ("SQL", "API");
- my @humanReadable;
-
- for $part (@conditional) {
- if (!grep {$_ eq $part} @upperCaseExceptions) {
- $part = camelize(lc($part));
- }
- push(@humanReadable, $part);
- }
-
- return join(' ', @humanReadable);
-}
-
-sub GetParentGObjType {
- my $interface = shift;
-
- return "WEBKIT_TYPE_DOM_OBJECT" unless $interface->parent;
- return "WEBKIT_TYPE_DOM_" . uc(decamelize(($interface->parent)));
-}
-
-sub GetClassName {
- my $name = shift;
-
- return "WebKitDOM$name";
-}
-
-sub GetCoreObject {
- my ($interfaceName, $name, $parameter) = @_;
-
- return "WebCore::${interfaceName}* $name = WebKit::core($parameter);";
-}
-
-sub SkipAttribute {
- my $attribute = shift;
-
- if ($attribute->signature->extendedAttributes->{"Custom"}
- || $attribute->signature->extendedAttributes->{"CustomGetter"}) {
- return 1;
- }
-
- my $propType = $attribute->signature->type;
- if ($propType =~ /Constructor$/) {
- return 1;
- }
-
- return 1 if $attribute->isStatic;
- return 1 if $codeGenerator->IsTypedArrayType($propType);
-
- $codeGenerator->AssertNotSequenceType($propType);
-
- if ($codeGenerator->GetArrayType($propType)) {
- return 1;
- }
-
- if ($codeGenerator->IsEnumType($propType)) {
- return 1;
- }
-
- # This is for DOMWindow.idl location attribute
- if ($attribute->signature->name eq "location") {
- return 1;
- }
-
- # This is for HTMLInput.idl valueAsDate
- if ($attribute->signature->name eq "valueAsDate") {
- return 1;
- }
-
- # This is for DOMWindow.idl Crypto attribute
- if ($attribute->signature->type eq "Crypto") {
- return 1;
- }
-
- if ($attribute->signature->type eq "EventListener") {
- return 1;
- }
-
- if ($attribute->signature->type eq "MediaQueryListListener") {
- return 1;
- }
-
- # Skip indexed database attributes for now, they aren't yet supported for the GObject generator.
- if ($attribute->signature->name =~ /^(?:webkit)?[Ii]ndexedDB/ or $attribute->signature->name =~ /^(?:webkit)?IDB/) {
- return 1;
- }
-
- return 0;
-}
-
-sub SkipFunction {
- my $object = shift;
- my $function = shift;
- my $parentNode = shift;
- my $decamelize = shift;
- my $prefix = shift;
-
- my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($function->signature->name);
- my $functionReturnType = $prefix eq "set_" ? "void" : $function->signature->type;
- my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"};
- my $callWith = $function->signature->extendedAttributes->{"CallWith"};
- my $isUnsupportedCallWith = $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments") || $codeGenerator->ExtendedAttributeContains($callWith, "CallStack");
-
- if (($isCustomFunction || $isUnsupportedCallWith) &&
- $functionName ne "webkit_dom_node_replace_child" &&
- $functionName ne "webkit_dom_node_insert_before" &&
- $functionName ne "webkit_dom_node_remove_child" &&
- $functionName ne "webkit_dom_node_append_child" &&
- $functionName ne "webkit_dom_html_collection_item" &&
- $functionName ne "webkit_dom_html_collection_named_item") {
- return 1;
- }
-
- # Skip functions that have callback parameters, because this code generator doesn't know
- # how to auto-generate callbacks. Skip functions that have "MediaQueryListListener" or
- # sequence<T> parameters, because this code generator doesn't know how to auto-generate
- # MediaQueryListListener or sequence<T>. Skip EventListeners because they are handled elsewhere.
- foreach my $param (@{$function->parameters}) {
- if ($codeGenerator->IsCallbackInterface($param->type) ||
- $param->extendedAttributes->{"Clamp"} ||
- $param->type eq "MediaQueryListListener" ||
- $param->type eq "EventListener" ||
- $codeGenerator->GetSequenceType($param->type)) {
- return 1;
- }
- }
-
- # Skip functions for which we have a custom implementation due to API breaks
- if ($functionName eq "webkit_dom_html_media_element_set_current_time") {
- return 1;
- }
-
- # This is for DataTransferItemList.idl add(File) method
- if ($functionName eq "webkit_dom_data_transfer_item_list_add" && @{$function->parameters} == 1) {
- return 1;
- }
-
- # Skip dispatch_event methods, except the one already deprecated.
- if ($parentNode->extendedAttributes->{"EventTarget"} && $function->signature->name eq "dispatchEvent"
- && $functionName ne "webkit_dom_audio_track_list_dispatch_event"
- && $functionName ne "webkit_dom_battery_manager_dispatch_event"
- && $functionName ne "webkit_dom_dom_application_cache_dispatch_event"
- && $functionName ne "webkit_dom_dom_window_dispatch_event"
- && $functionName ne "webkit_dom_node_dispatch_event"
- && $functionName ne "webkit_dom_text_track_cue_dispatch_event"
- && $functionName ne "webkit_dom_text_track_dispatch_event"
- && $functionName ne "webkit_dom_text_track_list_dispatch_event"
- && $functionName ne "webkit_dom_video_track_list_dispatch_event"
- && $functionName ne "webkit_dom_webkit_named_flow_dispatch_event"
- && $functionName ne "webkit_dom_test_event_target_dispatch_event") {
- return 1;
- }
-
- # Skip Console::profile() and Console::profileEnd() as they're not correctly generated for the moment.
- if ($functionName eq "webkit_dom_console_profile" || $functionName eq "webkit_dom_console_profile_end") {
- return 1;
- }
-
- if ($function->signature->name eq "set" and $parentNode->extendedAttributes->{"TypedArray"}) {
- return 1;
- }
-
- if ($object eq "MediaQueryListListener") {
- return 1;
- }
-
- if ($function->signature->name eq "getSVGDocument") {
- return 1;
- }
-
- if ($function->signature->name eq "getCSSCanvasContext") {
- return 1;
- }
-
- if ($function->signature->name eq "setRangeText" && @{$function->parameters} == 1) {
- return 1;
- }
-
- if ($function->signature->name eq "timeEnd") {
- return 1;
- }
-
- if ($codeGenerator->GetSequenceType($functionReturnType)) {
- return 1;
- }
-
- if ($function->signature->name eq "supports" && @{$function->parameters} == 1) {
- return 1;
- }
-
- return 0;
-}
-
-# Name type used in the g_value_{set,get}_* functions
-sub GetGValueTypeName {
- my $type = shift;
-
- my %types = ("DOMString", "string",
- "DOMTimeStamp", "uint",
- "float", "float",
- "double", "double",
- "boolean", "boolean",
- "char", "char",
- "long", "long",
- "long long", "int64",
- "byte", "int8",
- "octet", "uint8",
- "short", "int",
- "uchar", "uchar",
- "unsigned", "uint",
- "int", "int",
- "unsigned int", "uint",
- "unsigned long long", "uint64",
- "unsigned long", "ulong",
- "unsigned short", "uint");
-
- return $types{$type} ? $types{$type} : "object";
-}
-
-# Name type used in C declarations
-sub GetGlibTypeName {
- my $type = shift;
- my $name = GetClassName($type);
-
- my %types = ("DOMString", "gchar*",
- "DOMTimeStamp", "guint32",
- "CompareHow", "gushort",
- "float", "gfloat",
- "double", "gdouble",
- "boolean", "gboolean",
- "char", "gchar",
- "long", "glong",
- "long long", "gint64",
- "byte", "gint8",
- "octet", "guint8",
- "short", "gshort",
- "uchar", "guchar",
- "unsigned", "guint",
- "int", "gint",
- "unsigned int", "guint",
- "unsigned long", "gulong",
- "unsigned long long", "guint64",
- "unsigned short", "gushort",
- "void", "void");
-
- return $types{$type} ? $types{$type} : "$name*";
-}
-
-sub IsGDOMClassType {
- my $type = shift;
-
- return 0 if $codeGenerator->IsNonPointerType($type) || $codeGenerator->IsStringType($type);
- return 1;
-}
-
-sub IsPropertyReadable {
- my $property = shift;
- return !SkipAttribute($property);
-}
-
-sub IsPropertyWriteable {
- my $property = shift;
-
- if (!IsPropertyReadable($property)) {
- return 0;
- }
-
- if ($property->isReadOnly) {
- return 0;
- }
-
- my $gtype = GetGValueTypeName($property->signature->type);
- my $hasGtypeSignature = $gtype eq "boolean" || $gtype eq "float" || $gtype eq "double" ||
- $gtype eq "int64" || $gtype eq "uint64" ||
- $gtype eq "long" || $gtype eq "ulong" ||
- $gtype eq "int" || $gtype eq "uint" ||
- $gtype eq "short" || $gtype eq "ushort" ||
- $gtype eq "int8" || $gtype eq "uint8" ||
- $gtype eq "char" || $gtype eq "uchar" ||
- $gtype eq "string";
- if (!$hasGtypeSignature) {
- return 0;
- }
-
- # FIXME: We are not generating setters for 'Replaceable' attributes now, but we should somehow.
- if ($property->signature->extendedAttributes->{"Replaceable"}) {
- return 0;
- }
-
- if ($property->signature->extendedAttributes->{"CustomSetter"}) {
- return 0;
- }
-
- return 1;
-}
-
-sub GenerateConditionalWarning
-{
- my $node = shift;
- my $indentSize = shift;
- if (!$indentSize) {
- $indentSize = 4;
- }
-
- my $conditional = $node->extendedAttributes->{"Conditional"};
- my @warn;
-
- if ($conditional) {
- if ($conditional =~ /&/) {
- my @splitConditionals = split(/&/, $conditional);
- foreach $condition (@splitConditionals) {
- push(@warn, "#if !ENABLE($condition)\n");
- push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($condition) . "\")\n");
- push(@warn, "#endif\n");
- }
- } elsif ($conditional =~ /\|/) {
- foreach $condition (split(/\|/, $conditional)) {
- push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($condition) . "\")\n");
- }
- } else {
- push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($conditional) . "\")\n");
- }
- }
-
- return @warn;
-}
-
-sub GenerateProperty {
- my $attribute = shift;
- my $interfaceName = shift;
- my @writeableProperties = @{shift @_};
- my $parentNode = shift;
-
- my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
- my @conditionalWarn = GenerateConditionalWarning($attribute->signature, 8);
- my $parentConditionalString = $codeGenerator->GenerateConditionalString($parentNode);
- my @parentConditionalWarn = GenerateConditionalWarning($parentNode, 8);
- my $camelPropName = $attribute->signature->name;
- my $setPropNameFunction = $codeGenerator->WK_ucfirst($camelPropName);
- my $getPropNameFunction = $codeGenerator->WK_lcfirst($camelPropName);
- my $hasGetterException = $attribute->signature->extendedAttributes->{"GetterRaisesException"};
- my $hasSetterException = $attribute->signature->extendedAttributes->{"SetterRaisesException"};
-
- my $propName = decamelize($camelPropName);
- my $propNameCaps = uc($propName);
- $propName =~ s/_/-/g;
- my ${propEnum} = "PROP_${propNameCaps}";
- push(@cBodyProperties, " ${propEnum},\n");
-
- my $propType = $attribute->signature->type;
- my ${propGType} = decamelize($propType);
- my ${ucPropGType} = uc($propGType);
-
- my $gtype = GetGValueTypeName($propType);
- my $gparamflag = "WEBKIT_PARAM_READABLE";
- my $writeable = IsPropertyWriteable($attribute);
-
- my $mutableString = "read-only";
- my $hasCustomSetter = $attribute->signature->extendedAttributes->{"CustomSetter"};
- if ($writeable && $hasCustomSetter) {
- $mutableString = "read-only (due to custom functions needed in webkitdom)";
- } elsif ($writeable) {
- $gparamflag = "WEBKIT_PARAM_READWRITE";
- $mutableString = "read-write";
- }
-
- my $convertFunction = "";
- if ($gtype eq "string") {
- $convertFunction = "WTF::String::fromUTF8";
- }
-
- my ($getterFunctionName, @getterArguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
- my ($setterFunctionName, @setterArguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
-
- if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
- my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
- $implIncludes{"${implementedBy}.h"} = 1;
- push(@setterArguments, "${convertFunction}(g_value_get_$gtype(value))");
- unshift(@getterArguments, "coreSelf");
- unshift(@setterArguments, "coreSelf");
- $getterFunctionName = "WebCore::${implementedBy}::$getterFunctionName";
- $setterFunctionName = "WebCore::${implementedBy}::$setterFunctionName";
- } else {
- push(@setterArguments, "${convertFunction}(g_value_get_$gtype(value))");
- $getterFunctionName = "coreSelf->$getterFunctionName";
- $setterFunctionName = "coreSelf->$setterFunctionName";
- }
- push(@getterArguments, "isNull") if $attribute->signature->isNullable;
- push(@getterArguments, "ec") if $hasGetterException;
- push(@setterArguments, "ec") if $hasSetterException;
-
- if (grep {$_ eq $attribute} @writeableProperties) {
- push(@txtSetProps, " case ${propEnum}: {\n");
- push(@txtSetProps, "#if ${parentConditionalString}\n") if $parentConditionalString;
- push(@txtSetProps, "#if ${conditionalString}\n") if $conditionalString;
- push(@txtSetProps, " WebCore::ExceptionCode ec = 0;\n") if $hasSetterException;
- push(@txtSetProps, " ${setterFunctionName}(" . join(", ", @setterArguments) . ");\n");
- push(@txtSetProps, "#else\n") if $conditionalString;
- push(@txtSetProps, @conditionalWarn) if scalar(@conditionalWarn);
- push(@txtSetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
- push(@txtSetProps, "#else\n") if $parentConditionalString;
- push(@txtSetProps, @parentConditionalWarn) if scalar(@parentConditionalWarn);
- push(@txtSetProps, "#endif /* ${parentConditionalString} */\n") if $parentConditionalString;
- push(@txtSetProps, " break;\n }\n");
- }
-
- push(@txtGetProps, " case ${propEnum}: {\n");
- push(@txtGetProps, "#if ${parentConditionalString}\n") if $parentConditionalString;
- push(@txtGetProps, "#if ${conditionalString}\n") if $conditionalString;
- push(@txtGetProps, " bool isNull = false;\n") if $attribute->signature->isNullable;
- push(@txtGetProps, " WebCore::ExceptionCode ec = 0;\n") if $hasGetterException;
-
- # FIXME: Should we return a default value when isNull == true?
-
- my $postConvertFunction = "";
- if ($gtype eq "string") {
- push(@txtGetProps, " g_value_take_string(value, convertToUTF8String(${getterFunctionName}(" . join(", ", @getterArguments) . ")));\n");
- } elsif ($gtype eq "object") {
- push(@txtGetProps, " RefPtr<WebCore::${propType}> ptr = ${getterFunctionName}(" . join(", ", @getterArguments) . ");\n");
- push(@txtGetProps, " g_value_set_object(value, WebKit::kit(ptr.get()));\n");
- } else {
- push(@txtGetProps, " g_value_set_$gtype(value, ${convertFunction}${getterFunctionName}(" . join(", ", @getterArguments) . ")${postConvertFunction});\n");
- }
-
- push(@txtGetProps, "#else\n") if $conditionalString;
- push(@txtGetProps, @conditionalWarn) if scalar(@conditionalWarn);
- push(@txtGetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
- push(@txtGetProps, "#else\n") if $parentConditionalString;
- push(@txtGetProps, @parentConditionalWarn) if scalar(@parentConditionalWarn);
- push(@txtGetProps, "#endif /* ${parentConditionalString} */\n") if $parentConditionalString;
- push(@txtGetProps, " break;\n }\n");
-
- my %parameterSpecOptions = ("int" => [ "G_MININT", "G_MAXINT", "0" ],
- "int8" => [ "G_MININT8", "G_MAXINT8", "0" ],
- "boolean" => [ "FALSE" ],
- "float" => [ "-G_MAXFLOAT", "G_MAXFLOAT", "0" ],
- "double" => [ "-G_MAXDOUBLE", "G_MAXDOUBLE", "0" ],
- "uint64" => [ "0", "G_MAXUINT64", "0" ],
- "long" => [ "G_MINLONG", "G_MAXLONG", "0" ],
- "int64" => [ "G_MININT64", "G_MAXINT64", "0" ],
- "ulong" => [ "0", "G_MAXULONG", "0" ],
- "uint" => [ "0", "G_MAXUINT", "0" ],
- "uint8" => [ "0", "G_MAXUINT8", "0" ],
- "ushort" => [ "0", "G_MAXUINT16", "0" ],
- "uchar" => [ "G_MININT8", "G_MAXINT8", "0" ],
- "char" => [ "0", "G_MAXUINT8", "0" ],
- "string" => [ '""', ],
- "object" => [ "WEBKIT_TYPE_DOM_${ucPropGType}" ]);
-
- my $extraParameters = join(", ", @{$parameterSpecOptions{$gtype}});
- my $glibTypeName = GetGlibTypeName($propType);
- my $txtInstallProp = << "EOF";
- g_object_class_install_property(
- gobjectClass,
- $propEnum,
- g_param_spec_$gtype(
- "$propName",
- "$interfaceName:$propName",
- "$mutableString $glibTypeName $interfaceName:$propName",
- $extraParameters,
- $gparamflag));
-
-EOF
- push(@txtInstallProps, $txtInstallProp);
-}
-
-sub GenerateProperties {
- my ($object, $interfaceName, $interface) = @_;
-
- my $decamelize = decamelize($interfaceName);
- my $clsCaps = uc($decamelize);
- my $lowerCaseIfaceName = "webkit_dom_$decamelize";
- my $parentImplClassName = GetParentImplClassName($interface);
-
- my $conditionGuardStart = "";
- my $conditionGuardEnd = "";
- my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
- if ($conditionalString) {
- $conditionGuardStart = "#if ${conditionalString}";
- $conditionGuardEnd = "#endif // ${conditionalString}";
- }
-
- # Properties
- my $implContent = "";
- my @readableProperties = grep { IsPropertyReadable($_) } @{$interface->attributes};
- my @writeableProperties = grep { IsPropertyWriteable($_) } @{$interface->attributes};
- my $numProperties = scalar @readableProperties;
-
- # Properties
- my $privFunction = GetCoreObject($interfaceName, "coreSelf", "self");
- if ($numProperties > 0) {
- $implContent = << "EOF";
-enum {
- PROP_0,
-EOF
- push(@cBodyProperties, $implContent);
-
- my $txtGetProp = << "EOF";
-static void ${lowerCaseIfaceName}_get_property(GObject* object, guint propertyId, GValue* value, GParamSpec* pspec)
-{
- WebCore::JSMainThreadNullState state;
-EOF
- push(@txtGetProps, $txtGetProp);
- $txtGetProp = << "EOF";
-$conditionGuardStart
- ${className}* self = WEBKIT_DOM_${clsCaps}(object);
- $privFunction
-$conditionGuardEnd
-EOF
- push(@txtGetProps, $txtGetProp);
-
- $txtGetProp = << "EOF";
- switch (propertyId) {
-EOF
- push(@txtGetProps, $txtGetProp);
-
- if (scalar @writeableProperties > 0) {
- my $txtSetProps = << "EOF";
-static void ${lowerCaseIfaceName}_set_property(GObject* object, guint propertyId, const GValue* value, GParamSpec* pspec)
-{
- WebCore::JSMainThreadNullState state;
-EOF
- push(@txtSetProps, $txtSetProps);
-
- $txtSetProps = << "EOF";
-$conditionGuardStart
- ${className}* self = WEBKIT_DOM_${clsCaps}(object);
- $privFunction
-$conditionGuardEnd
-EOF
- push(@txtSetProps, $txtSetProps);
-
- $txtSetProps = << "EOF";
- switch (propertyId) {
-EOF
- push(@txtSetProps, $txtSetProps);
- }
-
- foreach my $attribute (@readableProperties) {
- GenerateProperty($attribute, $interfaceName, \@writeableProperties, $interface);
- }
-
- push(@cBodyProperties, "};\n\n");
-
- $txtGetProp = << "EOF";
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
- break;
- }
-}
-EOF
- push(@txtGetProps, $txtGetProp);
-
- if (scalar @writeableProperties > 0) {
- $txtSetProps = << "EOF";
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
- break;
- }
-}
-EOF
- push(@txtSetProps, $txtSetProps);
- }
- }
-
- # Do not insert extra spaces when interpolating array variables
- $" = "";
-
- if ($parentImplClassName eq "Object") {
- $implContent = << "EOF";
-static void ${lowerCaseIfaceName}_finalize(GObject* object)
-{
- ${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(object);
-$conditionGuardStart
- WebKit::DOMObjectCache::forget(priv->coreObject.get());
-$conditionGuardEnd
- priv->~${className}Private();
- G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->finalize(object);
-}
-
-EOF
- push(@cBodyProperties, $implContent);
- }
-
- if ($numProperties > 0) {
- if (scalar @writeableProperties > 0) {
- push(@cBodyProperties, @txtSetProps);
- push(@cBodyProperties, "\n");
- }
- push(@cBodyProperties, @txtGetProps);
- push(@cBodyProperties, "\n");
- }
-
- # Add a constructor implementation only for direct subclasses of Object to make sure
- # that the WebCore wrapped object is added only once to the DOM cache. The DOM garbage
- # collector works because Node is a direct subclass of Object and the version of
- # DOMObjectCache::put() that receives a Node (which is the one setting the frame) is
- # always called for DOM objects derived from Node.
- if ($parentImplClassName eq "Object") {
- $implContent = << "EOF";
-static GObject* ${lowerCaseIfaceName}_constructor(GType type, guint constructPropertiesCount, GObjectConstructParam* constructProperties)
-{
- GObject* object = G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructor(type, constructPropertiesCount, constructProperties);
-$conditionGuardStart
- ${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(object);
- priv->coreObject = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(object)->coreObject);
- WebKit::DOMObjectCache::put(priv->coreObject.get(), object);
-$conditionGuardEnd
- return object;
-}
-
-EOF
- push(@cBodyProperties, $implContent);
- }
-
- $implContent = << "EOF";
-static void ${lowerCaseIfaceName}_class_init(${className}Class* requestClass)
-{
-EOF
- push(@cBodyProperties, $implContent);
-
- if ($parentImplClassName eq "Object" || $numProperties > 0) {
- push(@cBodyProperties, " GObjectClass* gobjectClass = G_OBJECT_CLASS(requestClass);\n");
-
- if ($parentImplClassName eq "Object") {
- push(@cBodyProperties, " g_type_class_add_private(gobjectClass, sizeof(${className}Private));\n");
- push(@cBodyProperties, " gobjectClass->constructor = ${lowerCaseIfaceName}_constructor;\n");
- push(@cBodyProperties, " gobjectClass->finalize = ${lowerCaseIfaceName}_finalize;\n");
- }
-
- if ($numProperties > 0) {
- if (scalar @writeableProperties > 0) {
- push(@cBodyProperties, " gobjectClass->set_property = ${lowerCaseIfaceName}_set_property;\n");
- }
- push(@cBodyProperties, " gobjectClass->get_property = ${lowerCaseIfaceName}_get_property;\n");
- push(@cBodyProperties, "\n");
- push(@cBodyProperties, @txtInstallProps);
- }
- }
- $implContent = << "EOF";
-}
-
-static void ${lowerCaseIfaceName}_init(${className}* request)
-{
-EOF
- push(@cBodyProperties, $implContent);
-
- if ($parentImplClassName eq "Object") {
- $implContent = << "EOF";
- ${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(request);
- new (priv) ${className}Private();
-EOF
- push(@cBodyProperties, $implContent);
- }
- $implContent = << "EOF";
-}
-
-EOF
- push(@cBodyProperties, $implContent);
-}
-
-sub GenerateHeader {
- my ($object, $interfaceName, $parentClassName) = @_;
-
- my $implContent = "";
-
- # Add the default header template
- @hPrefix = split("\r", $licenceTemplate);
- push(@hPrefix, "\n");
-
- # Force single header include.
- my $headerCheck = << "EOF";
-#if !defined(__WEBKITDOM_H_INSIDE__) && !defined(BUILDING_WEBKIT)
-#error "Only <webkitdom/webkitdom.h> can be included directly."
-#endif
-
-EOF
- push(@hPrefix, $headerCheck);
-
- # Header guard
- my $guard = $className . "_h";
-
- @hPrefixGuard = << "EOF";
-#ifndef $guard
-#define $guard
-
-EOF
-
- $implContent = << "EOF";
-G_BEGIN_DECLS
-
-EOF
-
- push(@hBodyPre, $implContent);
-
- my $decamelize = decamelize($interfaceName);
- my $clsCaps = uc($decamelize);
- my $lowerCaseIfaceName = "webkit_dom_$decamelize";
-
- $implContent = << "EOF";
-#define WEBKIT_TYPE_DOM_${clsCaps} (${lowerCaseIfaceName}_get_type())
-#define WEBKIT_DOM_${clsCaps}(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className}))
-#define WEBKIT_DOM_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class)
-#define WEBKIT_DOM_IS_${clsCaps}(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_DOM_${clsCaps}))
-#define WEBKIT_DOM_IS_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_DOM_${clsCaps}))
-#define WEBKIT_DOM_${clsCaps}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class))
-
-struct _${className} {
- ${parentClassName} parent_instance;
-};
-
-struct _${className}Class {
- ${parentClassName}Class parent_class;
-};
-
-WEBKIT_API GType
-${lowerCaseIfaceName}_get_type (void);
-
-EOF
-
- push(@hBody, $implContent);
-}
-
-sub GetGReturnMacro {
- my ($paramName, $paramIDLType, $returnType, $functionName) = @_;
-
- my $condition;
- if ($paramIDLType eq "GError") {
- $condition = "!$paramName || !*$paramName";
- } elsif (IsGDOMClassType($paramIDLType)) {
- my $paramTypeCaps = uc(decamelize($paramIDLType));
- $condition = "WEBKIT_DOM_IS_${paramTypeCaps}($paramName)";
- if (ParamCanBeNull($functionName, $paramName)) {
- $condition = "!$paramName || $condition";
- }
- } else {
- if (ParamCanBeNull($functionName, $paramName)) {
- return "";
- }
- $condition = "$paramName";
- }
-
- my $macro;
- if ($returnType ne "void") {
- $defaultReturn = $returnType eq "gboolean" ? "FALSE" : 0;
- $macro = " g_return_val_if_fail($condition, $defaultReturn);\n";
- } else {
- $macro = " g_return_if_fail($condition);\n";
- }
-
- return $macro;
-}
-
-sub ParamCanBeNull {
- my($functionName, $paramName) = @_;
-
- if (defined($functionName)) {
- return scalar(grep {$_ eq $paramName} @{$canBeNullParams->{$functionName}});
- }
- return 0;
-}
-
-sub GetFunctionDeprecationInformation {
- my($function, $parentNode) = @_;
-
- my $version;
- my $replacement;
-
- if ($parentNode->extendedAttributes->{"EventTarget"} && $function->signature->name eq "dispatchEvent") {
- # dispatchEvent is implemented already as part fo the WebKitDOMEventTarget interface.
- # Mark it as deprecated for now in favor of the interface method, and skip it once
- # we break the API. All other methods of WebKitDOMEventTarget interface are already
- # skipped because they receive an EventListener as parameter.
- $version = "2.4";
- $replacement = "webkit_dom_event_target_dispatch_event";
- }
-
- return ($version, $replacement);
-}
-
-sub GetTransferTypeForReturnType {
- my $returnType = shift;
-
- # Node is always transfer none.
- return "none" if $returnType eq "Node";
-
- # Any base class but Node is transfer full.
- return "full" if IsBaseType($returnType);
-
- # Any other class not derived from Node is transfer full.
- return "full" if $transferFullTypeHash{$returnType};
- return "none";
-}
-
-sub GenerateFunction {
- my ($object, $interfaceName, $function, $prefix, $parentNode) = @_;
-
- my $decamelize = decamelize($interfaceName);
-
- if (SkipFunction($object, $function, $parentNode, $decamelize, $prefix)) {
- return;
- }
-
- my ($deprecationVersion, $deprecationReplacement) = GetFunctionDeprecationInformation($function, $parentNode);
- my $functionSigType = $prefix eq "set_" ? "void" : $function->signature->type;
- my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($function->signature->name);
- my $returnType = GetGlibTypeName($functionSigType);
- my $returnValueIsGDOMType = IsGDOMClassType($functionSigType);
- my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
-
- my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
- my $parentConditionalString = $codeGenerator->GenerateConditionalString($parentNode);
- my @conditionalWarn = GenerateConditionalWarning($function->signature);
- my @parentConditionalWarn = GenerateConditionalWarning($parentNode);
-
- my $functionSig = "${className}* self";
- my $symbolSig = "${className}*";
-
- my @callImplParams;
- foreach my $param (@{$function->parameters}) {
- my $paramIDLType = $param->type;
- my $paramType = GetGlibTypeName($paramIDLType);
- my $const = $paramType eq "gchar*" ? "const " : "";
- my $paramName = $param->name;
-
- $functionSig .= ", ${const}$paramType $paramName";
- $symbolSig .= ", ${const}$paramType";
-
- my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
- if ($paramIsGDOMType) {
- if ($paramIDLType ne "any") {
- $implIncludes{"WebKitDOM${paramIDLType}Private.h"} = 1;
- }
- }
- if ($paramIsGDOMType || ($paramIDLType eq "DOMString") || ($paramIDLType eq "CompareHow")) {
- $paramName = "converted" . $codeGenerator->WK_ucfirst($paramName);
- }
- push(@callImplParams, $paramName);
- }
-
- if ($returnType ne "void" && $returnValueIsGDOMType && $functionSigType ne "any") {
- $implIncludes{"WebKitDOM${functionSigType}Private.h"} = 1;
- }
-
- $functionSig .= ", GError** error" if $raisesException;
- $symbolSig .= ", GError**" if $raisesException;
-
- push(@symbols, "$returnType $functionName($symbolSig)\n");
-
- if ($deprecationVersion) {
- push(@hBody, "#if !defined(WEBKIT_DISABLE_DEPRECATED)\n");
- }
-
- # Insert introspection annotations
- push(@hBody, "/**\n");
- push(@hBody, " * ${functionName}:\n");
- push(@hBody, " * \@self: A #${className}\n");
-
- foreach my $param (@{$function->parameters}) {
- my $paramType = GetGlibTypeName($param->type);
- # $paramType can have a trailing * in some cases
- $paramType =~ s/\*$//;
- my $paramName = $param->name;
- my $paramAnnotations = "";
- if (ParamCanBeNull($functionName, $paramName)) {
- $paramAnnotations = " (allow-none):";
- }
- push(@hBody, " * \@${paramName}:${paramAnnotations} A #${paramType}\n");
- }
- push(@hBody, " * \@error: #GError\n") if $raisesException;
- push(@hBody, " *\n");
- my $returnTypeName = $returnType;
- $returnTypeName =~ s/\*$//;
- if ($returnValueIsGDOMType) {
- my $transferType = GetTransferTypeForReturnType($functionSigType);
- push(@hBody, " * Returns: (transfer $transferType): A #${returnTypeName}\n");
- } elsif ($returnType ne "void") {
- push(@hBody, " * Returns: A #${returnTypeName}\n");
- }
- if ($deprecationVersion) {
- push(@hBody, " *\n");
- push(@hBody, " * Deprecated: $deprecationVersion");
- if ($deprecationReplacement) {
- push(@hBody, ": Use $deprecationReplacement() instead.");
- }
- push(@hBody, "\n");
- }
- push(@hBody, "**/\n");
-
- if ($deprecationVersion && $deprecationReplacement) {
- push(@hBody, "WEBKIT_DEPRECATED_FOR($deprecationReplacement) ");
- } elsif ($deprecationVersion) {
- push(@hBody, "WEBKIT_DEPRECATED ");
- } else {
- push(@hBody, "WEBKIT_API ");
- }
- push(@hBody, "$returnType\n$functionName($functionSig);\n");
- if ($deprecationVersion) {
- push(@hBody, "#endif /* WEBKIT_DISABLE_DEPRECATED */\n");
- }
- push(@hBody, "\n");
-
- push(@cBody, "$returnType $functionName($functionSig)\n{\n");
- push(@cBody, "#if ${parentConditionalString}\n") if $parentConditionalString;
- push(@cBody, "#if ${conditionalString}\n") if $conditionalString;
-
- push(@cBody, " WebCore::JSMainThreadNullState state;\n");
-
- # g_return macros to check parameters of public methods.
- $gReturnMacro = GetGReturnMacro("self", $interfaceName, $returnType);
- push(@cBody, $gReturnMacro);
-
- foreach my $param (@{$function->parameters}) {
- my $paramName = $param->name;
- my $paramIDLType = $param->type;
- my $paramTypeIsPointer = !$codeGenerator->IsNonPointerType($paramIDLType);
- if ($paramTypeIsPointer) {
- $gReturnMacro = GetGReturnMacro($paramName, $paramIDLType, $returnType, $functionName);
- push(@cBody, $gReturnMacro);
- }
- }
-
- if ($raisesException) {
- $gReturnMacro = GetGReturnMacro("error", "GError", $returnType);
- push(@cBody, $gReturnMacro);
- }
-
- # The WebKit::core implementations check for null already; no need to duplicate effort.
- push(@cBody, " WebCore::${interfaceName}* item = WebKit::core(self);\n");
-
- $returnParamName = "";
- foreach my $param (@{$function->parameters}) {
- my $paramIDLType = $param->type;
- my $paramName = $param->name;
-
- my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
- $convertedParamName = "converted" . $codeGenerator->WK_ucfirst($paramName);
- if ($paramIDLType eq "DOMString") {
- push(@cBody, " WTF::String ${convertedParamName} = WTF::String::fromUTF8($paramName);\n");
- } elsif ($paramIDLType eq "CompareHow") {
- push(@cBody, " WebCore::Range::CompareHow ${convertedParamName} = static_cast<WebCore::Range::CompareHow>($paramName);\n");
- } elsif ($paramIsGDOMType) {
- push(@cBody, " WebCore::${paramIDLType}* ${convertedParamName} = WebKit::core($paramName);\n");
- }
- $returnParamName = $convertedParamName if $param->extendedAttributes->{"CustomReturn"};
- }
-
- my $assign = "";
- my $assignPre = "";
- my $assignPost = "";
-
- # We need to special-case these Node methods because their C++
- # signature is different from what we'd expect given their IDL
- # description; see Node.h.
- my $functionHasCustomReturn = $functionName eq "webkit_dom_node_append_child" ||
- $functionName eq "webkit_dom_node_insert_before" ||
- $functionName eq "webkit_dom_node_replace_child" ||
- $functionName eq "webkit_dom_node_remove_child";
-
- if ($returnType ne "void" && !$functionHasCustomReturn) {
- if ($returnValueIsGDOMType) {
- $assign = "RefPtr<WebCore::${functionSigType}> gobjectResult = ";
- $assignPre = "WTF::getPtr(";
- $assignPost = ")";
- } else {
- $assign = "${returnType} result = ";
- }
- }
-
- # FIXME: Should we return a default value when isNull == true?
- if ($function->signature->isNullable) {
- push(@cBody, " bool isNull = false;\n");
- push(@callImplParams, "isNull");
- }
-
- if ($raisesException) {
- push(@cBody, " WebCore::ExceptionCode ec = 0;\n");
- push(@callImplParams, "ec");
- }
-
- my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $function->signature->name;
-
- if ($functionHasCustomReturn) {
- push(@cBody, " bool ok = item->${functionImplementationName}(" . join(", ", @callImplParams) . ");\n");
- my $customNodeAppendChild = << "EOF";
- if (ok)
- return WebKit::kit($returnParamName);
-EOF
- push(@cBody, $customNodeAppendChild);
-
- if($raisesException) {
- my $exceptionHandling = << "EOF";
-
- WebCore::ExceptionCodeDescription ecdesc(ec);
- g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
-EOF
- push(@cBody, $exceptionHandling);
- }
- push(@cBody, " return 0;\n");
- push(@cBody, "}\n\n");
- return;
- } elsif ($functionSigType eq "DOMString") {
- my $getterContentHead;
- if ($prefix) {
- my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $function);
- push(@arguments, @callImplParams);
- if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
- my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
- $implIncludes{"${implementedBy}.h"} = 1;
- unshift(@arguments, "item");
- $functionName = "WebCore::${implementedBy}::${functionName}";
- } else {
- $functionName = "item->${functionName}";
- }
- $getterContentHead = "${assign}convertToUTF8String(${functionName}(" . join(", ", @arguments) . "));\n";
- } else {
- my @arguments = @callImplParams;
- if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
- my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
- $implIncludes{"${implementedBy}.h"} = 1;
- unshift(@arguments, "item");
- $getterContentHead = "${assign}convertToUTF8String(WebCore::${implementedBy}::${functionImplementationName}(" . join(", ", @arguments) . "));\n";
- } else {
- $getterContentHead = "${assign}convertToUTF8String(item->${functionImplementationName}(" . join(", ", @arguments) . "));\n";
- }
- }
- push(@cBody, " ${getterContentHead}");
- } else {
- my $contentHead;
- if ($prefix eq "get_") {
- my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $function);
- push(@arguments, @callImplParams);
- if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
- my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
- $implIncludes{"${implementedBy}.h"} = 1;
- unshift(@arguments, "item");
- $functionName = "WebCore::${implementedBy}::${functionName}";
- } else {
- $functionName = "item->${functionName}";
- }
- $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
- } elsif ($prefix eq "set_") {
- my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $function);
- push(@arguments, @callImplParams);
- if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
- my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
- $implIncludes{"${implementedBy}.h"} = 1;
- unshift(@arguments, "item");
- $functionName = "WebCore::${implementedBy}::${functionName}";
- $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
- } else {
- $functionName = "item->${functionName}";
- $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
- }
- } else {
- my @arguments = @callImplParams;
- if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
- my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
- $implIncludes{"${implementedBy}.h"} = 1;
- unshift(@arguments, "item");
- $contentHead = "${assign}${assignPre}WebCore::${implementedBy}::${functionImplementationName}(" . join(", ", @arguments) . "${assignPost});\n";
- } else {
- $contentHead = "${assign}${assignPre}item->${functionImplementationName}(" . join(", ", @arguments) . "${assignPost});\n";
- }
- }
- push(@cBody, " ${contentHead}");
-
- if($raisesException) {
- my $exceptionHandling = << "EOF";
- if (ec) {
- WebCore::ExceptionCodeDescription ecdesc(ec);
- g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
- }
-EOF
- push(@cBody, $exceptionHandling);
- }
- }
-
- if ($returnType ne "void" && !$functionHasCustomReturn) {
- if ($functionSigType ne "any") {
- if ($returnValueIsGDOMType) {
- push(@cBody, " return WebKit::kit(gobjectResult.get());\n");
- } else {
- push(@cBody, " return result;\n");
- }
- } else {
- push(@cBody, " return 0; // TODO: return canvas object\n");
- }
- }
-
- if ($conditionalString) {
- push(@cBody, "#else\n");
- push(@cBody, @conditionalWarn) if scalar(@conditionalWarn);
- if ($returnType ne "void") {
- if ($codeGenerator->IsNonPointerType($functionSigType)) {
- push(@cBody, " return static_cast<${returnType}>(0);\n");
- } else {
- push(@cBody, " return 0;\n");
- }
- }
- push(@cBody, "#endif /* ${conditionalString} */\n");
- }
-
- if ($parentConditionalString) {
- push(@cBody, "#else\n");
- push(@cBody, @parentConditionalWarn) if scalar(@parentConditionalWarn);
- if ($returnType ne "void") {
- if ($codeGenerator->IsNonPointerType($functionSigType)) {
- push(@cBody, " return static_cast<${returnType}>(0);\n");
- } else {
- push(@cBody, " return 0;\n");
- }
- }
- push(@cBody, "#endif /* ${parentConditionalString} */\n");
- }
-
- push(@cBody, "}\n\n");
-}
-
-sub ClassHasFunction {
- my ($class, $name) = @_;
-
- foreach my $function (@{$class->functions}) {
- if ($function->signature->name eq $name) {
- return 1;
- }
- }
-
- return 0;
-}
-
-sub GenerateFunctions {
- my ($object, $interfaceName, $interface) = @_;
-
- foreach my $function (@{$interface->functions}) {
- $object->GenerateFunction($interfaceName, $function, "", $interface);
- }
-
- TOP:
- foreach my $attribute (@{$interface->attributes}) {
- if (SkipAttribute($attribute)) {
- next TOP;
- }
-
- if ($attribute->signature->name eq "type") {
- # This will conflict with the get_type() function we define to return a GType
- # according to GObject conventions. Skip this for now.
- next TOP;
- }
-
- my $attrNameUpper = $codeGenerator->WK_ucfirst($attribute->signature->name);
- my $getname = "get${attrNameUpper}";
- my $setname = "set${attrNameUpper}";
- if (ClassHasFunction($interface, $getname) || ClassHasFunction($interface, $setname)) {
- # Very occasionally an IDL file defines getter/setter functions for one of its
- # attributes; in this case we don't need to autogenerate the getter/setter.
- next TOP;
- }
-
- # Generate an attribute getter. For an attribute "foo", this is a function named
- # "get_foo" which calls a DOM class method named foo().
- my $function = new domFunction();
- $function->signature($attribute->signature);
- $function->signature->extendedAttributes({%{$attribute->signature->extendedAttributes}});
- if ($attribute->signature->extendedAttributes->{"GetterRaisesException"}) {
- $function->signature->extendedAttributes->{"RaisesException"} = "VALUE_IS_MISSING";
- }
- $object->GenerateFunction($interfaceName, $function, "get_", $interface);
-
- # FIXME: We are not generating setters for 'Replaceable'
- # attributes now, but we should somehow.
- my $custom = $attribute->signature->extendedAttributes->{"CustomSetter"};
- if ($attribute->isReadOnly || $attribute->signature->extendedAttributes->{"Replaceable"} || $custom) {
- next TOP;
- }
-
- # Generate an attribute setter. For an attribute, "foo", this is a function named
- # "set_foo" which calls a DOM class method named setFoo().
- $function = new domFunction();
-
- $function->signature(new domSignature());
- $function->signature->name($attribute->signature->name);
- $function->signature->type($attribute->signature->type);
- $function->signature->extendedAttributes({%{$attribute->signature->extendedAttributes}});
-
- my $param = new domSignature();
- $param->name("value");
- $param->type($attribute->signature->type);
- my %attributes = ();
- $param->extendedAttributes(\%attributes);
- my $arrayRef = $function->parameters;
- push(@$arrayRef, $param);
-
- if ($attribute->signature->extendedAttributes->{"SetterRaisesException"}) {
- $function->signature->extendedAttributes->{"RaisesException"} = "VALUE_IS_MISSING";
- } else {
- delete $function->signature->extendedAttributes->{"RaisesException"};
- }
-
- $object->GenerateFunction($interfaceName, $function, "set_", $interface);
- }
-}
-
-sub GenerateCFile {
- my ($object, $interfaceName, $parentClassName, $parentGObjType, $interface) = @_;
-
- if ($interface->extendedAttributes->{"EventTarget"}) {
- $object->GenerateEventTargetIface($interface);
- }
-
- my $implContent = "";
-
- my $decamelize = decamelize($interfaceName);
- my $clsCaps = uc($decamelize);
- my $lowerCaseIfaceName = "webkit_dom_$decamelize";
- my $parentImplClassName = GetParentImplClassName($interface);
- my $baseClassName = GetBaseClass($parentImplClassName, $interface);
-
- # Add a private struct only for direct subclasses of Object so that we can use RefPtr
- # for the WebCore wrapped object and make sure we only increment the reference counter once.
- if ($parentImplClassName eq "Object") {
- my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
- push(@cStructPriv, "#define WEBKIT_DOM_${clsCaps}_GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE(obj, WEBKIT_TYPE_DOM_${clsCaps}, ${className}Private)\n\n");
- push(@cStructPriv, "typedef struct _${className}Private {\n");
- push(@cStructPriv, "#if ${conditionalString}\n") if $conditionalString;
- push(@cStructPriv, " RefPtr<WebCore::${interfaceName}> coreObject;\n");
- push(@cStructPriv, "#endif // ${conditionalString}\n") if $conditionalString;
- push(@cStructPriv, "} ${className}Private;\n\n");
- }
-
- $implContent = << "EOF";
-${defineTypeMacro}(${className}, ${lowerCaseIfaceName}, ${parentGObjType}${defineTypeInterfaceImplementation}
-
-EOF
- push(@cBodyProperties, $implContent);
-
- if ($parentImplClassName eq "Object") {
- push(@cBodyPriv, "${className}* kit(WebCore::$interfaceName* obj)\n");
- push(@cBodyPriv, "{\n");
- push(@cBodyPriv, " if (!obj)\n");
- push(@cBodyPriv, " return 0;\n\n");
- push(@cBodyPriv, " if (gpointer ret = DOMObjectCache::get(obj))\n");
- push(@cBodyPriv, " return WEBKIT_DOM_${clsCaps}(ret);\n\n");
- if (IsPolymorphic($interfaceName)) {
- push(@cBodyPriv, " return wrap(obj);\n");
- } else {
- push(@cBodyPriv, " return wrap${interfaceName}(obj);\n");
- }
- push(@cBodyPriv, "}\n\n");
- } else {
- push(@cBodyPriv, "${className}* kit(WebCore::$interfaceName* obj)\n");
- push(@cBodyPriv, "{\n");
- if (!IsPolymorphic($baseClassName)) {
- push(@cBodyPriv, " if (!obj)\n");
- push(@cBodyPriv, " return 0;\n\n");
- push(@cBodyPriv, " if (gpointer ret = DOMObjectCache::get(obj))\n");
- push(@cBodyPriv, " return WEBKIT_DOM_${clsCaps}(ret);\n\n");
- push(@cBodyPriv, " return wrap${interfaceName}(obj);\n");
- } else {
- push(@cBodyPriv, " return WEBKIT_DOM_${clsCaps}(kit(static_cast<WebCore::$baseClassName*>(obj)));\n");
- }
- push(@cBodyPriv, "}\n\n");
- }
-
- $implContent = << "EOF";
-WebCore::${interfaceName}* core(${className}* request)
-{
- return request ? static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(request)->coreObject) : 0;
-}
-
-${className}* wrap${interfaceName}(WebCore::${interfaceName}* coreObject)
-{
- ASSERT(coreObject);
- return WEBKIT_DOM_${clsCaps}(g_object_new(WEBKIT_TYPE_DOM_${clsCaps}, "core-object", coreObject, NULL));
-}
-
-EOF
- push(@cBodyPriv, $implContent);
-
- $object->GenerateProperties($interfaceName, $interface);
- $object->GenerateFunctions($interfaceName, $interface);
-}
-
-sub GenerateEndHeader {
- my ($object) = @_;
-
- #Header guard
- my $guard = $className . "_h";
-
- push(@hBody, "G_END_DECLS\n\n");
- push(@hPrefixGuardEnd, "#endif /* $guard */\n");
-}
-
-sub IsPolymorphic {
- my $type = shift;
-
- return scalar(grep {$_ eq $type} qw(Blob Event HTMLCollection Node StyleSheet));
-}
-
-sub GenerateEventTargetIface {
- my $object = shift;
- my $interface = shift;
-
- my $interfaceName = $interface->name;
- my $decamelize = decamelize($interfaceName);
- my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
- my @conditionalWarn = GenerateConditionalWarning($interface);
-
- $implIncludes{"GObjectEventListener.h"} = 1;
- $implIncludes{"WebKitDOMEventTarget.h"} = 1;
- $implIncludes{"WebKitDOMEventPrivate.h"} = 1;
-
- push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_dispatch_event(WebKitDOMEventTarget* target, WebKitDOMEvent* event, GError** error)\n{\n");
- push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
- push(@cBodyProperties, " WebCore::Event* coreEvent = WebKit::core(event);\n");
- push(@cBodyProperties, " WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n\n");
- push(@cBodyProperties, " WebCore::ExceptionCode ec = 0;\n");
- push(@cBodyProperties, " gboolean result = coreTarget->dispatchEvent(coreEvent, ec);\n");
- push(@cBodyProperties, " if (ec) {\n WebCore::ExceptionCodeDescription description(ec);\n");
- push(@cBodyProperties, " g_set_error_literal(error, g_quark_from_string(\"WEBKIT_DOM\"), description.code, description.name);\n }\n");
- push(@cBodyProperties, " return result;\n");
- push(@cBodyProperties, "#else\n") if $conditionalString;
- push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
- push(@cBodyProperties, " return false;\n#endif // ${conditionalString}\n") if $conditionalString;
- push(@cBodyProperties, "}\n\n");
-
- push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_add_event_listener(WebKitDOMEventTarget* target, const char* eventName, GClosure* handler, gboolean useCapture)\n{\n");
- push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
- push(@cBodyProperties, " WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n");
- push(@cBodyProperties, " return WebCore::GObjectEventListener::addEventListener(G_OBJECT(target), coreTarget, eventName, handler, useCapture);\n");
- push(@cBodyProperties, "#else\n") if $conditionalString;
- push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
- push(@cBodyProperties, " return false;\n#endif // ${conditionalString}\n") if $conditionalString;
- push(@cBodyProperties, "}\n\n");
-
- push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_remove_event_listener(WebKitDOMEventTarget* target, const char* eventName, GClosure* handler, gboolean useCapture)\n{\n");
- push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
- push(@cBodyProperties, " WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n");
- push(@cBodyProperties, " return WebCore::GObjectEventListener::removeEventListener(G_OBJECT(target), coreTarget, eventName, handler, useCapture);\n");
- push(@cBodyProperties, "#else\n") if $conditionalString;
- push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
- push(@cBodyProperties, " return false;\n#endif // ${conditionalString}\n") if $conditionalString;
- push(@cBodyProperties, "}\n\n");
-
- push(@cBodyProperties, "static void webkit_dom_event_target_init(WebKitDOMEventTargetIface* iface)\n{\n");
- push(@cBodyProperties, " iface->dispatch_event = webkit_dom_${decamelize}_dispatch_event;\n");
- push(@cBodyProperties, " iface->add_event_listener = webkit_dom_${decamelize}_add_event_listener;\n");
- push(@cBodyProperties, " iface->remove_event_listener = webkit_dom_${decamelize}_remove_event_listener;\n}\n\n");
-
- $defineTypeMacro = "G_DEFINE_TYPE_WITH_CODE";
- $defineTypeInterfaceImplementation = ", G_IMPLEMENT_INTERFACE(WEBKIT_TYPE_DOM_EVENT_TARGET, webkit_dom_event_target_init))";
-}
-
-sub Generate {
- my ($object, $interface) = @_;
-
- my $parentClassName = GetParentClassName($interface);
- my $parentGObjType = GetParentGObjType($interface);
- my $interfaceName = $interface->name;
- my $parentImplClassName = GetParentImplClassName($interface);
- my $baseClassName = GetBaseClass($parentImplClassName, $interface);
-
- # Add the default impl header template
- @cPrefix = split("\r", $licenceTemplate);
- push(@cPrefix, "\n");
-
- $implIncludes{"DOMObjectCache.h"} = 1;
- $implIncludes{"WebKitDOMPrivate.h"} = 1;
- $implIncludes{"gobject/ConvertToUTF8String.h"} = 1;
- $implIncludes{"${className}Private.h"} = 1;
- $implIncludes{"Document.h"} = 1;
- $implIncludes{"JSMainThreadExecState.h"} = 1;
- $implIncludes{"ExceptionCode.h"} = 1;
- $implIncludes{"CSSImportRule.h"} = 1;
- if ($parentImplClassName ne "Object" and IsPolymorphic($baseClassName)) {
- $implIncludes{"WebKitDOM${baseClassName}Private.h"} = 1;
- }
-
- $hdrIncludes{"webkitdom/${parentClassName}.h"} = 1;
-
- $object->GenerateHeader($interfaceName, $parentClassName);
- $object->GenerateCFile($interfaceName, $parentClassName, $parentGObjType, $interface);
- $object->GenerateEndHeader();
-}
-
-sub WriteData {
- my $object = shift;
- my $interface = shift;
- my $outputDir = shift;
- mkdir $outputDir;
-
- # Write a private header.
- my $interfaceName = $interface->name;
- my $filename = "$outputDir/" . $className . "Private.h";
- my $guard = "${className}Private_h";
-
- # Add the guard if the 'Conditional' extended attribute exists
- my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
-
- open(PRIVHEADER, ">$filename") or die "Couldn't open file $filename for writing";
-
- print PRIVHEADER split("\r", $licenceTemplate);
- print PRIVHEADER "\n";
-
- my $text = << "EOF";
-#ifndef $guard
-#define $guard
-
-#include "${interfaceName}.h"
-#include <webkitdom/${className}.h>
-EOF
-
- print PRIVHEADER $text;
- print PRIVHEADER "#if ${conditionalString}\n" if $conditionalString;
- print PRIVHEADER map { "#include \"$_\"\n" } sort keys(%hdrPropIncludes);
- print PRIVHEADER "\n";
- $text = << "EOF";
-namespace WebKit {
-${className}* wrap${interfaceName}(WebCore::${interfaceName}*);
-${className}* kit(WebCore::${interfaceName}*);
-WebCore::${interfaceName}* core(${className}*);
-EOF
-
- print PRIVHEADER $text;
-
- $text = << "EOF";
-} // namespace WebKit
-
-EOF
-
- print PRIVHEADER $text;
- print PRIVHEADER "#endif /* ${conditionalString} */\n\n" if $conditionalString;
- print PRIVHEADER "#endif /* ${guard} */\n";
-
- close(PRIVHEADER);
-
- my $basename = FileNamePrefix . $interfaceName;
- $basename =~ s/_//g;
-
- # Write public header.
- my $fullHeaderFilename = "$outputDir/" . $basename . ".h";
- my $installedHeaderFilename = "${basename}.h";
- open(HEADER, ">$fullHeaderFilename") or die "Couldn't open file $fullHeaderFilename";
-
- print HEADER @hPrefix;
- print HEADER @hPrefixGuard;
- print HEADER "#include <glib-object.h>\n";
- print HEADER map { "#include <$_>\n" } sort keys(%hdrIncludes);
- print HEADER "#include <webkitdom/webkitdomdefines.h>\n\n";
- print HEADER @hBodyPre;
- print HEADER @hBody;
- print HEADER @hPrefixGuardEnd;
-
- close(HEADER);
-
- # Write the implementation sources
- my $implFileName = "$outputDir/" . $basename . ".cpp";
- open(IMPL, ">$implFileName") or die "Couldn't open file $implFileName";
-
- print IMPL @cPrefix;
- print IMPL "#include \"config.h\"\n";
- print IMPL "#include \"$installedHeaderFilename\"\n\n";
-
- # Remove the implementation header from the list of included files.
- %includesCopy = %implIncludes;
- print IMPL map { "#include \"$_\"\n" } sort keys(%includesCopy);
-
- print IMPL "#include <wtf/GetPtr.h>\n";
- print IMPL "#include <wtf/RefPtr.h>\n\n";
- print IMPL @cStructPriv;
- print IMPL "#if ${conditionalString}\n\n" if $conditionalString;
-
- print IMPL "namespace WebKit {\n\n";
- print IMPL @cBodyPriv;
- print IMPL "} // namespace WebKit\n\n";
- print IMPL "#endif // ${conditionalString}\n\n" if $conditionalString;
-
- print IMPL @cBodyProperties;
- print IMPL @cBody;
-
- close(IMPL);
-
- # Write a symbols file.
- my $symbolsFileName = "$outputDir/" . $basename . ".symbols";
- open(SYM, ">$symbolsFileName") or die "Couldn't open file $symbolsFileName";
- print SYM @symbols;
- close(SYM);
-
- %implIncludes = ();
- %hdrIncludes = ();
- @hPrefix = ();
- @hBody = ();
-
- @cPrefix = ();
- @cBody = ();
- @cBodyPriv = ();
- @cBodyProperties = ();
- @cStructPriv = ();
-
- @symbols = ();
-}
-
-sub GenerateInterface {
- my ($object, $interface, $defines) = @_;
-
- # Set up some global variables
- $className = GetClassName($interface->name);
-
- $object->Generate($interface);
-}
-
-1;
diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
index d3685f8e3..b71e2ce9a 100644
--- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
+++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
@@ -3,7 +3,7 @@
# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
# Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
-# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved.
+# Copyright (C) 2006-2017 Apple Inc. All rights reserved.
# 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)
@@ -11,6 +11,7 @@
# Copyright (C) 2012 Ericsson AB. All rights reserved.
# Copyright (C) 2007, 2008, 2009, 2012 Google Inc.
# Copyright (C) 2013 Samsung Electronics. All rights reserved.
+# Copyright (C) 2015, 2016 Canon Inc. All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
@@ -27,15 +28,17 @@
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
+
package CodeGeneratorJS;
use strict;
use constant FileNamePrefix => "JS";
+use Carp qw<longmess>;
+use Data::Dumper;
use Hasher;
my $codeGenerator;
-
-my $writeDependencies = 0;
+my $writeDependencies;
my @headerContentHeader = ();
my @headerContent = ();
@@ -47,7 +50,6 @@ my @implContent = ();
my %implIncludes = ();
my @depsContent = ();
my $numCachedAttributes = 0;
-my $currentCachedAttribute = 0;
my $beginAppleCopyrightForHeaderFiles = <<END;
// ------- Begin Apple Copyright -------
@@ -106,6 +108,16 @@ my $headerTemplate = << "EOF";
*/
EOF
+sub assert
+{
+ my $message = shift;
+
+ my $mess = longmess();
+ print Dumper($mess);
+
+ die $message;
+}
+
# Default constructor
sub new
{
@@ -113,96 +125,99 @@ sub new
my $reference = { };
$codeGenerator = shift;
- shift; # $useLayerOnTop
- shift; # $preprocessor
$writeDependencies = shift;
bless($reference, $object);
return $reference;
}
+sub GenerateEnumeration
+{
+ my ($object, $enumeration) = @_;
+
+ my $className = GetEnumerationClassName($enumeration->type);
+ $object->GenerateEnumerationHeader($enumeration, $className);
+ $object->GenerateEnumerationImplementation($enumeration, $className);
+}
+
+sub GenerateDictionary
+{
+ my ($object, $dictionary, $enumerations, $otherDictionaries) = @_;
+
+ my $className = GetDictionaryClassName($dictionary->type);
+ $object->GenerateDictionaryHeader($dictionary, $className, $enumerations, $otherDictionaries);
+ $object->GenerateDictionaryImplementation($dictionary, $className, $enumerations, $otherDictionaries);
+}
+
+sub GenerateCallbackFunction
+{
+ my ($object, $callbackFunction, $enumerations, $dictionaries) = @_;
+
+ $object->GenerateCallbackFunctionHeader($callbackFunction, $enumerations, $dictionaries);
+ $object->GenerateCallbackFunctionImplementation($callbackFunction, $enumerations, $dictionaries);
+}
+
sub GenerateInterface
{
- my $object = shift;
- my $interface = shift;
- my $defines = shift;
+ my ($object, $interface, $defines, $enumerations, $dictionaries) = @_;
$codeGenerator->LinkOverloadedFunctions($interface);
+ AddStringifierOperationIfNeeded($interface);
- # Start actual generation
if ($interface->isCallback) {
- $object->GenerateCallbackHeader($interface);
- $object->GenerateCallbackImplementation($interface);
+ $object->GenerateCallbackInterfaceHeader($interface, $enumerations, $dictionaries);
+ $object->GenerateCallbackInterfaceImplementation($interface, $enumerations, $dictionaries);
} else {
- $object->GenerateHeader($interface);
- $object->GenerateImplementation($interface);
+ $object->GenerateHeader($interface, $enumerations, $dictionaries);
+ $object->GenerateImplementation($interface, $enumerations, $dictionaries);
}
}
-sub GenerateAttributeEventListenerCall
+sub AddStringifierOperationIfNeeded
{
- my $className = shift;
- my $implSetterFunctionName = shift;
- my $windowEventListener = shift;
+ my $interface = shift;
- my $wrapperObject = $windowEventListener ? "globalObject" : "castedThis";
- my @GenerateEventListenerImpl = ();
+ foreach my $attribute (@{$interface->attributes}) {
+ next unless $attribute->isStringifier;
- if ($className eq "JSSVGElementInstance") {
- # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement
- $wrapperObject = "asObject(correspondingElementWrapper)";
+ my $stringifier = IDLOperation->new();
+ $stringifier->name("toString");
- push(@GenerateEventListenerImpl, <<END);
- JSValue correspondingElementWrapper = toJS(exec, castedThis->globalObject(), impl.correspondingElement());
- if (correspondingElementWrapper.isObject())
-END
+ my $extendedAttributeList = {};
+ $extendedAttributeList->{ImplementedAs} = $attribute->name;
+ $stringifier->extendedAttributes($extendedAttributeList);
+ die "stringifier can only be used on attributes of String types" unless $codeGenerator->IsStringType($attribute->type);
+
+ # FIXME: This should use IDLParser's cloneType.
+ my $type = IDLType->new();
+ $type->name($attribute->type->name);
- # Add leading whitespace to format the impl.set... line correctly
- push(@GenerateEventListenerImpl, " ");
- }
+ $stringifier->type($type);
- push(@GenerateEventListenerImpl, " impl.set$implSetterFunctionName(createJSAttributeEventListener(exec, value, $wrapperObject));\n");
- return @GenerateEventListenerImpl;
+ push(@{$interface->functions}, $stringifier);
+ last;
+ }
}
-sub GenerateEventListenerCall
+sub EventHandlerAttributeEventName
{
- my $className = shift;
- my $functionName = shift;
- my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
-
- $implIncludes{"JSEventListener.h"} = 1;
-
- my @GenerateEventListenerImpl = ();
- my $wrapperObject = "castedThis";
- if ($className eq "JSSVGElementInstance") {
- # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement
- $wrapperObject = "asObject(correspondingElementWrapper)";
+ my $attribute = shift;
+ my $eventType = $attribute->extendedAttributes->{ImplementedAs} || $attribute->name;
- push(@GenerateEventListenerImpl, <<END);
- JSValue correspondingElementWrapper = toJS(exec, castedThis->globalObject(), impl.correspondingElement());
- if (!correspondingElementWrapper.isObject())
- return JSValue::encode(jsUndefined());
-END
- }
+ # Remove the "on" prefix.
+ $eventType = substr($eventType, 2);
- push(@GenerateEventListenerImpl, <<END);
- JSValue listener = exec->argument(1);
- if (!listener.isObject())
- return JSValue::encode(jsUndefined());
- impl.${functionName}EventListener(exec->argument(0).toString(exec)->value(exec), JSEventListener::create(asObject(listener), $wrapperObject, false, currentWorld(exec))$passRefPtrHandling, exec->argument(2).toBoolean(exec));
- return JSValue::encode(jsUndefined());
-END
- return @GenerateEventListenerImpl;
+ return "eventNames().${eventType}Event";
}
sub GetParentClassName
{
my $interface = shift;
- return $interface->extendedAttributes->{"JSLegacyParent"} if $interface->extendedAttributes->{"JSLegacyParent"};
- return "JSDOMWrapper" unless $interface->parent;
- return "JS" . $interface->parent;
+ return $interface->extendedAttributes->{JSLegacyParent} if $interface->extendedAttributes->{JSLegacyParent};
+ return "JSDOMObject" unless NeedsImplementationClass($interface);
+ return "JSDOMWrapper<" . GetImplClassName($interface) . ">" unless $interface->parentType;
+ return "JS" . $interface->parentType->name;
}
sub GetCallbackClassName
@@ -212,286 +227,499 @@ sub GetCallbackClassName
return "JS$className";
}
-sub AddIncludesForTypeInImpl
+sub GetJSCallbackDataType
{
- my $type = shift;
- my $isCallback = @_ ? shift : 0;
-
- AddIncludesForType($type, $isCallback, \%implIncludes);
+ my $callback = shift;
+
+ return $callback->extendedAttributes->{IsWeakCallback} ? "JSCallbackDataWeak" : "JSCallbackDataStrong";
}
-sub AddIncludesForTypeInHeader
+sub GetExportMacroForJSClass
{
- my $type = shift;
- my $isCallback = @_ ? shift : 0;
+ my $interface = shift;
+
+ return $interface->extendedAttributes->{ExportMacro} . " " if $interface->extendedAttributes->{ExportMacro};
+ return "";
+}
+
+sub AddIncludesForImplementationTypeInImpl
+{
+ my $implementationType = shift;
- AddIncludesForType($type, $isCallback, \%headerIncludes);
+ AddIncludesForImplementationType($implementationType, \%implIncludes);
}
-my %typesWithoutHeader = (
- "Array" => 1,
- "DOMString" => 1,
- "DOMTimeStamp" => 1,
- "any" => 1
-);
+sub AddIncludesForImplementationTypeInHeader
+{
+ my $implementationType = shift;
+
+ AddIncludesForImplementationType($implementationType, \%headerIncludes);
+}
-sub SkipIncludeHeader
+sub AddIncludesForImplementationType
{
- my $type = shift;
+ my ($implementationType, $includesRef) = @_;
- return 1 if $codeGenerator->SkipIncludeHeader($type);
- return $typesWithoutHeader{$type};
+ $includesRef->{"${implementationType}.h"} = 1;
}
-sub AddIncludesForType
+sub AddToImplIncludesForIDLType
{
- my $type = shift;
- my $isCallback = shift;
- my $includesRef = shift;
+ my ($type, $conditional) = @_;
+
+ return AddToIncludesForIDLType($type, \%implIncludes, $conditional)
+}
- return if SkipIncludeHeader($type);
+sub AddToIncludesForIDLType
+{
+ my ($type, $includesRef, $conditional) = @_;
- # When we're finished with the one-file-per-class
- # reorganization, we won't need these special cases.
- if ($type eq "XPathNSResolver") {
- $includesRef->{"JSXPathNSResolver.h"} = 1;
- $includesRef->{"JSCustomXPathNSResolver.h"} = 1;
- } elsif ($isCallback && $codeGenerator->IsWrapperType($type)) {
- $includesRef->{"JS${type}.h"} = 1;
- } elsif ($codeGenerator->GetSequenceType($type) or $codeGenerator->GetArrayType($type)) {
- my $arrayType = $codeGenerator->GetArrayType($type);
- my $sequenceType = $codeGenerator->GetSequenceType($type);
- my $arrayOrSequenceType = $arrayType || $sequenceType;
-
- if ($arrayType eq "DOMString") {
- $includesRef->{"JSDOMStringList.h"} = 1;
- $includesRef->{"DOMStringList.h"} = 1;
- } elsif ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) {
- $includesRef->{"JS${arrayOrSequenceType}.h"} = 1;
- $includesRef->{"${arrayOrSequenceType}.h"} = 1;
+ return if $codeGenerator->IsPrimitiveType($type);
+ return if $codeGenerator->IsStringType($type);
+ return if $codeGenerator->IsTypedArrayType($type);
+ return if $type->name eq "any";
+ return if $type->name eq "object";
+
+ if ($type->isUnion) {
+ AddToIncludes("<wtf/Variant.h>", $includesRef, $conditional);
+
+ foreach my $memberType (@{$type->subtypes}) {
+ AddToIncludesForIDLType($memberType, $includesRef, $conditional);
}
- $includesRef->{"<runtime/JSArray.h>"} = 1;
- } else {
- # default, include the same named file
- $includesRef->{"${type}.h"} = 1;
+
+ return;
+ }
+
+ if ($codeGenerator->IsSequenceOrFrozenArrayType($type)) {
+ AddToIncludes("<runtime/JSArray.h>", $includesRef, $conditional);
+ AddToIncludesForIDLType(@{$type->subtypes}[0], $includesRef, $conditional);
+ return;
+ }
+
+ if ($codeGenerator->IsRecordType($type)) {
+ AddToIncludes("<wtf/Vector.h>", $includesRef, $conditional);
+ AddToIncludesForIDLType(@{$type->subtypes}[0], $includesRef, $conditional);
+ AddToIncludesForIDLType(@{$type->subtypes}[1], $includesRef, $conditional);
+ return;
+ }
+
+ if ($codeGenerator->IsWrapperType($type) || $codeGenerator->IsExternalDictionaryType($type) || $codeGenerator->IsExternalEnumType($type) || $type->name eq "EventListener") {
+ AddToIncludes("JS" . $type->name . ".h", $includesRef, $conditional);
+ return;
+ }
+
+ if ($type->name eq "SerializedScriptValue") {
+ AddToIncludes($type->name . ".h", $includesRef, $conditional);
+ return;
}
}
sub AddToImplIncludes
{
- my $header = shift;
- my $conditional = shift;
+ my ($header, $conditional) = @_;
- 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);
- }
- }
+ AddToIncludes($header, \%implIncludes, $conditional);
}
-sub IsScriptProfileType
+sub AddToIncludes
{
- my $type = shift;
- return 1 if ($type eq "ScriptProfileNode");
- return 0;
+ my ($header, $includesRef, $conditional) = @_;
+
+ if (not $conditional) {
+ $includesRef->{$header} = 1;
+ } elsif (not exists($includesRef->{$header})) {
+ $includesRef->{$header} = $conditional;
+ } else {
+ my $oldValue = $includesRef->{$header};
+ $includesRef->{$header} = "$oldValue|$conditional" if $oldValue ne 1;
+ }
}
sub IsReadonly
{
my $attribute = shift;
- return $attribute->isReadOnly && !$attribute->signature->extendedAttributes->{"Replaceable"};
+ return $attribute->isReadOnly && !$attribute->extendedAttributes->{Replaceable} && !$attribute->extendedAttributes->{PutForwards};
}
-sub AddTypedefForScriptProfileType
+sub AddClassForwardIfNeeded
{
my $type = shift;
- (my $jscType = $type) =~ s/Script//;
- push(@headerContent, "typedef JSC::$jscType $type;\n\n");
-}
+ # SVGAnimatedLength/Number/etc. are not classes so they can't be forward declared as classes.
+ return if $codeGenerator->IsSVGAnimatedType($type);
+ return if $codeGenerator->IsTypedArrayType($type);
+ return if $type->name eq "BufferSource";
-sub AddClassForwardIfNeeded
-{
- my $interfaceName = shift;
-
- # SVGAnimatedLength/Number/etc. are typedefs to SVGAnimatedTemplate, so don't use class forwards for them!
- unless ($codeGenerator->IsSVGAnimatedType($interfaceName) or IsScriptProfileType($interfaceName) or $codeGenerator->IsTypedArrayType($interfaceName)) {
- push(@headerContent, "class $interfaceName;\n\n");
- # ScriptProfile and ScriptProfileNode are typedefs to JSC::Profile and JSC::ProfileNode.
- } elsif (IsScriptProfileType($interfaceName)) {
- $headerIncludes{"<profiler/ProfileNode.h>"} = 1;
- AddTypedefForScriptProfileType($interfaceName);
- }
+ push(@headerContent, "class " . $type->name . ";\n\n");
}
-sub hashTableAccessor
+sub GetGenerateIsReachable
{
- my $noStaticTables = shift;
- my $className = shift;
- if ($noStaticTables) {
- return "get${className}Table(exec->vm())";
- } else {
- return "${className}Table";
- }
+ my $interface = shift;
+ return $interface->extendedAttributes->{GenerateIsReachable};
}
-sub prototypeHashTableAccessor
+sub GetCustomIsReachable
{
- my $noStaticTables = shift;
- my $className = shift;
- if ($noStaticTables) {
- return "get${className}PrototypeTable(exec->vm())";
- } else {
- return "${className}PrototypeTable";
- }
+ my $interface = shift;
+ return $interface->extendedAttributes->{CustomIsReachable};
}
-sub constructorHashTableAccessor
+sub IsDOMGlobalObject
{
- my $noStaticTables = shift;
- my $constructorClassName = shift;
- if ($noStaticTables) {
- return "get${constructorClassName}Table(exec->vm())";
- } else {
- return "${constructorClassName}Table";
- }
+ my $interface = shift;
+ return $interface->type->name eq "DOMWindow" || $codeGenerator->InheritsInterface($interface, "WorkerGlobalScope") || $interface->type->name eq "TestGlobalObject";
}
-sub GetGenerateIsReachable
+sub ShouldUseGlobalObjectPrototype
{
my $interface = shift;
- return $interface->extendedAttributes->{"GenerateIsReachable"};
+
+ # For workers, the global object is a DedicatedWorkerGlobalScope.
+ return 0 if $interface->type->name eq "WorkerGlobalScope";
+
+ return IsDOMGlobalObject($interface);
}
-sub GetCustomIsReachable
+sub GenerateIndexedGetter
{
- my $interface = shift;
- return $interface->extendedAttributes->{"CustomIsReachable"};
+ my ($interface, $indexedGetterFunction) = @_;
+
+ my @output = ();
+
+ my @attributes = ();
+ push(@attributes, "ReadOnly") if !$interface->extendedAttributes->{CustomNamedSetter};
+
+ my $attributeString = ((@attributes > 0) ? join(" | ", @attributes) : "0");
+
+ my $indexedGetterFunctionName = $indexedGetterFunction->name || "item";
+ my $nativeToJSConversion = NativeToJSValueUsingPointers($indexedGetterFunction, $interface, "thisObject->wrapped().${indexedGetterFunctionName}(index)", "thisObject");
+
+ push(@output, " slot.setValue(thisObject, ${attributeString}, ${nativeToJSConversion});\n");
+ push(@output, " return true;\n");
+
+ return @output;
}
-sub IsDOMGlobalObject
+sub GenerateNamedGetter
{
- my $interface = shift;
- return $interface->name eq "DOMWindow" || $codeGenerator->InheritsInterface($interface, "WorkerGlobalScope");
+ my ($interface, $namedGetterFunction) = @_;
+
+ my @output = ();
+
+ my @attributes = ();
+ push(@attributes, "ReadOnly") if !$interface->extendedAttributes->{CustomNamedSetter};
+ push(@attributes, "DontEnum") if $interface->extendedAttributes->{LegacyUnenumerableNamedProperties};
+
+ my $attributeString = ((@attributes > 0) ? join(" | ", @attributes) : "0");
+
+ if ($interface->extendedAttributes->{CustomNamedGetter}) {
+ push(@output, " JSValue value;\n");
+ push(@output, " if (thisObject->nameGetter(state, propertyName, value)) {\n");
+ push(@output, " slot.setValue(thisObject, ${attributeString}, value);\n");
+ } else {
+ my $namedGetterFunctionName = $namedGetterFunction->name || "namedItem";
+ my $itemVariable = "item";
+ push(@output, " auto item = thisObject->wrapped().${namedGetterFunctionName}(propertyNameToAtomicString(propertyName));\n");
+
+ if ($namedGetterFunction->extendedAttributes->{MayThrowException}) {
+ push(@output, " if (item.hasException()) {\n");
+ push(@output, " auto throwScope = DECLARE_THROW_SCOPE(state->vm());\n");
+ push(@output, " propagateException(*state, throwScope, item.releaseException());\n");
+ push(@output, " return true;\n");
+ push(@output, " }\n\n");
+ push(@output, " auto itemValue = item.releaseReturnValue();\n");
+
+ $itemVariable = "itemValue";
+ }
+
+ my $IDLType = GetIDLType($interface, $namedGetterFunction->type);
+ push(@output, " if (!${IDLType}::isNullValue(${itemVariable})) {\n");
+
+ my $nativeToJSConversion = NativeToJSValueUsingPointers($namedGetterFunction, $interface, $itemVariable, "thisObject", 1);
+ push(@output, " slot.setValue(thisObject, ${attributeString}, ${nativeToJSConversion});\n");
+ }
+
+ push(@output, " return true;\n");
+ push(@output, " }\n");
+
+ return @output;
}
sub GenerateGetOwnPropertySlotBody
{
- my ($interface, $interfaceName, $className, $hasAttributes, $inlined) = @_;
+ my ($interface, $className, $indexedGetterFunction, $namedGetterFunction) = @_;
- my $namespaceMaybe = ($inlined ? "JSC::" : "");
- my $namedGetterFunction = GetNamedGetterFunction($interface);
- my $indexedGetterFunction = GetIndexedGetterFunction($interface);
- my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
+ my @output = ();
- my @getOwnPropertySlotImpl = ();
+ my $ownPropertyCheck = sub {
+ push(@output, " if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot))\n");
+ push(@output, " return true;\n");
+ };
- if ($interfaceName eq "NamedNodeMap" or $interfaceName =~ /^HTML\w*Collection$/) {
- push(@getOwnPropertySlotImpl, " ${namespaceMaybe}JSValue proto = thisObject->prototype();\n");
- push(@getOwnPropertySlotImpl, " if (proto.isObject() && jsCast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n");
- push(@getOwnPropertySlotImpl, " return false;\n\n");
+ # FIXME: As per the Web IDL specification, the prototype check is supposed to skip "named properties objects":
+ # https://heycam.github.io/webidl/#dfn-named-property-visibility
+ # https://heycam.github.io/webidl/#dfn-named-properties-object
+ my $prototypeCheck = sub {
+ push(@output, " JSValue proto = thisObject->getPrototypeDirect();\n");
+ push(@output, " if (proto.isObject() && jsCast<JSObject*>(proto)->hasProperty(state, propertyName))\n");
+ push(@output, " return false;\n\n");
+ };
+
+ push(@output, "bool ${className}::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)\n");
+ push(@output, "{\n");
+ push(@output, " auto* thisObject = jsCast<${className}*>(object);\n");
+ push(@output, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
+
+
+ if ($indexedGetterFunction) {
+ push(@output, " auto optionalIndex = parseIndex(propertyName);\n");
+ push(@output, " if (optionalIndex && optionalIndex.value() < thisObject->wrapped().length()) {\n");
+ push(@output, " auto index = optionalIndex.value();\n");
+ push(@output, GenerateIndexedGetter($interface, $indexedGetterFunction));
+ push(@output, " }\n");
+ }
+
+ my $hasNamedGetter = $namedGetterFunction || $interface->extendedAttributes->{CustomNamedGetter};
+ if ($hasNamedGetter) {
+ if (!$interface->extendedAttributes->{OverrideBuiltins}) {
+ &$ownPropertyCheck();
+ &$prototypeCheck();
+ }
+ if ($indexedGetterFunction) {
+ push(@output, " if (!optionalIndex && thisObject->classInfo() == info() && !propertyName.isSymbol()) {\n");
+ } else {
+ push(@output, " if (thisObject->classInfo() == info() && !propertyName.isSymbol()) {\n");
+ }
+ push(@output, GenerateNamedGetter($interface, $namedGetterFunction));
+ push(@output, " }\n");
+ }
+
+ if ($interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}) {
+ push(@output, " if (thisObject->getOwnPropertySlotDelegate(state, propertyName, slot))\n");
+ push(@output, " return true;\n");
+ }
+
+ if (!$hasNamedGetter || $interface->extendedAttributes->{OverrideBuiltins}) {
+ &$ownPropertyCheck();
}
- my $manualLookupGetterGeneration = sub {
- my $requiresManualLookup = ($indexedGetterFunction && !$hasNumericIndexedGetter) || $namedGetterFunction;
- if ($requiresManualLookup) {
- push(@getOwnPropertySlotImpl, " const ${namespaceMaybe}HashEntry* entry = getStaticValueSlotEntryWithoutCaching<$className>(exec, propertyName);\n");
- push(@getOwnPropertySlotImpl, " if (entry) {\n");
- push(@getOwnPropertySlotImpl, " slot.setCustom(thisObject, entry->attributes(), entry->propertyGetter());\n");
- push(@getOwnPropertySlotImpl, " return true;\n");
- push(@getOwnPropertySlotImpl, " }\n");
+ push(@output, " return false;\n");
+ push(@output, "}\n\n");
+
+ return @output;
+}
+
+sub GenerateGetOwnPropertySlotBodyByIndex
+{
+ my ($interface, $className, $indexedGetterFunction, $namedGetterFunction) = @_;
+
+ my @output = ();
+
+ push(@output, "bool ${className}::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot)\n");
+ push(@output, "{\n");
+ push(@output, " auto* thisObject = jsCast<${className}*>(object);\n");
+ push(@output, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
+
+ # Sink the int-to-string conversion that happens when we create a PropertyName
+ # to the point where we actually need it.
+ my $generatedPropertyName = 0;
+ my $propertyNameGeneration = sub {
+ if ($generatedPropertyName) {
+ return;
}
+ push(@output, " Identifier propertyName = Identifier::from(state, index);\n");
+ $generatedPropertyName = 1;
};
+
+ if ($indexedGetterFunction) {
+ push(@output, " if (LIKELY(index < thisObject->wrapped().length())) {\n");
+ push(@output, GenerateIndexedGetter($interface, $indexedGetterFunction));
+ push(@output, " }\n");
+ }
- if (!$interface->extendedAttributes->{"CustomNamedGetter"}) {
- &$manualLookupGetterGeneration();
+ # Indexing an object with an integer that is not a supported property index should not call the named property getter.
+ # https://heycam.github.io/webidl/#idl-indexed-properties
+ if (!$indexedGetterFunction && ($namedGetterFunction || $interface->extendedAttributes->{CustomNamedGetter})) {
+ &$propertyNameGeneration();
+ push(@output, " if (thisObject->classInfo() == info()) {\n");
+ push(@output, GenerateNamedGetter($interface, $namedGetterFunction));
+ push(@output, " }\n");
}
- if ($indexedGetterFunction) {
- push(@getOwnPropertySlotImpl, " unsigned index = propertyName.asIndex();\n");
+ if ($interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}) {
+ &$propertyNameGeneration();
+ push(@output, " if (thisObject->getOwnPropertySlotDelegate(state, propertyName, slot))\n");
+ push(@output, " return true;\n");
+ }
- # If the item function returns a string then we let the TreatReturnedNullStringAs handle the cases
- # where the index is out of range.
- if ($indexedGetterFunction->signature->type eq "DOMString") {
- push(@getOwnPropertySlotImpl, " if (index != PropertyName::NotAnIndex) {\n");
- } else {
- push(@getOwnPropertySlotImpl, " if (index != PropertyName::NotAnIndex && index < thisObject->impl().length()) {\n");
- }
- # Assume that if there's a setter, the index will be writable
- if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
- push(@getOwnPropertySlotImpl, " unsigned attributes = ${namespaceMaybe}DontDelete;\n");
- } else {
- push(@getOwnPropertySlotImpl, " unsigned attributes = ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly;\n");
- }
- if ($hasNumericIndexedGetter) {
- push(@getOwnPropertySlotImpl, " slot.setValue(thisObject, attributes, thisObject->getByIndex(exec, index));\n");
+ push(@output, " return Base::getOwnPropertySlotByIndex(thisObject, state, index, slot);\n");
+ push(@output, "}\n\n");
+
+ return @output;
+}
+
+sub GenerateGetOwnPropertyNames
+{
+ my ($interface, $className, $indexedGetterFunction, $namedGetterFunction) = @_;
+
+ my @output = ();
+
+ # Property enumeration - https://heycam.github.io/webidl/#legacy-platform-object-property-enumeration
+
+ push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* state, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " auto* thisObject = jsCast<${className}*>(object);\n");
+ push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
+
+ # 1. If the object supports indexed properties, then the object’s supported
+ # property indices are enumerated first, in numerical order.
+ if ($indexedGetterFunction) {
+ push(@implContent, " for (unsigned i = 0, count = thisObject->wrapped().length(); i < count; ++i)\n");
+ push(@implContent, " propertyNames.add(Identifier::from(state, i));\n");
+ }
+
+ # 2. If the object supports named properties and doesn’t implement an interface
+ # with the [LegacyUnenumerableNamedProperties] extended attribute, then the
+ # object’s supported property names that are visible according to the named
+ # property visibility algorithm are enumerated next, in the order given in
+ # the definition of the set of supported property names.
+ if ($namedGetterFunction) {
+ if (!$interface->extendedAttributes->{LegacyUnenumerableNamedProperties}) {
+ push(@implContent, " for (auto& propertyName : thisObject->wrapped().supportedPropertyNames())\n");
+ push(@implContent, " propertyNames.add(Identifier::fromString(state, propertyName));\n");
} else {
- push(@getOwnPropertySlotImpl, " slot.setCustomIndex(thisObject, attributes, index, indexGetter);\n");
+ push(@implContent, " if (mode.includeDontEnumProperties()) {\n");
+ push(@implContent, " for (auto& propertyName : thisObject->wrapped().supportedPropertyNames())\n");
+ push(@implContent, " propertyNames.add(Identifier::fromString(state, propertyName));\n");
+ push(@implContent, " }\n");
}
- push(@getOwnPropertySlotImpl, " return true;\n");
- push(@getOwnPropertySlotImpl, " }\n");
}
+ # 3. Finally, any enumerable own properties or properties from the object’s
+ # prototype chain are then enumerated, in no defined order.
+ push(@implContent, " Base::getOwnPropertyNames(thisObject, state, propertyNames, mode);\n");
+ push(@implContent, "}\n\n");
- if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
- push(@getOwnPropertySlotImpl, " if (canGetItemsForName(exec, &thisObject->impl(), propertyName)) {\n");
- push(@getOwnPropertySlotImpl, " slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);\n");
- push(@getOwnPropertySlotImpl, " return true;\n");
- push(@getOwnPropertySlotImpl, " }\n");
- if ($inlined) {
- $headerIncludes{"wtf/text/AtomicString.h"} = 1;
+ return @output;
+}
+
+sub GeneratePut
+{
+ my ($interface, $className, $indexedSetterFunction, $namedSetterFunction) = @_;
+
+ assert("Named setters are not supported.") if $namedSetterFunction;
+
+ my @output = ();
+
+ push(@output, "bool ${className}::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
+ push(@output, "{\n");
+ push(@output, " auto* thisObject = jsCast<${className}*>(cell);\n");
+ push(@output, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
+
+ if ($indexedSetterFunction || $interface->extendedAttributes->{CustomIndexedSetter}) {
+ if ($interface->extendedAttributes->{CustomIndexedSetter}) {
+ push(@output, " if (auto index = parseIndex(propertyName)) {\n");
+ push(@output, " thisObject->indexSetter(state, index.value(), value);\n");
+ push(@output, " return true;\n");
+ push(@output, " }\n");
} else {
- $implIncludes{"wtf/text/AtomicString.h"} = 1;
+ # The second argument of the indexed setter function is the argument being converted.
+ my $argument = @{$indexedSetterFunction->arguments}[1];
+ my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $argument, "value", $indexedSetterFunction->extendedAttributes->{Conditional}, "state", "*state", "thisObject", "", "");
+
+ push(@output, " if (auto index = parseIndex(propertyName)) {\n");
+ push(@output, " auto throwScope = DECLARE_THROW_SCOPE(state->vm());\n");
+ push(@output, " auto nativeValue = ${nativeValue};\n");
+ push(@output, " RETURN_IF_EXCEPTION(throwScope, true);\n") if $mayThrowException;
+
+ my $indexedSetterFunctionName = $indexedSetterFunction->name || "setItem";
+ my $functionString = "${indexedSetterFunctionName}(index, WTFMove(nativeValue))";
+ $functionString = "propagateException(*state, throwScope, ${functionString})" if NeedsExplicitPropagateExceptionCall($indexedSetterFunction);
+
+ push(@output, " ${functionString};\n");
+ push(@output, " return true;\n");
+ push(@output, " }\n");
}
}
-
- if ($interface->extendedAttributes->{"CustomNamedGetter"}) {
- &$manualLookupGetterGeneration();
+
+ if ($interface->extendedAttributes->{CustomNamedSetter}) {
+ push(@output, " bool putResult = false;\n");
+ push(@output, " if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
+ push(@output, " return putResult;\n");
}
- if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
- push(@getOwnPropertySlotImpl, " if (thisObject->getOwnPropertySlotDelegate(exec, propertyName, slot))\n");
- push(@getOwnPropertySlotImpl, " return true;\n");
- }
+ push(@output, " return Base::put(thisObject, state, propertyName, value, slot);\n");
+ push(@output, "}\n\n");
+
+ return @output;
+}
+
+sub GeneratePutByIndex
+{
+ my ($interface, $className, $indexedSetterFunction, $namedSetterFunction) = @_;
+
+ assert("Named setters are not supported.") if $namedSetterFunction;
+
+ my @output = ();
- if ($hasAttributes) {
- if ($inlined) {
- die "Cannot inline if NoStaticTables is set." if ($interface->extendedAttributes->{"JSNoStaticTables"});
- push(@getOwnPropertySlotImpl, " return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, *info()->staticPropHashTable, thisObject, propertyName, slot);\n");
+ push(@output, "bool ${className}::putByIndex(JSCell* cell, ExecState* state, unsigned index, JSValue value, bool shouldThrow)\n");
+ push(@output, "{\n");
+ push(@output, " auto* thisObject = jsCast<${className}*>(cell);\n");
+ push(@output, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
+
+ if ($indexedSetterFunction || $interface->extendedAttributes->{CustomIndexedSetter}) {
+ if ($interface->extendedAttributes->{CustomIndexedSetter}) {
+ push(@output, " if (LIKELY(index <= MAX_ARRAY_INDEX)) {\n");
+ push(@output, " thisObject->indexSetter(state, index, value);\n");
+ push(@output, " return true;\n");
+ push(@output, " }\n");
} else {
- push(@getOwnPropertySlotImpl, " return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, " . hashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
+ # The second argument of the indexed setter function is the argument being converted.
+ my $argument = @{$indexedSetterFunction->arguments}[1];
+ my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $argument, "value", $indexedSetterFunction->extendedAttributes->{Conditional}, "state", "*state", "thisObject", "", "");
+
+ push(@output, " if (LIKELY(index <= MAX_ARRAY_INDEX)) {\n");
+ push(@output, " auto throwScope = DECLARE_THROW_SCOPE(state->vm());\n");
+ push(@output, " auto nativeValue = ${nativeValue};\n");
+ push(@output, " RETURN_IF_EXCEPTION(throwScope, true);\n") if $mayThrowException;
+
+ my $indexedSetterFunctionName = $indexedSetterFunction->name || "setItem";
+ my $functionString = "${indexedSetterFunctionName}(index, WTFMove(nativeValue))";
+ $functionString = "propagateException(*state, throwScope, ${functionString})" if NeedsExplicitPropagateExceptionCall($indexedSetterFunction);
+
+ push(@output, " ${functionString};\n");
+ push(@output, " return true;\n");
+ push(@output, " }\n");
}
- } else {
- push(@getOwnPropertySlotImpl, " return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");
}
- return @getOwnPropertySlotImpl;
+ if ($interface->extendedAttributes->{CustomNamedSetter}) {
+ push(@output, " Identifier propertyName = Identifier::from(state, index);\n");
+ push(@output, " PutPropertySlot slot(thisObject, shouldThrow);\n");
+ push(@output, " bool putResult = false;\n");
+ push(@output, " if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
+ push(@output, " return putResult;\n");
+ }
+
+ push(@output, " return Base::putByIndex(cell, state, index, value, shouldThrow);\n");
+ push(@output, "}\n\n");
+
+ return @output;
}
sub GenerateHeaderContentHeader
{
my $interface = shift;
- my $className = "JS" . $interface->name;
+ my $className = "JS" . $interface->type->name;
my @headerContentHeader;
- if ($interface->extendedAttributes->{"AppleCopyright"}) {
+ if ($interface->extendedAttributes->{AppleCopyright}) {
@headerContentHeader = split("\r", $beginAppleCopyrightForHeaderFiles);
} else {
@headerContentHeader = split("\r", $headerTemplate);
}
- # - Add header protection
- push(@headerContentHeader, "\n#ifndef $className" . "_h");
- push(@headerContentHeader, "\n#define $className" . "_h\n\n");
+ push(@headerContentHeader, "\n#pragma once\n\n");
my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
@@ -501,10 +729,10 @@ sub GenerateHeaderContentHeader
sub GenerateImplementationContentHeader
{
my $interface = shift;
- my $className = "JS" . $interface->name;
+ my $className = "JS" . $interface->type->name;
my @implContentHeader;
- if ($interface->extendedAttributes->{"AppleCopyright"}) {
+ if ($interface->extendedAttributes->{AppleCopyright}) {
@implContentHeader = split("\r", $beginAppleCopyrightForSourceFiles);
} else {
@implContentHeader = split("\r", $headerTemplate);
@@ -517,54 +745,157 @@ sub GenerateImplementationContentHeader
return @implContentHeader;
}
-my %usesToJSNewlyCreated = (
- "CDATASection" => 1,
- "Element" => 1,
- "Node" => 1,
- "Text" => 1,
- "Touch" => 1,
- "TouchList" => 1
-);
+sub NeedsImplementationClass
+{
+ my ($interface) = @_;
+
+ return 0 if $interface->extendedAttributes->{JSBuiltin};
+ return 1;
+}
+
+sub ShouldGenerateToWrapped
+{
+ my ($hasParent, $interface) = @_;
+
+ return 0 if not NeedsImplementationClass($interface);
+ return 1 if !$hasParent or $interface->extendedAttributes->{JSGenerateToNativeObject};
+ return 1 if $interface->parentType && $interface->parentType->name eq "EventTarget";
+ return 0;
+}
+
+sub ShouldGenerateWrapperOwnerCode
+{
+ my ($hasParent, $interface) = @_;
+
+ return 0 if not NeedsImplementationClass($interface);
+ return 1 if !$hasParent;
+ return 1 if GetGenerateIsReachable($interface);
+ return 1 if GetCustomIsReachable($interface);
+ return 1 if $interface->extendedAttributes->{JSCustomFinalize};
+ return 1 if $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject");
+ return 0;
+}
sub ShouldGenerateToJSDeclaration
{
my ($hasParent, $interface) = @_;
- return 0 if ($interface->extendedAttributes->{"SuppressToJSObject"});
- return 1 if (!$hasParent or $interface->extendedAttributes->{"JSGenerateToJSObject"} or $interface->extendedAttributes->{"CustomToJSObject"});
+
+ return 0 if ($interface->extendedAttributes->{SuppressToJSObject});
+ return 0 if not NeedsImplementationClass($interface);
+ return 0 if $interface->extendedAttributes->{CustomProxyToJSObject};
+ return 1 if (!$hasParent or $interface->extendedAttributes->{JSGenerateToJSObject} or $interface->extendedAttributes->{CustomToJSObject});
+ return 1 if $interface->parentType && $interface->parentType->name eq "EventTarget";
+ return 1 if $interface->extendedAttributes->{Constructor} or $interface->extendedAttributes->{NamedConstructor};
return 0;
}
sub ShouldGenerateToJSImplementation
{
my ($hasParent, $interface) = @_;
- return 0 if ($interface->extendedAttributes->{"SuppressToJSObject"});
- return 1 if ((!$hasParent or $interface->extendedAttributes->{"JSGenerateToJSObject"}) and !$interface->extendedAttributes->{"CustomToJSObject"});
+
+ return 0 if not ShouldGenerateToJSDeclaration($hasParent, $interface);
+ return 1 if not $interface->extendedAttributes->{CustomToJSObject};
return 0;
}
-sub GetAttributeGetterName
+sub GetArgumentExceptionFunction
{
- my ($interfaceName, $className, $attribute) = @_;
- if ($attribute->isStatic) {
- return $codeGenerator->WK_lcfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name);
+ my ($interface, $argument, $argumentIndex, $quotedFunctionName) = @_;
+
+ my $name = $argument->name;
+ my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
+ my $typeName = $argument->type->name;
+
+ if ($codeGenerator->IsCallbackInterface($argument->type) || $codeGenerator->IsCallbackFunction($argument->type)) {
+ # FIXME: We should have specialized messages for callback interfaces vs. callback functions.
+ return "throwArgumentMustBeFunctionError(state, scope, ${argumentIndex}, \"${name}\", \"${visibleInterfaceName}\", ${quotedFunctionName});";
}
- return "js" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
+
+ if ($codeGenerator->IsWrapperType($argument->type) || $codeGenerator->IsTypedArrayType($argument->type)) {
+ return "throwArgumentTypeError(state, scope, ${argumentIndex}, \"${name}\", \"${visibleInterfaceName}\", ${quotedFunctionName}, \"${typeName}\");";
+ }
+
+ return undef;
}
-sub GetAttributeSetterName
+sub GetArgumentExceptionThrower
{
- my ($interfaceName, $className, $attribute) = @_;
- if ($attribute->isStatic) {
- return "set" . $codeGenerator->WK_ucfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name);
+ my ($interface, $argument, $argumentIndex, $quotedFunctionName) = @_;
+
+ my $functionCall = GetArgumentExceptionFunction($interface, $argument, $argumentIndex, $quotedFunctionName);
+ return "[](JSC::ExecState& state, JSC::ThrowScope& scope) { " . $functionCall . " }" if $functionCall;
+}
+
+sub GetAttributeExceptionFunction
+{
+ my ($interface, $attribute) = @_;
+
+ my $name = $attribute->name;
+ my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
+ my $typeName = $attribute->type->name;
+
+ if ($codeGenerator->IsWrapperType($attribute->type) || $codeGenerator->IsTypedArrayType($attribute->type)) {
+ return "throwAttributeTypeError(state, scope, \"${visibleInterfaceName}\", \"${name}\", \"${typeName}\");";
}
- return "setJS" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
+}
+
+sub GetAttributeExceptionThrower
+{
+ my ($interface, $attribute) = @_;
+
+ my $functionCall = GetAttributeExceptionFunction($interface, $attribute);
+ return "[](JSC::ExecState& state, JSC::ThrowScope& scope) { " . $functionCall . " }" if $functionCall;
+
+}
+
+sub PassArgumentExpression
+{
+ my ($name, $context) = @_;
+
+ my $type = $context->type;
+
+ return "${name}.value()" if $codeGenerator->IsEnumType($type);
+ return "WTFMove(${name})" if $type->isNullable;
+
+ if ($codeGenerator->IsTypedArrayType($type)) {
+ return "*${name}" if $type->name eq "ArrayBuffer";
+ return "${name}.releaseNonNull()";
+ }
+
+ return "${name}.releaseNonNull()" if $codeGenerator->IsCallbackInterface($type) || $codeGenerator->IsCallbackFunction($type);
+ return "*${name}" if $codeGenerator->IsWrapperType($type);
+ return "WTFMove(${name})";
+}
+
+sub GetAttributeGetterName
+{
+ my ($interface, $className, $attribute) = @_;
+
+ return $codeGenerator->WK_lcfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->name) if $attribute->isStatic;
+ return GetJSBuiltinFunctionName($className, $attribute) if IsJSBuiltin($interface, $attribute);
+ return "js" . $interface->type->name . $codeGenerator->WK_ucfirst($attribute->name) . ($codeGenerator->IsConstructorType($attribute->type) ? "Constructor" : "");
+}
+
+sub GetAttributeSetterName
+{
+ my ($interface, $className, $attribute) = @_;
+
+ return "set" . $codeGenerator->WK_ucfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->name) if $attribute->isStatic;
+ return "set" . $codeGenerator->WK_ucfirst(GetJSBuiltinFunctionName($className, $attribute)) if IsJSBuiltin($interface, $attribute);
+ return "setJS" . $interface->type->name . $codeGenerator->WK_ucfirst($attribute->name) . ($codeGenerator->IsConstructorType($attribute->type) ? "Constructor" : "");
}
sub GetFunctionName
{
- my ($className, $function) = @_;
- my $kind = $function->isStatic ? "Constructor" : "Prototype";
- return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($function->signature->name);
+ my ($interface, $className, $function) = @_;
+
+ return GetJSBuiltinFunctionName($className, $function) if IsJSBuiltin($interface, $function);
+
+ my $functionName = $function->name;
+ $functionName = "SymbolIterator" if $functionName eq "[Symbol.Iterator]";
+
+ my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
+ return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($functionName);
}
sub GetSpecialAccessorFunctionForType
@@ -575,10 +906,10 @@ sub GetSpecialAccessorFunctionForType
my $numberOfParameters = shift;
foreach my $function (@{$interface->functions}, @{$interface->anonymousFunctions}) {
- my $specials = $function->signature->specials;
+ my $specials = $function->specials;
my $specialExists = grep { $_ eq $special } @$specials;
- my $parameters = $function->parameters;
- if ($specialExists and scalar(@$parameters) == $numberOfParameters and $parameters->[0]->type eq $firstParameterType) {
+ my $arguments = $function->arguments;
+ if ($specialExists and scalar(@$arguments) == $numberOfParameters and $arguments->[0]->type->name eq $firstParameterType) {
return $function;
}
}
@@ -586,76 +917,787 @@ sub GetSpecialAccessorFunctionForType
return 0;
}
+sub HasComplexGetOwnProperty
+{
+ my $interface = shift;
+ return $interface->extendedAttributes->{CheckSecurity}
+ || IsDOMGlobalObject($interface)
+ || InstanceOverridesGetOwnPropertySlot($interface);
+}
+
+sub IsGlobalOrPrimaryGlobalInterface
+{
+ my $interface = shift;
+
+ return $interface->extendedAttributes->{Global} || $interface->extendedAttributes->{PrimaryGlobal};
+}
+
+sub InterfaceRequiresAttributesOnInstance
+{
+ my $interface = shift;
+ my $interfaceName = $interface->type->name;
+
+ # FIXME: All these return 1 if ... should ideally be removed.
+ # Some of them are unavoidable due to DOM weirdness, in which case we should
+ # add an IDL attribute for them.
+
+ # FIXME: We should be able to drop this once <rdar://problem/24466097> is fixed.
+ return 1 if $interface->isException;
+
+ return 1 if IsGlobalOrPrimaryGlobalInterface($interface);
+
+ return 0;
+}
+
+sub AttributeShouldBeOnInstance
+{
+ my $interface = shift;
+ my $attribute = shift;
+
+ return 1 if InterfaceRequiresAttributesOnInstance($interface);
+ return 1 if $codeGenerator->IsConstructorType($attribute->type);
+
+ # [Unforgeable] attributes should be on the instance.
+ # https://heycam.github.io/webidl/#Unforgeable
+ return 1 if IsUnforgeable($interface, $attribute);
+
+ if ($interface->extendedAttributes->{CheckSecurity}) {
+ return 0 if $attribute->extendedAttributes->{DoNotCheckSecurity};
+ return 0 if $attribute->extendedAttributes->{DoNotCheckSecurityOnGetter};
+ return 1;
+ }
+
+ return 0;
+}
+
+sub NeedsRuntimeCheck
+{
+ my $interface = shift;
+ return $interface->extendedAttributes->{EnabledAtRuntime}
+ || $interface->extendedAttributes->{EnabledForWorld};
+}
+
+# https://heycam.github.io/webidl/#es-operations
+sub OperationShouldBeOnInstance
+{
+ my $interface = shift;
+ my $function = shift;
+
+ return 1 if IsGlobalOrPrimaryGlobalInterface($interface);
+
+ # FIXME: The bindings generator does not support putting runtime-enabled operations on the instance yet (except for global objects).
+ return 0 if NeedsRuntimeCheck($function);
+
+ # [Unforgeable] operations should be on the instance. https://heycam.github.io/webidl/#Unforgeable
+ return 1 if IsUnforgeable($interface, $function);
+
+ return 0;
+}
+
+sub GetJSCAttributesForAttribute
+{
+ my $interface = shift;
+ my $attribute = shift;
+
+ my @specials = ();
+ push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute);
+
+ # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable.
+ my $isGlobalConstructor = $codeGenerator->IsConstructorType($attribute->type);
+ push(@specials, "DontEnum") if ($attribute->extendedAttributes->{NotEnumerable} || $isGlobalConstructor);
+ push(@specials, "ReadOnly") if IsReadonly($attribute);
+ push(@specials, "CustomAccessor") unless $isGlobalConstructor or IsJSBuiltin($interface, $attribute);
+ push(@specials, "DOMJITAttribute") if $attribute->extendedAttributes->{"DOMJIT"};
+ push(@specials, "Accessor | Builtin") if IsJSBuiltin($interface, $attribute);
+ return (@specials > 0) ? join(" | ", @specials) : "0";
+}
+
sub GetIndexedGetterFunction
{
my $interface = shift;
return GetSpecialAccessorFunctionForType($interface, "getter", "unsigned long", 1);
}
+sub GetIndexedSetterFunction
+{
+ my $interface = shift;
+ return GetSpecialAccessorFunctionForType($interface, "setter", "unsigned long", 2);
+}
+
sub GetNamedGetterFunction
{
my $interface = shift;
return GetSpecialAccessorFunctionForType($interface, "getter", "DOMString", 1);
}
-sub InstanceOverridesGetOwnPropertySlot
+sub GetNamedSetterFunction
{
my $interface = shift;
- my $numAttributes = @{$interface->attributes};
+ return GetSpecialAccessorFunctionForType($interface, "setter", "DOMString", 2);
+}
- my $namedGetterFunction = GetNamedGetterFunction($interface);
- my $indexedGetterFunction = GetIndexedGetterFunction($interface);
- my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
+sub GetNamedDeleterFunction
+{
+ my $interface = shift;
+ return GetSpecialAccessorFunctionForType($interface, "deleter", "DOMString", 1);
+}
- my $hasImpureNamedGetter = $namedGetterFunction
- || $interface->extendedAttributes->{"CustomNamedGetter"}
- || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"};
+sub InstanceFunctionCount
+{
+ my $interface = shift;
+ my $count = 0;
- my $hasComplexGetter = $indexedGetterFunction
- || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
- || $hasImpureNamedGetter;
+ foreach my $function (@{$interface->functions}) {
+ $count++ if OperationShouldBeOnInstance($interface, $function);
+ }
+
+ return $count;
+}
+
+sub PrototypeFunctionCount
+{
+ my $interface = shift;
+ my $count = 0;
+
+ foreach my $function (@{$interface->functions}) {
+ $count++ if !$function->isStatic && !OperationShouldBeOnInstance($interface, $function);
+ }
- return $numAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"} || $hasComplexGetter;
+ $count += scalar @{$interface->iterable->functions} if $interface->iterable;
+ $count += scalar @{$interface->serializable->functions} if $interface->serializable;
+
+ return $count;
+}
+sub InstancePropertyCount
+{
+ my $interface = shift;
+ my $count = 0;
+ foreach my $attribute (@{$interface->attributes}) {
+ $count++ if AttributeShouldBeOnInstance($interface, $attribute);
+ }
+ $count += InstanceFunctionCount($interface);
+ return $count;
+}
+
+sub PrototypePropertyCount
+{
+ my $interface = shift;
+ my $count = 0;
+ foreach my $attribute (@{$interface->attributes}) {
+ $count++ if !AttributeShouldBeOnInstance($interface, $attribute);
+ }
+ $count += PrototypeFunctionCount($interface);
+ $count++ if NeedsConstructorProperty($interface);
+ return $count;
+}
+
+sub InstanceOverridesGetOwnPropertySlot
+{
+ my $interface = shift;
+ return $interface->extendedAttributes->{CustomGetOwnPropertySlot}
+ || $interface->extendedAttributes->{CustomNamedGetter}
+ || $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}
+ || GetIndexedGetterFunction($interface)
+ || GetNamedGetterFunction($interface);
+}
+
+sub InstanceOverridesPut
+{
+ my $interface = shift;
+ return $interface->extendedAttributes->{CustomNamedSetter}
+ || $interface->extendedAttributes->{CustomIndexedSetter}
+ || GetIndexedSetterFunction($interface)
+ || GetNamedSetterFunction($interface);
}
-sub PrototypeOverridesGetOwnPropertySlot
+sub PrototypeHasStaticPropertyTable
{
my $interface = shift;
my $numConstants = @{$interface->constants};
- my $numFunctions = @{$interface->functions};
- return $numFunctions > 0 || $numConstants > 0;
+ return $numConstants > 0 || PrototypePropertyCount($interface) > 0;
}
sub InstanceOverridesPutImplementation
{
my $interface = shift;
- return $interface->extendedAttributes->{"CustomNamedSetter"}
- || $interface->extendedAttributes->{"CustomIndexedSetter"};
+ return $interface->extendedAttributes->{CustomNamedSetter}
+ || $interface->extendedAttributes->{CustomIndexedSetter};
}
sub InstanceOverridesPutDeclaration
{
my $interface = shift;
- return $interface->extendedAttributes->{"CustomPutFunction"}
- || $interface->extendedAttributes->{"CustomNamedSetter"}
- || $interface->extendedAttributes->{"CustomIndexedSetter"};
+ return $interface->extendedAttributes->{CustomPutFunction}
+ || $interface->extendedAttributes->{CustomNamedSetter}
+ || $interface->extendedAttributes->{CustomIndexedSetter};
}
-sub GenerateHeader
+sub InstanceNeedsVisitChildren
+{
+ my $interface = shift;
+ return $interface->extendedAttributes->{JSCustomMarkFunction}
+ || $codeGenerator->InheritsInterface($interface, "EventTarget")
+ || $interface->type->name eq "EventTarget"
+ || $interface->extendedAttributes->{ReportExtraMemoryCost}
+ || IsJSBuiltinConstructor($interface)
+}
+
+sub InstanceNeedsEstimatedSize
+{
+ my $interface = shift;
+ return $interface->extendedAttributes->{ReportExtraMemoryCost};
+}
+
+sub GetImplClassName
{
- my $object = shift;
my $interface = shift;
- my $interfaceName = $interface->name;
+ return $interface->type->name;
+}
+
+sub IsClassNameWordBoundary
+{
+ my ($name, $i) = @_;
+
+ # Interpret negative numbers as distance from end of string, just as the substr function does.
+ $i += length($name) if $i < 0;
+
+ return 0 if $i < 0;
+ return 1 if $i == 0;
+ return 1 if $i == length($name);
+ return 0 if $i > length($name);
+
+ my $checkString = substr($name, $i - 1);
+ return $checkString =~ /^[^A-Z][A-Z]/ || $checkString =~ /^[A-Z][A-Z][^A-Z]/;
+}
+
+sub IsPrefixRemovable
+{
+ my ($class, $name, $i) = @_;
+
+ return IsClassNameWordBoundary($name, $i)
+ && (IsClassNameWordBoundary($class, $i) && substr($class, 0, $i) eq substr($name, 0, $i)
+ || IsClassNameWordBoundary($class, -$i) && substr($class, -$i) eq substr($name, 0, $i));
+}
+
+sub GetNestedClassName
+{
+ my ($interface, $name) = @_;
+
+ my $class = GetImplClassName($interface);
+ my $member = $codeGenerator->WK_ucfirst($name);
+
+ # Since the enumeration name will be nested in the class name's namespace, remove any words
+ # that happen to match the start or end of the class name. If an enumeration is named TrackType or
+ # TextTrackType, and the class is named TextTrack, then we will get a name like TextTrack::Type.
+ my $memberLength = length($member);
+ my $longestPrefixLength = 0;
+ if ($member =~ /^[A-Z]./) {
+ for (my $i = 2; $i < $memberLength - 1; $i++) {
+ $longestPrefixLength = $i if IsPrefixRemovable($class, $member, $i);
+ }
+ }
+ $member = substr($member, $longestPrefixLength);
+
+ return "${class}::$member";
+}
+
+sub GetEnumerationClassName
+{
+ my ($type, $interface) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
+
+ if ($codeGenerator->HasEnumImplementationNameOverride($type)) {
+ return $codeGenerator->GetEnumImplementationNameOverride($type);
+ }
+
+ my $name = $type->name;
+
+ return $name if $codeGenerator->IsExternalEnumType($type);
+ return $name unless defined($interface);
+
+ return GetNestedClassName($interface, $name);
+}
+
+sub GetEnumerationValueName
+{
+ my ($name) = @_;
+
+ return "EmptyString" if $name eq "";
+ $name = join("", map { $codeGenerator->WK_ucfirst($_) } split("-", $name));
+ $name = "_$name" if $name =~ /^\d/;
+ return $name;
+}
+
+sub GenerateEnumerationHeader
+{
+ my ($object, $enumeration, $className) = @_;
+
+ # - Add default header template and header protection.
+ push(@headerContentHeader, GenerateHeaderContentHeader($enumeration));
+
+ $headerIncludes{"$className.h"} = 1;
+ $headerIncludes{"JSDOMConvert.h"} = 1;
+
+ push(@headerContent, "\nnamespace WebCore {\n\n");
+ push(@headerContent, GenerateEnumerationHeaderContent($enumeration, $className));
+ push(@headerContent, "} // namespace WebCore\n");
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
+ push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+}
+
+sub GenerateEnumerationImplementation
+{
+ my ($object, $enumeration, $className) = @_;
+
+ # - Add default header template
+ push(@implContentHeader, GenerateImplementationContentHeader($enumeration));
+
+ # FIXME: A little ugly to have this be a side effect instead of a return value.
+ AddToImplIncludes("<runtime/JSString.h>");
+ AddToImplIncludes("JSDOMConvert.h");
+
+ push(@implContent, "\nusing namespace JSC;\n\n");
+ push(@implContent, "namespace WebCore {\n\n");
+ push(@implContent, GenerateEnumerationImplementationContent($enumeration, $className));
+ push(@implContent, "} // namespace WebCore\n");
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
+ push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+}
+
+sub GenerateEnumerationImplementationContent
+{
+ my ($enumeration, $className, $interface, $conditionalString) = @_;
+
+ my $result = "";
+ $result .= "#if ${conditionalString}\n\n" if $conditionalString;
+
+ # FIXME: Change to take VM& instead of ExecState*.
+ $result .= "template<> JSString* convertEnumerationToJS(ExecState& state, $className enumerationValue)\n";
+ $result .= "{\n";
+ # FIXME: Might be nice to make this global be "const", but NeverDestroyed does not currently support that.
+ # FIXME: Might be nice to make the entire array be NeverDestroyed instead of each value, but not sure what the syntax for that is.
+ AddToImplIncludes("<wtf/NeverDestroyed.h>");
+ $result .= " static NeverDestroyed<const String> values[] = {\n";
+ foreach my $value (@{$enumeration->values}) {
+ if ($value eq "") {
+ $result .= " emptyString(),\n";
+ } else {
+ $result .= " ASCIILiteral(\"$value\"),\n";
+ }
+ }
+ $result .= " };\n";
+ my $index = 0;
+ foreach my $value (@{$enumeration->values}) {
+ my $enumerationValueName = GetEnumerationValueName($value);
+ $result .= " static_assert(static_cast<size_t>(${className}::$enumerationValueName) == $index, \"${className}::$enumerationValueName is not $index as expected\");\n";
+ $index++;
+ }
+ $result .= " ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values));\n";
+ $result .= " return jsStringWithCache(&state, values[static_cast<size_t>(enumerationValue)]);\n";
+ $result .= "}\n\n";
+
+ # FIXME: Change to take VM& instead of ExecState&.
+ # FIXME: Consider using toStringOrNull to make exception checking faster.
+ # FIXME: Consider finding a more efficient way to match against all the strings quickly.
+ $result .= "template<> std::optional<$className> parseEnumeration<$className>(ExecState& state, JSValue value)\n";
+ $result .= "{\n";
+ $result .= " auto stringValue = value.toWTFString(&state);\n";
+ foreach my $value (@{$enumeration->values}) {
+ my $enumerationValueName = GetEnumerationValueName($value);
+ if ($value eq "") {
+ $result .= " if (stringValue.isEmpty())\n";
+ } else {
+ $result .= " if (stringValue == \"$value\")\n";
+ }
+ $result .= " return ${className}::${enumerationValueName};\n";
+ }
+ $result .= " return std::nullopt;\n";
+ $result .= "}\n\n";
+
+ $result .= "template<> $className convertEnumeration<$className>(ExecState& state, JSValue value)\n";
+ $result .= "{\n";
+ $result .= " VM& vm = state.vm();\n";
+ $result .= " auto throwScope = DECLARE_THROW_SCOPE(vm);\n";
+ $result .= " auto result = parseEnumeration<$className>(state, value);\n";
+ $result .= " if (UNLIKELY(!result)) {\n";
+ $result .= " throwTypeError(&state, throwScope);\n";
+ $result .= " return { };\n";
+ $result .= " }\n";
+ $result .= " return result.value();\n";
+ $result .= "}\n\n";
+
+ $result .= "template<> const char* expectedEnumerationValues<$className>()\n";
+ $result .= "{\n";
+ $result .= " return \"\\\"" . join ("\\\", \\\"", @{$enumeration->values}) . "\\\"\";\n";
+ $result .= "}\n\n";
+
+ $result .= "#endif\n\n" if $conditionalString;
+
+ return $result;
+}
+
+sub GenerateEnumerationsImplementationContent
+{
+ my ($interface, $enumerations) = @_;
+
+ return "" unless @$enumerations;
+
+ # FIXME: A little ugly to have this be a side effect instead of a return value.
+ AddToImplIncludes("<runtime/JSString.h>");
+ AddToImplIncludes("JSDOMConvert.h");
+
+ my $result = "";
+ foreach my $enumeration (@$enumerations) {
+ my $className = GetEnumerationClassName($enumeration->type, $interface);
+ my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
+ $result .= GenerateEnumerationImplementationContent($enumeration, $className, $interface, $conditionalString);
+ }
+ return $result;
+}
+
+sub GenerateEnumerationHeaderContent
+{
+ my ($enumeration, $className, $conditionalString) = @_;
+
+ my $result = "";
+ $result .= "#if ${conditionalString}\n\n" if $conditionalString;
+
+ my $exportMacro = GetExportMacroForJSClass($enumeration);
+
+ $result .= "template<> ${exportMacro}JSC::JSString* convertEnumerationToJS(JSC::ExecState&, $className);\n\n";
+ $result .= "template<> ${exportMacro}std::optional<$className> parseEnumeration<$className>(JSC::ExecState&, JSC::JSValue);\n";
+ $result .= "template<> ${exportMacro}$className convertEnumeration<$className>(JSC::ExecState&, JSC::JSValue);\n";
+ $result .= "template<> ${exportMacro}const char* expectedEnumerationValues<$className>();\n\n";
+ $result .= "#endif\n\n" if $conditionalString;
+
+ return $result;
+}
+
+sub GenerateEnumerationsHeaderContent
+{
+ my ($interface, $enumerations) = @_;
+
+ return "" unless @$enumerations;
+
+ # FIXME: Could optimize this to only generate the parts of each enumeration that are actually
+ # used, which would require iterating over everything in the interface.
+
+ $headerIncludes{"JSDOMConvert.h"} = 1;
+
+ my $result = "";
+ foreach my $enumeration (@$enumerations) {
+ my $className = GetEnumerationClassName($enumeration->type, $interface);
+ my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
+ $result .= GenerateEnumerationHeaderContent($enumeration, $className, $conditionalString);
+ }
+ return $result;
+}
+
+sub GetDictionaryClassName
+{
+ my ($type, $interface) = @_;
+
+ if ($codeGenerator->HasDictionaryImplementationNameOverride($type)) {
+ return $codeGenerator->GetDictionaryImplementationNameOverride($type);
+ }
+
+ my $name = $type->name;
+ return $name if $codeGenerator->IsExternalDictionaryType($type);
+ return $name unless defined($interface);
+ return GetNestedClassName($interface, $name);
+}
+
+sub GenerateDefaultValue
+{
+ my ($typeScope, $context, $type, $defaultValue) = @_;
+
+ if ($codeGenerator->IsStringType($type)) {
+ my $useAtomicString = $context->extendedAttributes->{AtomicString};
+ if ($defaultValue eq "null") {
+ return $useAtomicString ? "nullAtom" : "String()";
+ } elsif ($defaultValue eq "\"\"") {
+ return $useAtomicString ? "emptyAtom" : "emptyString()";
+ } else {
+ return $useAtomicString ? "AtomicString(${defaultValue}, AtomicString::ConstructFromLiteral)" : "ASCIILiteral(${defaultValue})";
+ }
+ }
+
+ if ($codeGenerator->IsEnumType($type)) {
+ # FIXME: Would be nice to report an error if the value does not have quote marks around it.
+ # FIXME: Would be nice to report an error if the value is not one of the enumeration values.
+ my $className = GetEnumerationClassName($type, $typeScope);
+ my $enumerationValueName = GetEnumerationValueName(substr($defaultValue, 1, -1));
+ return $className . "::" . $enumerationValueName;
+ }
+ if ($defaultValue eq "null") {
+ if ($type->isUnion) {
+ return "std::nullopt" if $type->isNullable;
+
+ my $IDLType = GetIDLType($typeScope, $type);
+ return "convert<${IDLType}>(state, jsNull());";
+ }
+
+ return "jsNull()" if $type->name eq "any";
+ return "nullptr" if $codeGenerator->IsWrapperType($type) || $codeGenerator->IsTypedArrayType($type);
+ return "String()" if $codeGenerator->IsStringType($type);
+ return "std::nullopt";
+ }
+
+ if ($defaultValue eq "[]") {
+ my $IDLType = GetIDLType($typeScope, $type);
+ return "Converter<${IDLType}>::ReturnType{ }" if $codeGenerator->IsSequenceOrFrozenArrayType($type);
+
+ my $nativeType = GetNativeType($typeScope, $type);
+ return "$nativeType()"
+ }
+
+ return "jsUndefined()" if $defaultValue eq "undefined";
+ return "PNaN" if $defaultValue eq "NaN";
+
+ return $defaultValue;
+}
+
+sub GenerateDictionaryHeaderContent
+{
+ my ($dictionary, $className, $conditionalString) = @_;
+
+ my $result = "";
+ $result .= "#if ${conditionalString}\n\n" if $conditionalString;
+ $result .= "template<> ${className} convertDictionary<$className>(JSC::ExecState&, JSC::JSValue);\n\n";
+
+ if ($dictionary->extendedAttributes->{JSGenerateToJSObject}) {
+ $result .= "JSC::JSObject* convertDictionaryToJS(JSC::ExecState&, JSDOMGlobalObject&, const ${className}&);\n\n";
+ }
+
+ $result .= "#endif\n\n" if $conditionalString;
+ return $result;
+}
+
+sub GenerateDictionariesHeaderContent
+{
+ my ($typeScope, $allDictionaries) = @_;
+
+ return "" unless @$allDictionaries;
+
+ $headerIncludes{"JSDOMConvert.h"} = 1;
+
+ my $result = "";
+ foreach my $dictionary (@$allDictionaries) {
+ $headerIncludes{$typeScope->type->name . ".h"} = 1 if $typeScope;
+ my $className = GetDictionaryClassName($dictionary->type, $typeScope);
+ my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
+ $result .= GenerateDictionaryHeaderContent($dictionary, $className, $conditionalString);
+ }
+ return $result;
+}
+
+sub GenerateDictionaryImplementationContent
+{
+ my ($dictionary, $className, $interface, $conditionalString) = @_;
+
+ my $result = "";
+
+ my $name = $dictionary->type->name;
+ my $typeScope = $interface || $dictionary;
+
+ $result .= "#if ${conditionalString}\n\n" if $conditionalString;
+
+ # FIXME: A little ugly to have this be a side effect instead of a return value.
+ AddToImplIncludes("JSDOMConvert.h");
+
+ # https://heycam.github.io/webidl/#es-dictionary
+ $result .= "template<> $className convertDictionary<$className>(ExecState& state, JSValue value)\n";
+ $result .= "{\n";
+ $result .= " VM& vm = state.vm();\n";
+ $result .= " auto throwScope = DECLARE_THROW_SCOPE(vm);\n";
+ $result .= " bool isNullOrUndefined = value.isUndefinedOrNull();\n";
+ $result .= " auto* object = isNullOrUndefined ? nullptr : value.getObject();\n";
+
+ # 1. If Type(V) is not Undefined, Null or Object, then throw a TypeError.
+ $result .= " if (UNLIKELY(!isNullOrUndefined && !object)) {\n";
+ $result .= " throwTypeError(&state, throwScope);\n";
+ $result .= " return { };\n";
+ $result .= " }\n";
+
+ # 2. If V is a native RegExp object, then throw a TypeError.
+ # FIXME: This RegExp special handling is likely to go away in the specification.
+ $result .= " if (UNLIKELY(object && object->type() == RegExpObjectType)) {\n";
+ $result .= " throwTypeError(&state, throwScope);\n";
+ $result .= " return { };\n";
+ $result .= " }\n";
+
+ # 3. Let dict be an empty dictionary value of type D; every dictionary member is initially considered to be not present.
+
+ # 4. Let dictionaries be a list consisting of D and all of D’s inherited dictionaries, in order from least to most derived.
+ my @dictionaries;
+ push(@dictionaries, $dictionary);
+ my $parentType = $dictionary->parentType;
+ while (defined($parentType)) {
+ my $parentDictionary = $codeGenerator->GetDictionaryByType($parentType);
+ assert("Unable to find definition for dictionary named '" . $parentType->name . "'!") unless defined($parentDictionary);
+ unshift(@dictionaries, $parentDictionary);
+ $parentType = $parentDictionary->parentType;
+ }
+
+ my $arguments = "";
+ my $comma = "";
+
+ $result .= " $className result;\n";
+
+ # 5. For each dictionary dictionary in dictionaries, in order:
+ foreach my $dictionary (@dictionaries) {
+ # For each dictionary member member declared on dictionary, in lexicographical order:
+ my @sortedMembers = sort { $a->name cmp $b->name } @{$dictionary->members};
+ foreach my $member (@sortedMembers) {
+ $member->default("undefined") if $member->type->name eq "any" and !defined($member->default); # Use undefined as default value for member of type 'any' unless specified otherwise.
+
+ my $type = $member->type;
+ AddToImplIncludesForIDLType($type);
+
+ # 5.1. Let key be the identifier of member.
+ my $key = $member->name;
+
+ # 5.2. Let value be an ECMAScript value, depending on Type(V):
+ $result .= " JSValue ${key}Value = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, \"${key}\"));\n";
+
+ my $IDLType = GetIDLType($typeScope, $type);
+
+ # 5.3. If value is not undefined, then:
+ $result .= " if (!${key}Value.isUndefined()) {\n";
+ $result .= " result.$key = convert<${IDLType}>(state, ${key}Value);\n";
+ $result .= " RETURN_IF_EXCEPTION(throwScope, { });\n";
+
+ # Value is undefined.
+ # 5.4. Otherwise, if value is undefined but the dictionary member has a default value, then:
+ if (!$member->isRequired && defined $member->default) {
+ $result .= " } else\n";
+ $result .= " result.$key = " . GenerateDefaultValue($typeScope, $member, $member->type, $member->default) . ";\n";
+ } elsif ($member->isRequired) {
+ # 5.5. Otherwise, if value is undefined and the dictionary member is a required dictionary member, then throw a TypeError.
+ $result .= " } else {\n";
+ $result .= " throwRequiredMemberTypeError(state, throwScope, \"". $member->name ."\", \"$name\", \"". $type->name ."\");\n";
+ $result .= " return { };\n";
+ $result .= " }\n";
+ } else {
+ $result .= " }\n";
+ }
+ }
+ }
+
+ $result .= " return result;\n";
+ $result .= "}\n\n";
+
+ if ($dictionary->extendedAttributes->{JSGenerateToJSObject}) {
+ $result .= "JSC::JSObject* convertDictionaryToJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const ${className}& dictionary)\n";
+ $result .= "{\n";
+ $result .= " auto& vm = state.vm();\n\n";
+
+ # 1. Let O be ! ObjectCreate(%ObjectPrototype%).
+ $result .= " auto result = constructEmptyObject(&state);\n\n";
+
+ # 2. Let dictionaries be a list consisting of D and all of D’s inherited dictionaries,
+ # in order from least to most derived.
+ # NOTE: This was done above.
+
+ # 3. For each dictionary dictionary in dictionaries, in order:
+ foreach my $dictionary (@dictionaries) {
+ # 3.1. For each dictionary member member declared on dictionary, in lexicographical order:
+ my @sortedMembers = sort { $a->name cmp $b->name } @{$dictionary->members};
+ foreach my $member (@sortedMembers) {
+ my $key = $member->name;
+ my $IDLType = GetIDLType($typeScope, $member->type);
+
+ # 1. Let key be the identifier of member.
+ # 2. If the dictionary member named key is present in V, then:
+ # 1. Let idlValue be the value of member on V.
+ # 2. Let value be the result of converting idlValue to an ECMAScript value.
+ # 3. Perform ! CreateDataProperty(O, key, value).
+ if (!$member->isRequired && not defined $member->default) {
+ $result .= " if (!${IDLType}::isNullValue(dictionary.${key})) {\n";
+ $result .= " auto ${key}Value = toJS<$IDLType>(state, globalObject, ${IDLType}::extractValueFromNullable(dictionary.${key}));\n";
+ $result .= " result->putDirect(vm, JSC::Identifier::fromString(&vm, \"${key}\"), ${key}Value);\n";
+ $result .= " }\n";
+ } else {
+ $result .= " auto ${key}Value = toJS<$IDLType>(state, globalObject, dictionary.${key});\n";
+ $result .= " result->putDirect(vm, JSC::Identifier::fromString(&vm, \"${key}\"), ${key}Value);\n";
+ }
+ }
+ }
+
+ $result .= " return result;\n";
+ $result .= "}\n\n";
+ }
+
+ $result .= "#endif\n\n" if $conditionalString;
+
+ return $result;
+}
+
+sub GenerateDictionariesImplementationContent
+{
+ my ($typeScope, $allDictionaries) = @_;
+
+ my $result = "";
+ foreach my $dictionary (@$allDictionaries) {
+ my $className = GetDictionaryClassName($dictionary->type, $typeScope);
+ my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
+ $result .= GenerateDictionaryImplementationContent($dictionary, $className, $typeScope, $conditionalString);
+ }
+ return $result;
+}
+
+sub GetJSTypeForNode
+{
+ my ($interface) = @_;
+
+ if ($codeGenerator->InheritsInterface($interface, "Document")) {
+ return "JSDocumentWrapperType";
+ }
+ if ($codeGenerator->InheritsInterface($interface, "DocumentFragment")) {
+ return "JSDocumentFragmentNodeType";
+ }
+ if ($codeGenerator->InheritsInterface($interface, "DocumentType")) {
+ return "JSDocumentTypeNodeType";
+ }
+ if ($codeGenerator->InheritsInterface($interface, "ProcessingInstruction")) {
+ return "JSProcessingInstructionNodeType";
+ }
+ if ($codeGenerator->InheritsInterface($interface, "CDATASection")) {
+ return "JSCDATASectionNodeType";
+ }
+ if ($codeGenerator->InheritsInterface($interface, "Attr")) {
+ return "JSAttrNodeType";
+ }
+ if ($codeGenerator->InheritsInterface($interface, "Comment")) {
+ return "JSCommentNodeType";
+ }
+ if ($codeGenerator->InheritsInterface($interface, "Text")) {
+ return "JSTextNodeType";
+ }
+ if ($codeGenerator->InheritsInterface($interface, "Element")) {
+ return "JSElementType";
+ }
+ return "JSNodeType";
+}
+
+sub GenerateHeader
+{
+ my ($object, $interface, $enumerations, $dictionaries) = @_;
+
+ my $interfaceName = $interface->type->name;
my $className = "JS$interfaceName";
my %structureFlags = ();
- my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
- my $hasRealParent = $interface->parent;
+ my $hasLegacyParent = $interface->extendedAttributes->{JSLegacyParent};
+ my $hasRealParent = $interface->parentType;
my $hasParent = $hasLegacyParent || $hasRealParent;
my $parentClassName = GetParentClassName($interface);
- my $needsMarkChildren = $interface->extendedAttributes->{"JSCustomMarkFunction"} || $interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget";
+ my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
# - Add default header template and header protection
push(@headerContentHeader, GenerateHeaderContentHeader($interface));
@@ -663,33 +1705,19 @@ sub GenerateHeader
if ($hasParent) {
$headerIncludes{"$parentClassName.h"} = 1;
} else {
- $headerIncludes{"JSDOMBinding.h"} = 1;
- $headerIncludes{"<runtime/JSGlobalObject.h>"} = 1;
+ $headerIncludes{"JSDOMWrapper.h"} = 1;
if ($interface->isException) {
$headerIncludes{"<runtime/ErrorPrototype.h>"} = 1;
- } else {
- $headerIncludes{"<runtime/ObjectPrototype.h>"} = 1;
}
}
- if ($interface->extendedAttributes->{"CustomCall"}) {
- $headerIncludes{"<runtime/CallData.h>"} = 1;
- }
+ $headerIncludes{"<runtime/CallData.h>"} = 1 if $interface->extendedAttributes->{CustomCall};
- if ($hasParent && $interface->extendedAttributes->{"JSGenerateToNativeObject"}) {
- $headerIncludes{"$interfaceName.h"} = 1;
- }
-
- $headerIncludes{"<runtime/JSObject.h>"} = 1;
- $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
+ $headerIncludes{"$interfaceName.h"} = 1 if $hasParent && $interface->extendedAttributes->{JSGenerateToNativeObject};
- my $implType = $interfaceName;
- my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
- $implType = $svgNativeType if $svgNativeType;
+ $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
- my $svgPropertyOrListPropertyType;
- $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
- $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
+ my $implType = GetImplClassName($interface);
my $numConstants = @{$interface->constants};
my $numAttributes = @{$interface->attributes};
@@ -697,228 +1725,303 @@ sub GenerateHeader
push(@headerContent, "\nnamespace WebCore {\n\n");
- if ($codeGenerator->IsSVGAnimatedType($interfaceName)) {
+ if ($codeGenerator->IsSVGAnimatedType($interface->type)) {
$headerIncludes{"$interfaceName.h"} = 1;
} else {
# Implementation class forward declaration
if (IsDOMGlobalObject($interface)) {
- AddClassForwardIfNeeded($interfaceName) unless $svgPropertyOrListPropertyType;
+ AddClassForwardIfNeeded($interface->type);
}
}
- AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow";
- AddClassForwardIfNeeded("JSDictionary") if $codeGenerator->IsConstructorTemplate($interface, "Event");
+ push(@headerContent, "class JSDOMWindowShell;\n\n") if $interfaceName eq "DOMWindow";
+
+ my $exportMacro = GetExportMacroForJSClass($interface);
# Class declaration
- push(@headerContent, "class $className : public $parentClassName {\n");
+ push(@headerContent, "class $exportMacro$className : public $parentClassName {\n");
# Static create methods
push(@headerContent, "public:\n");
- push(@headerContent, " typedef $parentClassName Base;\n");
+ push(@headerContent, " using Base = $parentClassName;\n");
+ push(@headerContent, " using DOMWrapped = $implType;\n") if $hasRealParent;
+
if ($interfaceName eq "DOMWindow") {
- push(@headerContent, " static $className* create(JSC::VM& vm, JSC::Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* windowShell)\n");
+ push(@headerContent, " static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* windowShell)\n");
push(@headerContent, " {\n");
- push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, impl, windowShell);\n");
+ push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl), windowShell);\n");
push(@headerContent, " ptr->finishCreation(vm, windowShell);\n");
- push(@headerContent, " vm.heap.addFinalizer(ptr, destroy);\n");
push(@headerContent, " return ptr;\n");
push(@headerContent, " }\n\n");
} elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
- push(@headerContent, " static $className* create(JSC::VM& vm, JSC::Structure* structure, PassRefPtr<$implType> impl)\n");
+ push(@headerContent, " static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSC::JSProxy* proxy)\n");
push(@headerContent, " {\n");
- push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, impl);\n");
- push(@headerContent, " ptr->finishCreation(vm);\n");
- push(@headerContent, " vm.heap.addFinalizer(ptr, destroy);\n");
+ push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl));\n");
+ push(@headerContent, " ptr->finishCreation(vm, proxy);\n");
push(@headerContent, " return ptr;\n");
push(@headerContent, " }\n\n");
- } elsif ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
- AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
- push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
+ } elsif ($interface->extendedAttributes->{MasqueradesAsUndefined}) {
+ AddIncludesForImplementationTypeInHeader($implType);
+ push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
push(@headerContent, " {\n");
- push(@headerContent, " globalObject->masqueradesAsUndefinedWatchpoint()->fireAll();\n");
- push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, globalObject, impl);\n");
+ push(@headerContent, " globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(globalObject->vm(), \"Allocated masquerading object\");\n");
+ push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
push(@headerContent, " ptr->finishCreation(globalObject->vm());\n");
push(@headerContent, " return ptr;\n");
push(@headerContent, " }\n\n");
+ } elsif (!NeedsImplementationClass($interface)) {
+ push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject)\n");
+ push(@headerContent, " {\n");
+ push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject);\n");
+ push(@headerContent, " ptr->finishCreation(globalObject->vm());\n");
+ push(@headerContent, " return ptr;\n");
+ push(@headerContent, " }\n\n");
} else {
- AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
- push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
+ AddIncludesForImplementationTypeInHeader($implType);
+ push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
push(@headerContent, " {\n");
- push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, globalObject, impl);\n");
+ push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, *globalObject, WTFMove(impl));\n");
push(@headerContent, " ptr->finishCreation(globalObject->vm());\n");
push(@headerContent, " return ptr;\n");
push(@headerContent, " }\n\n");
}
- if (IsDOMGlobalObject($interface)) {
- push(@headerContent, " static const bool needsDestruction = false;\n\n");
- }
+ push(@headerContent, " static const bool needsDestruction = false;\n\n") if IsDOMGlobalObject($interface);
+
+ $structureFlags{"JSC::HasStaticPropertyTable"} = 1 if InstancePropertyCount($interface) > 0;
# Prototype
- push(@headerContent, " static JSC::JSObject* createPrototype(JSC::VM&, JSC::JSGlobalObject*);\n") unless IsDOMGlobalObject($interface);
+ unless (ShouldUseGlobalObjectPrototype($interface)) {
+ push(@headerContent, " static JSC::JSObject* createPrototype(JSC::VM&, JSC::JSGlobalObject*);\n");
+ push(@headerContent, " static JSC::JSObject* prototype(JSC::VM&, JSC::JSGlobalObject*);\n");
+ }
+
+ # JSValue to implementation type
+ if (ShouldGenerateToWrapped($hasParent, $interface)) {
+ my $nativeType = GetNativeType($interface, $interface->type);
- $headerTrailingIncludes{"${className}Custom.h"} = 1 if $interface->extendedAttributes->{"JSCustomHeader"};
+ # FIXME: Add extended attribute for this.
+ my @toWrappedArguments = ();
+ push(@toWrappedArguments, "JSC::VM&");
+ push(@toWrappedArguments, "JSC::ExecState&") if $interface->type->name eq "XPathNSResolver";
+ push(@toWrappedArguments, "JSC::JSValue");
+
+ my $export = "";
+ $export = "WEBCORE_EXPORT " if $interface->extendedAttributes->{ExportToWrappedFunction};
+ push(@headerContent, " static $export$nativeType toWrapped(" . join(", ", @toWrappedArguments) . ");\n");
+ }
+
+ $headerTrailingIncludes{"${className}Custom.h"} = 1 if $interface->extendedAttributes->{JSCustomHeader};
my $namedGetterFunction = GetNamedGetterFunction($interface);
my $indexedGetterFunction = GetIndexedGetterFunction($interface);
- my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
- my $hasImpureNamedGetter =
- $namedGetterFunction
- || $interface->extendedAttributes->{"CustomNamedGetter"}
- || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"};
+ my $hasNamedGetter = $namedGetterFunction
+ || $interface->extendedAttributes->{CustomNamedGetter};
+
+ my $hasComplexGetter = $indexedGetterFunction
+ || $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}
+ || $interface->extendedAttributes->{CustomGetOwnPropertySlot}
+ || $hasNamedGetter;
- my $hasComplexGetter =
- $indexedGetterFunction
- || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}
- || $hasImpureNamedGetter;
-
my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
- if ($hasImpureNamedGetter) {
- $structureFlags{"JSC::HasImpureGetOwnPropertySlot"} = 1;
- }
- if ($interface->extendedAttributes->{"NewImpurePropertyFiresWatchpoints"}) {
- $structureFlags{"JSC::NewImpurePropertyFiresWatchpoints"} = 1;
+ if ($hasNamedGetter) {
+ if ($interface->extendedAttributes->{OverrideBuiltins}) {
+ $structureFlags{"JSC::GetOwnPropertySlotIsImpure"} = 1;
+ } else {
+ $structureFlags{"JSC::GetOwnPropertySlotIsImpureForPropertyAbsence"} = 1;
+ }
}
+ $structureFlags{"JSC::NewImpurePropertyFiresWatchpoints"} = 1 if $interface->extendedAttributes->{NewImpurePropertyFiresWatchpoints};
+ $structureFlags{"JSC::IsImmutablePrototypeExoticObject"} = 1 if $interface->extendedAttributes->{IsImmutablePrototypeExoticObject};
+ $structureFlags{"JSC::TypeOfShouldCallGetCallData"} = 1 if $interface->extendedAttributes->{CustomCall};
# Getters
if ($hasGetter) {
push(@headerContent, " static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
- push(@headerContent, " static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n") if ($hasComplexGetter);
- push(@headerContent, " bool getOwnPropertySlotDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n") if $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"};
$structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
- $structureFlags{"JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero"} = 1;
+
+ if ($hasComplexGetter) {
+ push(@headerContent, " static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n");
+ $structureFlags{"JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero"} = 1;
+ }
}
my $overridesPut = InstanceOverridesPutDeclaration($interface);
# Getters
if ($overridesPut) {
- push(@headerContent, " static void put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
- push(@headerContent, " static void putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n");
- push(@headerContent, " bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n") if $interface->extendedAttributes->{"CustomNamedSetter"};
+ push(@headerContent, " static bool put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
+ push(@headerContent, " static bool putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n");
}
if (!$hasParent) {
push(@headerContent, " static void destroy(JSC::JSCell*);\n");
- push(@headerContent, " ~${className}();\n");
}
# Class info
if ($interfaceName eq "Node") {
- push(@headerContent, "protected:");
- push(@headerContent, " static WEBKIT_EXPORTDATA const JSC::ClassInfo s_info;\n");
- push(@headerContent, "public:");
- push(@headerContent, " static const JSC::ClassInfo* info() { return &s_info; }\n\n");
+ push(@headerContent, "\n");
+ push(@headerContent, "protected:\n");
+ push(@headerContent, " static const JSC::ClassInfo s_info;\n");
+ push(@headerContent, "public:\n");
+ push(@headerContent, " static constexpr const JSC::ClassInfo* info() { return &s_info; }\n\n");
} else {
+ push(@headerContent, "\n");
push(@headerContent, " DECLARE_INFO;\n\n");
}
+
# Structure ID
- if ($interfaceName eq "DOMWindow") {
- $structureFlags{"JSC::ImplementsHasInstance"} = 1;
- }
+ $structureFlags{"JSC::ImplementsHasInstance | JSC::ImplementsDefaultHasInstance"} = 1 if $interfaceName eq "DOMWindow";
push(@headerContent, " static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
push(@headerContent, " {\n");
if (IsDOMGlobalObject($interface)) {
push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info());\n");
+ } elsif ($codeGenerator->InheritsInterface($interface, "Node")) {
+ my $type = GetJSTypeForNode($interface);
+ push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType($type), StructureFlags), info());\n");
+ } elsif ($codeGenerator->InheritsInterface($interface, "Event")) {
+ push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSEventType), StructureFlags), info());\n");
} else {
push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n");
}
push(@headerContent, " }\n\n");
# Custom pushEventHandlerScope function
- push(@headerContent, " JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{"JSCustomPushEventHandlerScope"};
+ push(@headerContent, " JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{JSCustomPushEventHandlerScope};
# Custom call functions
- push(@headerContent, " static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $interface->extendedAttributes->{"CustomCall"};
+ push(@headerContent, " static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $interface->extendedAttributes->{CustomCall};
# Custom deleteProperty function
- push(@headerContent, " static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
- push(@headerContent, " static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"};
+ push(@headerContent, " static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{CustomDeleteProperty};
+ push(@headerContent, " static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{CustomDeleteProperty};
# Custom getPropertyNames function exists on DOMWindow
if ($interfaceName eq "DOMWindow") {
- push(@headerContent, " static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
+ push(@headerContent, " static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
+ push(@headerContent, " static void getGenericPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
+ push(@headerContent, " static void getStructurePropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
+ push(@headerContent, " static uint32_t getEnumerableLength(JSC::ExecState*, JSC::JSObject*);\n");
$structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
}
# Custom getOwnPropertyNames function
- if ($interface->extendedAttributes->{"CustomEnumerateProperty"} || $indexedGetterFunction) {
- push(@headerContent, " static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
+ if ($interface->extendedAttributes->{CustomEnumerateProperty} || $indexedGetterFunction || $namedGetterFunction) {
+ push(@headerContent, " static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
$structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
}
# Custom defineOwnProperty function
- push(@headerContent, " static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnProperty"};
+ push(@headerContent, " static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{JSCustomDefineOwnProperty};
- # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
- if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
- $structureFlags{"JSC::MasqueradesAsUndefined"} = 1;
- }
+ # Custom getPrototype / setPrototype functions.
+ push (@headerContent, " static JSC::JSValue getPrototype(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{CustomGetPrototype};
+ push (@headerContent, " static bool setPrototype(JSC::JSObject*, JSC::ExecState*, JSC::JSValue, bool shouldThrowIfCantSet);\n") if $interface->extendedAttributes->{CustomSetPrototype};
+
+ # Custom toStringName function.
+ push (@headerContent, " static String toStringName(const JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{CustomToStringName};
+
+ # Custom preventExtensions function.
+ push(@headerContent, " static bool preventExtensions(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{CustomPreventExtensions};
+
+ $structureFlags{"JSC::MasqueradesAsUndefined"} = 1 if $interface->extendedAttributes->{MasqueradesAsUndefined};
# Constructor object getter
- unless ($interface->extendedAttributes->{"NoInterfaceObject"}) {
- push(@headerContent, " static JSC::JSValue getConstructor(JSC::VM&, JSC::JSGlobalObject*);\n");
- push(@headerContent, " static JSC::JSValue getNamedConstructor(JSC::VM&, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{"NamedConstructor"};
+ unless ($interface->extendedAttributes->{NoInterfaceObject}) {
+ push(@headerContent, " static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);\n");
+ push(@headerContent, " static JSC::JSValue getNamedConstructor(JSC::VM&, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{NamedConstructor};
}
+ # Serializer function.
+ push(@headerContent, " static JSC::JSObject* serialize(JSC::ExecState*, JS${interfaceName}* thisObject, JSC::ThrowScope&);\n") if $interface->serializable;
+
my $numCustomFunctions = 0;
my $numCustomAttributes = 0;
+ my $hasForwardDeclaringFunctions = 0;
+ my $hasForwardDeclaringAttributes = 0;
+
+ my $hasDOMJITAttributes = 0;
+
# Attribute and function enums
if ($numAttributes > 0) {
foreach (@{$interface->attributes}) {
my $attribute = $_;
- $numCustomAttributes++ if HasCustomGetter($attribute->signature->extendedAttributes);
- $numCustomAttributes++ if HasCustomSetter($attribute->signature->extendedAttributes);
- if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
- my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
+ $numCustomAttributes++ if HasCustomGetter($attribute->extendedAttributes);
+ $numCustomAttributes++ if HasCustomSetter($attribute->extendedAttributes);
+ if ($attribute->extendedAttributes->{CachedAttribute}) {
+ my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
- push(@headerContent, " JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->signature->name . ";\n");
+ push(@headerContent, " mutable JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->name . ";\n");
$numCachedAttributes++;
- $needsMarkChildren = 1;
+ $needsVisitChildren = 1;
push(@headerContent, "#endif\n") if $conditionalString;
}
+ $hasDOMJITAttributes = 1 if $attribute->extendedAttributes->{"DOMJIT"};
+
+ $hasForwardDeclaringAttributes = 1 if $attribute->extendedAttributes->{ForwardDeclareInHeader};
}
}
# visit function
- if ($needsMarkChildren) {
- push(@headerContent, " static void visitChildren(JSCell*, JSC::SlotVisitor&);\n\n");
- $structureFlags{"JSC::OverridesVisitChildren"} = 1;
+ if ($needsVisitChildren) {
+ push(@headerContent, " static void visitChildren(JSCell*, JSC::SlotVisitor&);\n");
+ push(@headerContent, " void visitAdditionalChildren(JSC::SlotVisitor&);\n") if $interface->extendedAttributes->{JSCustomMarkFunction};
+ push(@headerContent, "\n");
+
+ if ($interface->extendedAttributes->{JSCustomMarkFunction}) {
+ # We assume that the logic in visitAdditionalChildren is highly volatile, and during a
+ # concurrent GC or in between eden GCs something may happen that would lead to this
+ # logic behaving differently. Since this could mark objects or add opaque roots, this
+ # means that after any increment of mutator resumption in a concurrent GC and at least
+ # once during any eden GC we need to re-execute visitAdditionalChildren on any objects
+ # that we had executed it on before. We do this using the DOM's own MarkingConstraint,
+ # which will call visitOutputConstraints on all objects in the DOM's own
+ # outputConstraintSubspace. visitOutputConstraints is the name JSC uses for the method
+ # that the GC calls to ask an object is it would like to mark anything else after the
+ # program resumed since the last call to visitChildren or visitOutputConstraints. Since
+ # this just calls visitAdditionalChildren, you usually don't have to worry about this.
+ push(@headerContent, " static void visitOutputConstraints(JSCell*, JSC::SlotVisitor&);\n");
+ my $subspaceFunc = IsDOMGlobalObject($interface) ? "globalObjectOutputConstraintSubspaceFor" : "outputConstraintSubspaceFor";
+ push(@headerContent, " template<typename> static JSC::Subspace* subspaceFor(JSC::VM& vm) { return $subspaceFunc(vm); }\n");
+ }
+ }
+
+ if (InstanceNeedsEstimatedSize($interface)) {
+ push(@headerContent, " static size_t estimatedSize(JSCell*);\n");
}
if ($numCustomAttributes > 0) {
push(@headerContent, "\n // Custom attributes\n");
foreach my $attribute (@{$interface->attributes}) {
- my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
- if (HasCustomGetter($attribute->signature->extendedAttributes)) {
+ my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
+ if (HasCustomGetter($attribute->extendedAttributes)) {
push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
- my $methodName = $codeGenerator->WK_lcfirst($attribute->signature->name);
- push(@headerContent, " JSC::JSValue " . $methodName . "(JSC::ExecState*) const;\n");
+ my $methodName = $codeGenerator->WK_lcfirst($attribute->name);
+ push(@headerContent, " JSC::JSValue " . $methodName . "(JSC::ExecState&) const;\n");
push(@headerContent, "#endif\n") if $conditionalString;
}
- if (HasCustomSetter($attribute->signature->extendedAttributes) && !IsReadonly($attribute)) {
+ if (HasCustomSetter($attribute->extendedAttributes) && !IsReadonly($attribute)) {
push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
- push(@headerContent, " void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue);\n");
+ push(@headerContent, " void set" . $codeGenerator->WK_ucfirst($attribute->name) . "(JSC::ExecState&, JSC::JSValue);\n");
push(@headerContent, "#endif\n") if $conditionalString;
}
}
}
foreach my $function (@{$interface->functions}) {
- $numCustomFunctions++ if HasCustomMethod($function->signature->extendedAttributes);
+ $numCustomFunctions++ if HasCustomMethod($function->extendedAttributes);
+ $hasForwardDeclaringFunctions = 1 if $function->extendedAttributes->{ForwardDeclareInHeader};
}
if ($numCustomFunctions > 0) {
my $inAppleCopyright = 0;
push(@headerContent, "\n // Custom functions\n");
foreach my $function (@{$interface->functions}) {
- # PLATFORM_IOS
- my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
- if ($needsAppleCopyright) {
+ if ($function->extendedAttributes->{AppleCopyright}) {
if (!$inAppleCopyright) {
push(@headerContent, $beginAppleCopyrightForHeaderFiles);
$inAppleCopyright = 1;
@@ -927,88 +2030,83 @@ sub GenerateHeader
push(@headerContent, $endAppleCopyright);
$inAppleCopyright = 0;
}
- # end PLATFORM_IOS
- next unless HasCustomMethod($function->signature->extendedAttributes);
+ next unless HasCustomMethod($function->extendedAttributes);
next if $function->{overloads} && $function->{overloadIndex} != 1;
- my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
+ my $conditionalString = $codeGenerator->GenerateConditionalString($function);
push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
- my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
- push(@headerContent, " " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState*);\n");
+ my $functionImplementationName = $function->extendedAttributes->{ImplementedAs} || $codeGenerator->WK_lcfirst($function->name);
+ push(@headerContent, " " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState&);\n");
push(@headerContent, "#endif\n") if $conditionalString;
}
push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
}
- if (!$hasParent) {
- push(@headerContent, " $implType& impl() const { return *m_impl; }\n");
- push(@headerContent, " void releaseImpl() { m_impl->deref(); m_impl = 0; }\n\n");
- push(@headerContent, " void releaseImplIfNotNull()\n");
- push(@headerContent, " {\n");
- push(@headerContent, " if (m_impl) {\n");
- push(@headerContent, " m_impl->deref();\n");
- push(@headerContent, " m_impl = 0;\n");
- push(@headerContent, " }\n");
- push(@headerContent, " }\n\n");
- push(@headerContent, "private:\n");
- push(@headerContent, " $implType* m_impl;\n");
- } else {
- push(@headerContent, " $interfaceName& impl() const\n");
- push(@headerContent, " {\n");
- push(@headerContent, " return static_cast<$interfaceName&>(Base::impl());\n");
- push(@headerContent, " }\n");
+ if (NeedsImplementationClass($interface)) {
+ if ($hasParent) {
+ push(@headerContent, " $interfaceName& wrapped() const\n");
+ push(@headerContent, " {\n");
+ push(@headerContent, " return static_cast<$interfaceName&>(Base::wrapped());\n");
+ push(@headerContent, " }\n");
+ }
+ }
+
+ # structure flags
+ if (%structureFlags) {
+ push(@headerContent, "public:\n");
+ push(@headerContent, " static const unsigned StructureFlags = ");
+ foreach my $structureFlag (sort (keys %structureFlags)) {
+ push(@headerContent, $structureFlag . " | ");
+ }
+ push(@headerContent, "Base::StructureFlags;\n");
}
push(@headerContent, "protected:\n");
+
# Constructor
if ($interfaceName eq "DOMWindow") {
- push(@headerContent, " $className(JSC::VM&, JSC::Structure*, PassRefPtr<$implType>, JSDOMWindowShell*);\n");
+ push(@headerContent, " $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&, JSDOMWindowShell*);\n");
+ } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
+ push(@headerContent, " $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&);\n");
+ } elsif (!NeedsImplementationClass($interface)) {
+ push(@headerContent, " $className(JSC::Structure*, JSDOMGlobalObject&);\n\n");
+ } else {
+ push(@headerContent, " $className(JSC::Structure*, JSDOMGlobalObject&, Ref<$implType>&&);\n\n");
+ }
+
+ if ($interfaceName eq "DOMWindow") {
+ push(@headerContent, " void finishCreation(JSC::VM&, JSDOMWindowShell*);\n");
} elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
- push(@headerContent, " $className(JSC::VM&, JSC::Structure*, PassRefPtr<$implType>);\n");
+ push(@headerContent, " void finishCreation(JSC::VM&, JSC::JSProxy*);\n");
} else {
- push(@headerContent, " $className(JSC::Structure*, JSDOMGlobalObject*, PassRefPtr<$implType>);\n");
push(@headerContent, " void finishCreation(JSC::VM&);\n");
}
- # structure flags
- push(@headerContent, " static const unsigned StructureFlags = ");
- foreach my $structureFlag (sort (keys %structureFlags)) {
- push(@headerContent, $structureFlag . " | ");
+ if ($interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}) {
+ push(@headerContent, " bool getOwnPropertySlotDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
}
- push(@headerContent, "Base::StructureFlags;\n");
- # Index getter
- if ($indexedGetterFunction) {
- if ($hasNumericIndexedGetter) {
- push(@headerContent, " JSC::JSValue getByIndex(JSC::ExecState*, unsigned index);\n");
- } else {
- push(@headerContent, " static JSC::EncodedJSValue indexGetter(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue, unsigned);\n");
- }
+ if ($interface->extendedAttributes->{CustomNamedGetter}) {
+ push(@headerContent, " bool nameGetter(JSC::ExecState*, JSC::PropertyName, JSC::JSValue&);\n");
}
- # Index setter
- if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
- push(@headerContent, " void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
+ if ($interface->extendedAttributes->{CustomNamedSetter}) {
+ push(@headerContent, " bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&, bool& putResult);\n");
}
- # Name getter
- if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
- push(@headerContent, "private:\n");
- push(@headerContent, " static bool canGetItemsForName(JSC::ExecState*, $interfaceName*, JSC::PropertyName);\n");
- push(@headerContent, " static JSC::EncodedJSValue nameGetter(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::PropertyName);\n");
+
+ if ($interface->extendedAttributes->{CustomIndexedSetter}) {
+ push(@headerContent, " void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
}
push(@headerContent, "};\n\n");
- if (!$hasParent ||
- GetGenerateIsReachable($interface) ||
- GetCustomIsReachable($interface) ||
- $interface->extendedAttributes->{"JSCustomFinalize"} ||
- $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
+ if (ShouldGenerateWrapperOwnerCode($hasParent, $interface)) {
if ($interfaceName ne "Node" && $codeGenerator->InheritsInterface($interface, "Node")) {
$headerIncludes{"JSNode.h"} = 1;
push(@headerContent, "class JS${interfaceName}Owner : public JSNodeOwner {\n");
} else {
push(@headerContent, "class JS${interfaceName}Owner : public JSC::WeakHandleOwner {\n");
}
+ $headerIncludes{"<wtf/NeverDestroyed.h>"} = 1;
push(@headerContent, "public:\n");
push(@headerContent, " virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
push(@headerContent, " virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
@@ -1016,99 +2114,42 @@ sub GenerateHeader
push(@headerContent, "\n");
push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, $implType*)\n");
push(@headerContent, "{\n");
- push(@headerContent, " DEFINE_STATIC_LOCAL(JS${interfaceName}Owner, js${interfaceName}Owner, ());\n");
- push(@headerContent, " return &js${interfaceName}Owner;\n");
+ push(@headerContent, " static NeverDestroyed<JS${interfaceName}Owner> owner;\n");
+ push(@headerContent, " return &owner.get();\n");
push(@headerContent, "}\n");
push(@headerContent, "\n");
- push(@headerContent, "inline void* wrapperContext(DOMWrapperWorld& world, $implType*)\n");
+ push(@headerContent, "inline void* wrapperKey($implType* wrappableObject)\n");
push(@headerContent, "{\n");
- push(@headerContent, " return &world;\n");
+ push(@headerContent, " return wrappableObject;\n");
push(@headerContent, "}\n");
push(@headerContent, "\n");
}
if (ShouldGenerateToJSDeclaration($hasParent, $interface)) {
- push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
- }
- if (!$hasParent || $interface->extendedAttributes->{"JSGenerateToNativeObject"}) {
- if ($interfaceName eq "NodeFilter") {
- push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::VM&, JSC::JSValue);\n");
- } elsif ($interfaceName eq "DOMStringList") {
- push(@headerContent, "PassRefPtr<DOMStringList> toDOMStringList(JSC::ExecState*, JSC::JSValue);\n");
+ # Node and NodeList have custom inline implementations which thus cannot be exported.
+ # FIXME: The special case for Node and NodeList should probably be implemented via an IDL attribute.
+ if ($implType eq "Node" or $implType eq "NodeList") {
+ push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType&);\n");
} else {
- push(@headerContent, "$implType* to${interfaceName}(JSC::JSValue);\n");
+ push(@headerContent, $exportMacro."JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType&);\n");
}
- }
- if ($usesToJSNewlyCreated{$interfaceName}) {
- push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, $interfaceName*);\n");
- }
-
- push(@headerContent, "\n");
-
- # Add prototype declaration.
- %structureFlags = ();
- push(@headerContent, "class ${className}Prototype : public JSC::JSNonFinalObject {\n");
- push(@headerContent, "public:\n");
- push(@headerContent, " typedef JSC::JSNonFinalObject Base;\n");
- unless (IsDOMGlobalObject($interface)) {
- push(@headerContent, " static JSC::JSObject* self(JSC::VM&, JSC::JSGlobalObject*);\n");
- }
-
- push(@headerContent, " static ${className}Prototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)\n");
- push(@headerContent, " {\n");
- push(@headerContent, " ${className}Prototype* ptr = new (NotNull, JSC::allocateCell<${className}Prototype>(vm.heap)) ${className}Prototype(vm, globalObject, structure);\n");
- push(@headerContent, " ptr->finishCreation(vm);\n");
- push(@headerContent, " return ptr;\n");
- push(@headerContent, " }\n\n");
-
- push(@headerContent, " DECLARE_INFO;\n");
- if (PrototypeOverridesGetOwnPropertySlot($interface)) {
- push(@headerContent, " static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
- $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
- }
- if ($interface->extendedAttributes->{"JSCustomMarkFunction"} or $needsMarkChildren) {
- $structureFlags{"JSC::OverridesVisitChildren"} = 1;
- }
- push(@headerContent,
- " static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n" .
- " {\n" .
- " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n" .
- " }\n");
- if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {
- push(@headerContent, " static void put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
- push(@headerContent, " bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
- }
+ push(@headerContent, "inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, $implType* impl) { return impl ? toJS(state, globalObject, *impl) : JSC::jsNull(); }\n");
- # Custom defineOwnProperty function
- push(@headerContent, " static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnPropertyOnPrototype"};
-
- push(@headerContent, "\nprivate:\n");
- push(@headerContent, " ${className}Prototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) : JSC::JSNonFinalObject(vm, structure) { }\n");
-
- # structure flags
- push(@headerContent, "protected:\n");
- push(@headerContent, " static const unsigned StructureFlags = ");
- foreach my $structureFlag (sort (keys %structureFlags)) {
- push(@headerContent, $structureFlag . " | ");
- }
- push(@headerContent, "Base::StructureFlags;\n");
+ push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, Ref<$implType>&&);\n");
+ push(@headerContent, "inline JSC::JSValue toJSNewlyCreated(JSC::ExecState* state, JSDOMGlobalObject* globalObject, RefPtr<$implType>&& impl) { return impl ? toJSNewlyCreated(state, globalObject, impl.releaseNonNull()) : JSC::jsNull(); }\n");
+ }
- push(@headerContent, "};\n\n");
+ push(@headerContent, "\n");
- if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
- $headerIncludes{"JSDOMBinding.h"} = 1;
- if ($interface->extendedAttributes->{"NamedConstructor"}) {
- $headerIncludes{"DOMConstructorWithDocument.h"} = 1;
- }
- GenerateConstructorDeclaration(\@headerContent, $className, $interface, $interfaceName);
- }
+ GeneratePrototypeDeclaration(\@headerContent, $className, $interface) if HeaderNeedsPrototypeDeclaration($interface);
- if ($numFunctions > 0) {
+ if ($hasForwardDeclaringFunctions) {
my $inAppleCopyright = 0;
push(@headerContent,"// Functions\n\n");
foreach my $function (@{$interface->functions}) {
next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
- my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
- if ($needsAppleCopyright) {
+ next unless $function->extendedAttributes->{ForwardDeclareInHeader};
+
+ if ($function->extendedAttributes->{AppleCopyright}) {
if (!$inAppleCopyright) {
push(@headerContent, $beginAppleCopyrightForHeaderFiles);
$inAppleCopyright = 1;
@@ -1118,296 +2159,619 @@ sub GenerateHeader
$inAppleCopyright = 0;
}
- my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
+ my $conditionalAttribute = getConditionalForFunctionConsideringOverloads($function);
+ my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
- my $functionName = GetFunctionName($className, $function);
+ my $functionName = GetFunctionName($interface, $className, $function);
push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
push(@headerContent, "#endif\n") if $conditionalString;
}
push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
+ push(@headerContent,"\n");
}
- if ($numAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"}) {
+ if ($hasForwardDeclaringAttributes) {
push(@headerContent,"// Attributes\n\n");
foreach my $attribute (@{$interface->attributes}) {
- my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
+ next unless $attribute->extendedAttributes->{ForwardDeclareInHeader};
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
- my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
- push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::PropertyName);\n");
+ my $getter = GetAttributeGetterName($interface, $className, $attribute);
+ push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
if (!IsReadonly($attribute)) {
- my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
- push(@headerContent, "void ${setter}(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
+ my $setter = GetAttributeSetterName($interface, $className, $attribute);
+ push(@headerContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
}
push(@headerContent, "#endif\n") if $conditionalString;
}
-
- if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
- my $getter = "js" . $interfaceName . "Constructor";
- push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::PropertyName);\n");
- }
+ }
- if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
- my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
- push(@headerContent, "void ${constructorFunctionName}(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
+ if ($hasDOMJITAttributes) {
+ $headerIncludes{"<domjit/DOMJITGetterSetter.h>"} = 1;
+ push(@headerContent,"// DOMJIT emitters for attributes\n\n");
+ foreach my $attribute (@{$interface->attributes}) {
+ next unless $attribute->extendedAttributes->{"DOMJIT"};
+ assert("Only DOMJIT=Getter is supported for attributes") unless $codeGenerator->ExtendedAttributeContains($attribute->extendedAttributes->{DOMJIT}, "Getter");
+
+ my $interfaceName = $interface->type->name;
+ my $className = $interfaceName . $codeGenerator->WK_ucfirst($attribute->name);
+ my $domJITClassName = $className . "DOMJIT";
+
+ push(@headerContent, "JSC::DOMJIT::GetterSetter* domJITGetterSetterFor$className(void);\n");
+
+ push(@headerContent, "class ${domJITClassName} : public JSC::DOMJIT::GetterSetter {\n");
+ push(@headerContent, "public:\n");
+ push(@headerContent, " ${domJITClassName}();\n");
+ push(@headerContent, "#if ENABLE(JIT)\n");
+ push(@headerContent, " Ref<JSC::DOMJIT::Patchpoint> checkDOM() override;\n");
+ push(@headerContent, " Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> callDOMGetter() override;\n");
+ push(@headerContent, "#endif\n");
+ push(@headerContent, "};\n\n");
}
}
- if ($numConstants > 0) {
- push(@headerContent,"// Constants\n\n");
- foreach my $constant (@{$interface->constants}) {
- my $conditionalString = $codeGenerator->GenerateConditionalString($constant);
- push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
- my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
- push(@headerContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::PropertyName);\n");
- push(@headerContent, "#endif\n") if $conditionalString;
- }
+ if (HasCustomConstructor($interface)) {
+ push(@headerContent, "// Custom constructor\n");
+ push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState&);\n\n");
}
+ if (NeedsImplementationClass($interface)) {
+ push(@headerContent, "template<> struct JSDOMWrapperConverterTraits<${implType}> {\n");
+ push(@headerContent, " using WrapperClass = ${className};\n");
+ push(@headerContent, " using ToWrappedReturnType = " . GetNativeType($interface, $interface->type) . ";\n");
+ push(@headerContent, "};\n");
+ }
+
+ push(@headerContent, GenerateEnumerationsHeaderContent($interface, $enumerations));
+ push(@headerContent, GenerateDictionariesHeaderContent($interface, $dictionaries));
+
my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
- push(@headerContent, "\n} // namespace WebCore\n\n");
- push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
- push(@headerContent, "#endif\n");
+ push(@headerContent, "\n} // namespace WebCore\n");
+ push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
- if ($interface->extendedAttributes->{"AppleCopyright"}) {
+ if ($interface->extendedAttributes->{AppleCopyright}) {
+ push(@headerContent, "\n");
push(@headerContent, split("\r", $endAppleCopyright));
}
+
+ # - Generate dependencies.
+ if ($writeDependencies) {
+ my @ancestors;
+ $codeGenerator->ForAllParents($interface, sub {
+ my $currentInterface = shift;
+ push(@ancestors, $currentInterface->type->name);
+ }, 0);
+ for my $dictionary (@$dictionaries) {
+ my $parentType = $dictionary->parentType;
+ while (defined($parentType)) {
+ push(@ancestors, $parentType->name) if $codeGenerator->IsExternalDictionaryType($parentType);
+ my $parentDictionary = $codeGenerator->GetDictionaryByType($parentType);
+ assert("Unable to find definition for dictionary named '" . $parentType->name . "'!") unless defined($parentDictionary);
+ $parentType = $parentDictionary->parentType;
+ }
+ }
+ push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestors), "\n");
+ push(@depsContent, map { "$_.idl :\n" } @ancestors);
+ }
}
-sub GenerateAttributesHashTable($$)
+sub GeneratePropertiesHashTable
{
- my ($object, $interface) = @_;
+ my ($object, $interface, $isInstance, $hashKeys, $hashSpecials, $hashValue1, $hashValue2, $conditionals, $runtimeEnabledFunctions, $runtimeEnabledAttributes) = @_;
# FIXME: These should be functions on $interface.
- my $interfaceName = $interface->name;
+ my $interfaceName = $interface->type->name;
my $className = "JS$interfaceName";
- # - Add all attributes in a hashtable definition
- my $numAttributes = @{$interface->attributes};
- $numAttributes++ if !$interface->extendedAttributes->{"NoInterfaceObject"};
+ # - Add all properties in a hashtable definition
+ my $propertyCount = $isInstance ? InstancePropertyCount($interface) : PrototypePropertyCount($interface);
- return 0 if !$numAttributes;
-
- my $hashSize = $numAttributes;
- my $hashName = $className . "Table";
+ if (!$isInstance && NeedsConstructorProperty($interface)) {
+ die if !$propertyCount;
+ push(@$hashKeys, "constructor");
+ my $getter = "js" . $interfaceName . "Constructor";
+ push(@$hashValue1, $getter);
- my @hashKeys = ();
- my @hashSpecials = ();
- my @hashValue1 = ();
- my @hashValue2 = ();
- my %conditionals = ();
+ my $setter = "setJS" . $interfaceName . "Constructor";
+ push(@$hashValue2, $setter);
+ push(@$hashSpecials, "DontEnum");
+ }
- my @entries = ();
+ return 0 if !$propertyCount;
foreach my $attribute (@{$interface->attributes}) {
next if ($attribute->isStatic);
- my $name = $attribute->signature->name;
- push(@hashKeys, $name);
+ next if AttributeShouldBeOnInstance($interface, $attribute) != $isInstance;
- my @specials = ();
- # As per Web IDL specification, constructor properties on the ECMAScript global object should be
- # configurable and should not be enumerable.
- my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
- push(@specials, "DontDelete") unless ($attribute->signature->extendedAttributes->{"Deletable"} || $is_global_constructor);
- push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor);
- push(@specials, "ReadOnly") if IsReadonly($attribute);
- my $special = (@specials > 0) ? join(" | ", @specials) : "0";
- push(@hashSpecials, $special);
+ # Global objects add RuntimeEnabled attributes after creation so do not add them to the static table.
+ if ($isInstance && NeedsRuntimeCheck($attribute)) {
+ $propertyCount -= 1;
+ next;
+ }
- my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
- push(@hashValue1, $getter);
+ my $name = $attribute->name;
+ push(@$hashKeys, $name);
- if (IsReadonly($attribute)) {
- push(@hashValue2, "0");
+ my $special = GetJSCAttributesForAttribute($interface, $attribute);
+ push(@$hashSpecials, $special);
+
+ if ($attribute->extendedAttributes->{"DOMJIT"}) {
+ push(@$hashValue1, "domJITGetterSetterFor" . $interface->type->name . $codeGenerator->WK_ucfirst($attribute->name));
+ push(@$hashValue2, "0");
} else {
- my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
- push(@hashValue2, $setter);
+ my $getter = GetAttributeGetterName($interface, $className, $attribute);
+ push(@$hashValue1, $getter);
+
+ if (IsReadonly($attribute)) {
+ push(@$hashValue2, "0");
+ } else {
+ my $setter = GetAttributeSetterName($interface, $className, $attribute);
+ push(@$hashValue2, $setter);
+ }
}
- my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
- if ($conditional) {
- $conditionals{$name} = $conditional;
+ my $conditional = $attribute->extendedAttributes->{Conditional};
+ $conditionals->{$name} = $conditional if $conditional;
+
+ if (NeedsRuntimeCheck($attribute)) {
+ push(@$runtimeEnabledAttributes, $attribute);
}
}
- if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
- push(@hashKeys, "constructor");
- my $getter = "js" . $interfaceName . "Constructor";
- push(@hashValue1, $getter);
- if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
- my $setter = "setJS" . $interfaceName . "Constructor";
- push(@hashValue2, $setter);
- push(@hashSpecials, "DontEnum | DontDelete");
- } else {
- push(@hashValue2, "0");
- push(@hashSpecials, "DontEnum | ReadOnly");
+ my @functions = @{$interface->functions};
+ push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
+ push(@functions, @{$interface->serializable->functions}) if $interface->serializable;
+ foreach my $function (@functions) {
+ next if ($function->extendedAttributes->{PrivateIdentifier} and not $function->extendedAttributes->{PublicIdentifier});
+ next if ($function->isStatic);
+ next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
+ next if OperationShouldBeOnInstance($interface, $function) != $isInstance;
+ next if $function->name eq "[Symbol.Iterator]";
+
+ # Global objects add RuntimeEnabled operations after creation so do not add them to the static table.
+ if ($isInstance && NeedsRuntimeCheck($function)) {
+ $propertyCount -= 1;
+ next;
+ }
+
+ my $name = $function->name;
+ push(@$hashKeys, $name);
+
+ my $functionName = GetFunctionName($interface, $className, $function);
+ push(@$hashValue1, $functionName);
+
+ my $functionLength = GetFunctionLength($function);
+
+ if ($function->extendedAttributes->{DOMJIT}) {
+ push(@$hashValue2, "&DOMJITSignatureFor" . $interface->type->name . $codeGenerator->WK_ucfirst($function->name));
+ } else {
+ push(@$hashValue2, $functionLength);
+ }
+
+ push(@$hashSpecials, ComputeFunctionSpecial($interface, $function));
+
+ my $conditional = getConditionalForFunctionConsideringOverloads($function);
+ $conditionals->{$name} = $conditional if $conditional;
+
+ if (NeedsRuntimeCheck($function)) {
+ push(@$runtimeEnabledFunctions, $function);
}
}
- $object->GenerateHashTable($hashName, $hashSize,
- \@hashKeys, \@hashSpecials,
- \@hashValue1, \@hashValue2,
- \%conditionals);
- return $numAttributes;
+ return $propertyCount;
}
-sub GenerateParametersCheckExpression
+# This computes an effective overload set for a given operation / constructor,
+# which represents the allowable invocations.This set is used as input for
+# the Web IDL overload resolution algorithm.
+# http://heycam.github.io/webidl/#dfn-effective-overload-set
+sub ComputeEffectiveOverloadSet
{
- my $numParameters = shift;
- my $function = shift;
+ my ($overloads) = @_;
+
+ my %allSets;
+ my $addTuple = sub {
+ my $tuple = shift;
+ # The Web IDL specification uses a flat set of tuples but we use a hash where the key is the
+ # number of parameters and the value is the set of tuples for the given number of parameters.
+ my $length = scalar(@{@$tuple[1]});
+ if (!exists($allSets{$length})) {
+ $allSets{$length} = [ $tuple ];
+ } else {
+ push(@{$allSets{$length}}, $tuple);
+ }
+ };
- my @andExpression = ();
- push(@andExpression, "argsCount == $numParameters");
- my $parameterIndex = 0;
- my %usedArguments = ();
- foreach my $parameter (@{$function->parameters}) {
- last if $parameterIndex >= $numParameters;
- my $value = "arg$parameterIndex";
- my $type = $parameter->type;
-
- # Only DOMString or wrapper types are checked.
- # For DOMString with StrictTypeChecking only Null, Undefined and Object
- # are accepted for compatibility. Otherwise, no restrictions are made to
- # match the non-overloaded behavior.
- # FIXME: Implement WebIDL overload resolution algorithm.
- if ($codeGenerator->IsStringType($type)) {
- if ($parameter->extendedAttributes->{"StrictTypeChecking"}) {
- push(@andExpression, "(${value}.isUndefinedOrNull() || ${value}.isString() || ${value}.isObject())");
- $usedArguments{$parameterIndex} = 1;
- }
- } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) {
- # For Callbacks only checks if the value is null or object.
- push(@andExpression, "(${value}.isNull() || ${value}.isFunction())");
- $usedArguments{$parameterIndex} = 1;
- } elsif ($codeGenerator->GetArrayType($type) || $codeGenerator->GetSequenceType($type)) {
- # FIXME: Add proper support for T[], T[]?, sequence<T>
- if ($parameter->isNullable) {
- push(@andExpression, "(${value}.isNull() || (${value}.isObject() && isJSArray(${value})))");
+ my $m = LengthOfLongestFunctionParameterList($overloads);
+ foreach my $overload (@{$overloads}) {
+ my $n = @{$overload->arguments};
+ my @t;
+ my @o;
+ my $isVariadic = 0;
+ foreach my $argument (@{$overload->arguments}) {
+ push(@t, $argument->type);
+ if ($argument->isOptional) {
+ push(@o, "optional");
+ } elsif ($argument->isVariadic) {
+ push(@o, "variadic");
+ $isVariadic = 1;
} else {
- push(@andExpression, "(${value}.isObject() && isJSArray(${value}))");
+ push(@o, "required");
}
- $usedArguments{$parameterIndex} = 1;
- } elsif (!IsNativeType($type)) {
- if ($parameter->isNullable) {
- push(@andExpression, "(${value}.isNull() || (${value}.isObject() && asObject(${value})->inherits(JS${type}::info())))");
- } else {
- push(@andExpression, "(${value}.isObject() && asObject(${value})->inherits(JS${type}::info()))");
+ }
+ &$addTuple([$overload, [@t], [@o]]);
+ if ($isVariadic) {
+ my @newT = @t;
+ my @newO = @o;
+ for (my $i = $n; $i < $m; $i++) {
+ push(@newT, $t[-1]);
+ push(@newO, "variadic");
+ &$addTuple([$overload, [@newT], [@newO]]);
}
- $usedArguments{$parameterIndex} = 1;
}
- $parameterIndex++;
+ for (my $i = $n - 1; $i >= 0; $i--) {
+ my $argument = @{$overload->arguments}[$i];
+ last unless ($argument->isOptional || $argument->isVariadic);
+ pop(@t);
+ pop(@o);
+ &$addTuple([$overload, [@t], [@o]]);
+ }
}
- my $res = join(" && ", @andExpression);
- $res = "($res)" if @andExpression > 1;
- return ($res, sort {$a <=> $b} (keys %usedArguments));
+ return %allSets;
}
-# As per Web IDL specification, the length of a function Object is
-# its number of mandatory parameters.
-sub GetFunctionLength
+sub IsIDLTypeDistinguishableWithUnionForOverloadResolution
{
- my $function = shift;
+ my ($type, $unionSubtypes) = @_;
- my $numMandatoryParams = 0;
- foreach my $parameter (@{$function->parameters}) {
- # Abort as soon as we find the first optional parameter as no mandatory
- # parameter can follow an optional one.
- last if $parameter->isOptional;
- $numMandatoryParams++;
- }
- return $numMandatoryParams;
+ assert("First type should not be a union") if $type->isUnion;
+ for my $unionSubType (@$unionSubtypes) {
+ return 0 unless AreTypesDistinguishableForOverloadResolution($type, $unionSubType);
+ }
+ return 1;
}
-sub GenerateFunctionParametersCheck
+# Determines if two types are distinguishable in the context of overload resolution,
+# according to the Web IDL specification:
+# http://heycam.github.io/webidl/#dfn-distinguishable
+sub AreTypesDistinguishableForOverloadResolution
{
- my $function = shift;
+ my ($typeA, $typeB) = @_;
- my @orExpression = ();
- my $numParameters = 0;
- my @neededArguments = ();
- my $hasVariadic = 0;
- my $numMandatoryParams = @{$function->parameters};
-
- foreach my $parameter (@{$function->parameters}) {
- if ($parameter->isOptional) {
- my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
- push(@orExpression, $expression);
- push(@neededArguments, @usedArguments);
- $numMandatoryParams--;
+ my $isDictionary = sub {
+ my $type = shift;
+ return $codeGenerator->IsDictionaryType($type);
+ };
+ my $isCallbackFunctionOrDictionary = sub {
+ my $type = shift;
+ return $codeGenerator->IsCallbackFunction($type) || &$isDictionary($type);
+ };
+
+ # Two types are distinguishable for overload resolution if at most one of the two includes a nullable type.
+ return 0 if $typeA->isNullable && $typeB->isNullable;
+
+ # Union types: typeA and typeB are distinguishable if:
+ # - Both types are either a union type or nullable union type, and each member type of the one is
+ # distinguishable with each member type of the other.
+ # - One type is a union type or nullable union type, the other is neither a union type nor a nullable
+ # union type, and each member type of the first is distinguishable with the second.
+ if ($typeA->isUnion && $typeB->isUnion) {
+ for my $unionASubType (@{$typeA->subtypes}) {
+ return 0 unless IsIDLTypeDistinguishableWithUnionForOverloadResolution($unionASubType, $typeB->subtypes);
}
- if ($parameter->isVariadic) {
- $hasVariadic = 1;
- last;
+ return 1;
+ } elsif ($typeA->isUnion) {
+ return IsIDLTypeDistinguishableWithUnionForOverloadResolution($typeB, $typeA->subtypes);
+ } elsif ($typeB->isUnion) {
+ return IsIDLTypeDistinguishableWithUnionForOverloadResolution($typeA, $typeB->subtypes);
+ }
+
+ return 0 if $typeA->name eq $typeB->name;
+ return 0 if $typeA->name eq "object" or $typeB->name eq "object";
+ return 0 if $codeGenerator->IsNumericType($typeA) && $codeGenerator->IsNumericType($typeB);
+ return 0 if $codeGenerator->IsStringOrEnumType($typeA) && $codeGenerator->IsStringOrEnumType($typeB);
+ return 0 if &$isDictionary($typeA) && &$isDictionary($typeB);
+ return 0 if $codeGenerator->IsCallbackInterface($typeA) && $codeGenerator->IsCallbackInterface($typeB);
+ return 0 if &$isCallbackFunctionOrDictionary($typeA) && &$isCallbackFunctionOrDictionary($typeB);
+ return 0 if $codeGenerator->IsSequenceOrFrozenArrayType($typeA) && $codeGenerator->IsSequenceOrFrozenArrayType($typeB);
+ # FIXME: return 0 if $typeA and $typeB are both exception types.
+ return 1;
+}
+
+# If there is more than one entry in an effective overload set that has a given type list length,
+# then for those entries there must be an index i such that for each pair of entries the types
+# at index i are distinguishable. The lowest such index is termed the distinguishing argument index.
+# http://heycam.github.io/webidl/#dfn-distinguishing-argument-index
+sub GetDistinguishingArgumentIndex
+{
+ my ($function, $S) = @_;
+
+ # FIXME: Consider all the tuples, not just the 2 first ones?
+ my $firstTupleTypes = @{@{$S}[0]}[1];
+ my $secondTupleTypes = @{@{$S}[1]}[1];
+ for (my $index = 0; $index < scalar(@$firstTupleTypes); $index++) {
+ return $index if AreTypesDistinguishableForOverloadResolution(@{$firstTupleTypes}[$index], @{$secondTupleTypes}[$index]);
+ }
+ die "Undistinguishable overloads for operation " . $function->name . " with length: " . scalar(@$firstTupleTypes);
+}
+
+sub GetOverloadThatMatches
+{
+ my ($S, $parameterIndex, $matches) = @_;
+
+ for my $tuple (@{$S}) {
+ my $type = @{@{$tuple}[1]}[$parameterIndex];
+ my $optionality = @{@{$tuple}[2]}[$parameterIndex];
+ if ($type->isUnion) {
+ for my $subtype (GetFlattenedMemberTypes($type)) {
+ return @{$tuple}[0] if $matches->($subtype, $optionality);
+ }
+ } else {
+ return @{$tuple}[0] if $matches->($type, $optionality);
}
- $numParameters++;
}
- if (!$hasVariadic) {
- my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
- push(@orExpression, $expression);
- push(@neededArguments, @usedArguments);
+}
+
+sub GetOverloadThatMatchesIgnoringUnionSubtypes
+{
+ my ($S, $parameterIndex, $matches) = @_;
+
+ for my $tuple (@{$S}) {
+ my $type = @{@{$tuple}[1]}[$parameterIndex];
+ my $optionality = @{@{$tuple}[2]}[$parameterIndex];
+ return @{$tuple}[0] if $matches->($type, $optionality);
}
- return ($numMandatoryParams, join(" || ", @orExpression), @neededArguments);
}
-sub GenerateOverloadedFunction
+sub getConditionalForFunctionConsideringOverloads
{
my $function = shift;
- my $interface = shift;
- my $interfaceName = 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.
+ return $function->extendedAttributes->{Conditional} unless $function->{overloads};
- my $kind = $function->isStatic ? "Constructor" : "Prototype";
- my $functionName = "js${interfaceName}${kind}Function" . $codeGenerator->WK_ucfirst($function->signature->name);
+ my %conditions;
+ foreach my $overload (@{$function->{overloads}}) {
+ my $conditional = $overload->extendedAttributes->{Conditional};
+ return unless $conditional;
+ $conditions{$conditional} = 1;
+ }
+ return join("|", keys %conditions);
+}
- push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
- push(@implContent, <<END);
+# Implements the overload resolution algorithm, as defined in the Web IDL specification:
+# http://heycam.github.io/webidl/#es-overloads
+sub GenerateOverloadedFunctionOrConstructor
{
- size_t argsCount = exec->argumentCount();
+ my ($function, $interface, $isConstructor) = @_;
+ my %allSets = ComputeEffectiveOverloadSet($function->{overloads});
+
+ my $interfaceName = $interface->type->name;
+ my $className = "JS$interfaceName";
+ my $functionName;
+ if ($isConstructor) {
+ $functionName = "construct${className}";
+ } else {
+ my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
+ $functionName = "js${interfaceName}${kind}Function" . $codeGenerator->WK_ucfirst($function->name);
+ }
+
+ my $generateOverloadCallIfNecessary = sub {
+ my ($overload, $condition, $include) = @_;
+ return unless $overload;
+ my $conditionalString = $codeGenerator->GenerateConditionalString($overload);
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ push(@implContent, " if ($condition)\n ") if $condition;
+ push(@implContent, " return ${functionName}$overload->{overloadIndex}(state);\n");
+ push(@implContent, "#endif\n") if $conditionalString;
+ AddToImplIncludes($include, $overload->extendedAttributes->{"Conditional"}) if $include;
+ };
+ my $isOptionalParameter = sub {
+ my ($type, $optionality) = @_;
+ return $optionality eq "optional";
+ };
+ my $isDictionaryOrRecordParameter = sub {
+ my ($type, $optionality) = @_;
+ return $codeGenerator->IsDictionaryType($type) || $codeGenerator->IsRecordType($type);
+ };
+ my $isNullableOrDictionaryOrRecordOrUnionContainingOne = sub {
+ my ($type, $optionality) = @_;
+ return 1 if $type->isNullable;
+ if ($type->isUnion) {
+ for my $subtype (GetFlattenedMemberTypes($type)) {
+ return 1 if $type->isNullable || &$isDictionaryOrRecordParameter($subtype, $optionality);
+ }
+ return 0;
+ } else {
+ return &$isDictionaryOrRecordParameter($type, $optionality);
+ }
+ };
+ my $isRegExpOrObjectParameter = sub {
+ my ($type, $optionality) = @_;
+ return $type->name eq "RegExp" || $type->name eq "object";
+ };
+ my $isObjectOrErrorParameter = sub {
+ my ($type, $optionality) = @_;
+ return $type->name eq "object" || $type->name eq "Error";
+ };
+ my $isObjectOrErrorOrDOMExceptionParameter = sub {
+ my ($type, $optionality) = @_;
+ return 1 if &$isObjectOrErrorParameter($type, $optionality);
+ return $type->name eq "DOMException";
+ };
+ my $isObjectOrCallbackFunctionParameter = sub {
+ my ($type, $optionality) = @_;
+ return $type->name eq "object" || $codeGenerator->IsCallbackFunction($type);
+ };
+ my $isSequenceOrFrozenArrayParameter = sub {
+ my ($type, $optionality) = @_;
+ return $codeGenerator->IsSequenceOrFrozenArrayType($type);
+ };
+ my $isDictionaryOrRecordOrObjectOrCallbackInterfaceParameter = sub {
+ my ($type, $optionality) = @_;
+ return 1 if &$isDictionaryOrRecordParameter($type, $optionality);
+ return 1 if $type->name eq "object";
+ return 1 if $codeGenerator->IsCallbackInterface($type) && !$codeGenerator->IsCallbackFunction($type);
+ return 0;
+ };
+ my $isBooleanParameter = sub {
+ my ($type, $optionality) = @_;
+ return $type->name eq "boolean";
+ };
+ my $isNumericParameter = sub {
+ my ($type, $optionality) = @_;
+ return $codeGenerator->IsNumericType($type);
+ };
+ my $isStringOrEnumParameter = sub {
+ my ($type, $optionality) = @_;
+ return $codeGenerator->IsStringOrEnumType($type);
+ };
+ my $isAnyParameter = sub {
+ my ($type, $optionality) = @_;
+ return $type->name eq "any";
+ };
+
+ my $maxArgCount = LengthOfLongestFunctionParameterList($function->{overloads});
+
+ my $conditionalAttribute = getConditionalForFunctionConsideringOverloads($function);
+ my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ if ($isConstructor) {
+ push(@implContent, "template<> EncodedJSValue JSC_HOST_CALL ${className}Constructor::construct(ExecState* state)\n");
+ } else {
+ push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* state)\n");
+ }
+ push(@implContent, <<END);
+{
+ VM& vm = state->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ size_t argsCount = std::min<size_t>($maxArgCount, state->argumentCount());
+END
+
+ for my $length ( sort keys %allSets ) {
+ push(@implContent, <<END);
+ if (argsCount == $length) {
END
+ my $S = $allSets{$length};
+ if (scalar(@$S) > 1) {
+ my $d = GetDistinguishingArgumentIndex($function, $S);
+ push(@implContent, " JSValue distinguishingArg = state->uncheckedArgument($d);\n");
+
+ my $overload = GetOverloadThatMatchesIgnoringUnionSubtypes($S, $d, \&$isOptionalParameter);
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isUndefined()");
+
+ $overload = GetOverloadThatMatchesIgnoringUnionSubtypes($S, $d, \&$isNullableOrDictionaryOrRecordOrUnionContainingOne);
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isUndefinedOrNull()");
+
+ for my $tuple (@{$S}) {
+ my $overload = @{$tuple}[0];
+ my $type = @{@{$tuple}[1]}[$d];
+
+ my @subtypes = $type->isUnion ? GetFlattenedMemberTypes($type) : ( $type );
+ for my $subtype (@subtypes) {
+ if ($codeGenerator->IsWrapperType($subtype) || $codeGenerator->IsTypedArrayType($subtype)) {
+ if ($subtype->name eq "DOMWindow") {
+ AddToImplIncludes("JSDOMWindowShell.h");
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && (asObject(distinguishingArg)->inherits(vm, JSDOMWindowShell::info()) || asObject(distinguishingArg)->inherits(vm, JSDOMWindow::info()))");
+ } else {
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->inherits(vm, JS" . $subtype->name . "::info())");
+ }
+ }
+ }
+ }
- my %fetchedArguments = ();
- my $leastNumMandatoryParams = 255;
+ $overload = GetOverloadThatMatches($S, $d, \&$isRegExpOrObjectParameter);
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() == RegExpObjectType");
- foreach my $overload (@{$function->{overloads}}) {
- my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload);
- $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams);
+ $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrErrorOrDOMExceptionParameter);
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->inherits(vm, JSDOMCoreException::info())");
- foreach my $parameterIndex (@neededArguments) {
- next if exists $fetchedArguments{$parameterIndex};
- push(@implContent, " JSValue arg$parameterIndex(exec->argument($parameterIndex));\n");
- $fetchedArguments{$parameterIndex} = 1;
- }
+ $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrErrorParameter);
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() == ErrorInstanceType");
- my $conditionalString = $codeGenerator->GenerateConditionalString($overload->signature);
- push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ $overload = GetOverloadThatMatches($S, $d, \&$isObjectOrCallbackFunctionParameter);
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isFunction()");
+
+ # FIXME: Avoid invoking GetMethod(object, Symbol.iterator) again in convert<IDLSequence<T>>(...).
+ $overload = GetOverloadThatMatches($S, $d, \&$isSequenceOrFrozenArrayParameter);
+ &$generateOverloadCallIfNecessary($overload, "hasIteratorMethod(*state, distinguishingArg)", "<runtime/IteratorOperations.h>");
+
+ $overload = GetOverloadThatMatches($S, $d, \&$isDictionaryOrRecordOrObjectOrCallbackInterfaceParameter);
+ &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && asObject(distinguishingArg)->type() != RegExpObjectType");
+
+ my $booleanOverload = GetOverloadThatMatches($S, $d, \&$isBooleanParameter);
+ &$generateOverloadCallIfNecessary($booleanOverload, "distinguishingArg.isBoolean()");
- push(@implContent, " if ($parametersCheck)\n");
- push(@implContent, " return ${functionName}$overload->{overloadIndex}(exec);\n");
- push(@implContent, "#endif\n\n") if $conditionalString;
+ my $numericOverload = GetOverloadThatMatches($S, $d, \&$isNumericParameter);
+ &$generateOverloadCallIfNecessary($numericOverload, "distinguishingArg.isNumber()");
+ # Fallbacks.
+ $overload = GetOverloadThatMatches($S, $d, \&$isStringOrEnumParameter);
+ if ($overload) {
+ &$generateOverloadCallIfNecessary($overload);
+ } elsif ($numericOverload) {
+ &$generateOverloadCallIfNecessary($numericOverload);
+ } elsif ($booleanOverload) {
+ &$generateOverloadCallIfNecessary($booleanOverload);
+ } else {
+ $overload = GetOverloadThatMatches($S, $d, \&$isAnyParameter);
+ &$generateOverloadCallIfNecessary($overload);
+ }
+ } else {
+ # Only 1 overload with this number of parameters.
+ my $overload = @{@{$S}[0]}[0];
+ &$generateOverloadCallIfNecessary($overload);
+ }
+ push(@implContent, <<END);
+ }
+END
}
- if ($leastNumMandatoryParams >= 1) {
- push(@implContent, " if (argsCount < $leastNumMandatoryParams)\n");
- push(@implContent, " return throwVMError(exec, createNotEnoughArgumentsError(exec));\n");
+ my $minArgCount = GetFunctionLength($function);
+ if ($minArgCount > 0) {
+ push(@implContent, " return argsCount < $minArgCount ? throwVMError(state, throwScope, createNotEnoughArgumentsError(state)) : throwVMTypeError(state, throwScope);\n")
+ } else {
+ push(@implContent, " return throwVMTypeError(state, throwScope);\n")
}
- push(@implContent, <<END);
- return throwVMTypeError(exec);
+ push(@implContent, "}\n");
+ push(@implContent, "#endif\n") if $conditionalString;
+ push(@implContent, "\n");
}
-END
+# As per Web IDL specification, the length of a function Object is its number of mandatory parameters.
+sub GetFunctionLength
+{
+ my $function = shift;
+
+ my $getOverloadLength = sub {
+ my $function = shift;
+
+ my $length = 0;
+ foreach my $argument (@{$function->arguments}) {
+ last if $argument->isOptional || $argument->isVariadic;
+ $length++;
+ }
+ return $length;
+ };
+
+ my $length = &$getOverloadLength($function);
+ foreach my $overload (@{$function->{overloads}}) {
+ my $newLength = &$getOverloadLength($overload);
+ $length = $newLength if $newLength < $length;
+ }
+ return $length;
}
-sub GetNativeTypeForConversions
+sub LengthOfLongestFunctionParameterList
{
- my $interface = shift;
- my $interfaceName = $interface->name;
- $interfaceName = $codeGenerator->GetSVGTypeNeedingTearOff($interfaceName) if $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName);
- return $interfaceName;
+ my ($overloads) = @_;
+ my $result = 0;
+ foreach my $overload (@{$overloads}) {
+ my @arguments = @{$overload->arguments};
+ $result = @arguments if $result < @arguments;
+ }
+ return $result;
}
# See http://refspecs.linux-foundation.org/cxxabi-1.83.html.
@@ -1418,7 +2782,7 @@ sub GetGnuVTableRefForInterface
if (!$vtableName) {
return "0";
}
- my $typename = GetNativeTypeForConversions($interface);
+ my $typename = $interface->type->name;
my $offset = GetGnuVTableOffsetForType($typename);
return "&" . $vtableName . "[" . $offset . "]";
}
@@ -1426,7 +2790,7 @@ sub GetGnuVTableRefForInterface
sub GetGnuVTableNameForInterface
{
my $interface = shift;
- my $typename = GetNativeTypeForConversions($interface);
+ my $typename = $interface->type->name;
my $templatePosition = index($typename, "<");
return "" if $templatePosition != -1;
return "" if GetImplementationLacksVTableForInterface($interface);
@@ -1437,13 +2801,13 @@ sub GetGnuVTableNameForInterface
sub GetGnuMangledNameForInterface
{
my $interface = shift;
- my $typename = GetNativeTypeForConversions($interface);
+ my $typename = $interface->type->name;
my $templatePosition = index($typename, "<");
if ($templatePosition != -1) {
return "";
}
my $mangledType = length($typename) . $typename;
- my $namespace = GetNamespaceForInterface($interface);
+ my $namespace = "WebCore";
my $mangledNamespace = "N" . length($namespace) . $namespace;
return $mangledNamespace . $mangledType . "E";
}
@@ -1487,7 +2851,7 @@ sub GetWinVTableRefForInterface
sub GetWinVTableNameForInterface
{
my $interface = shift;
- my $typename = GetNativeTypeForConversions($interface);
+ my $typename = $interface->type->name;
my $templatePosition = index($typename, "<");
return "" if $templatePosition != -1;
return "" if GetImplementationLacksVTableForInterface($interface);
@@ -1498,27 +2862,21 @@ sub GetWinVTableNameForInterface
sub GetWinMangledNameForInterface
{
my $interface = shift;
- my $typename = GetNativeTypeForConversions($interface);
- my $namespace = GetNamespaceForInterface($interface);
+ my $typename = $interface->type->name;
+ my $namespace = "WebCore";
return $typename . "@" . $namespace . "@@";
}
-sub GetNamespaceForInterface
-{
- my $interface = shift;
- return $interface->extendedAttributes->{"ImplementationNamespace"} || "WebCore";
-}
-
sub GetImplementationLacksVTableForInterface
{
my $interface = shift;
- return $interface->extendedAttributes->{"ImplementationLacksVTable"};
+ return $interface->extendedAttributes->{ImplementationLacksVTable};
}
sub GetSkipVTableValidationForInterface
{
my $interface = shift;
- return $interface->extendedAttributes->{"SkipVTableValidation"};
+ return $interface->extendedAttributes->{SkipVTableValidation};
}
# URL becomes url, but SetURL becomes setURL.
@@ -1526,12 +2884,13 @@ sub ToMethodName
{
my $param = shift;
my $ret = lcfirst($param);
+ $ret =~ s/cSS/css/ if $ret =~ /^cSS/;
+ $ret =~ s/dOM/dom/ if $ret =~ /^dOM/;
$ret =~ s/hTML/html/ if $ret =~ /^hTML/;
- $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
$ret =~ s/jS/js/ if $ret =~ /^jS/;
+ $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
$ret =~ s/xML/xml/ if $ret =~ /^xML/;
$ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
- $ret =~ s/cSS/css/ if $ret =~ /^cSS/;
# For HTML5 FileSystem API Flags attributes.
# (create is widely used to instantiate an object and must be avoided.)
@@ -1542,57 +2901,282 @@ sub ToMethodName
}
# Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
+# NOTE: Parameter passed in must have both an 'extendedAttributes' property.
+# (e.g. DOMInterface, DOMAttribute, DOMOperation, DOMIterable, etc.)
sub GetRuntimeEnableFunctionName
{
- my $signature = shift;
+ my $context = shift;
+
+ AddToImplIncludes("RuntimeEnabledFeatures.h");
+
+ if ($context->extendedAttributes->{EnabledForWorld}) {
+ return "worldForDOMObject(this)." . ToMethodName($context->extendedAttributes->{EnabledForWorld});
+ }
# If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::sharedFeatures().{FeatureName}Enabled() method.
- return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "VALUE_IS_MISSING");
+ if ($context->extendedAttributes->{EnabledAtRuntime} && $context->extendedAttributes->{EnabledAtRuntime} ne "VALUE_IS_MISSING") {
+ return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($context->extendedAttributes->{EnabledAtRuntime}) . "Enabled";
+ }
# Otherwise return a function named RuntimeEnabledFeatures::sharedFeatures().{methodName}Enabled().
- return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->name) . "Enabled";
+ return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($context->name) . "Enabled";
+}
+
+sub GetCastingHelperForThisObject
+{
+ my $interface = shift;
+ my $interfaceName = $interface->type->name;
+ return "jsDynamicDowncast<JS$interfaceName*>";
+}
+
+# http://heycam.github.io/webidl/#Unscopable
+sub addUnscopableProperties
+{
+ my $interface = shift;
+
+ my @unscopables;
+ foreach my $functionOrAttribute (@{$interface->functions}, @{$interface->attributes}) {
+ push(@unscopables, $functionOrAttribute->name) if $functionOrAttribute->extendedAttributes->{Unscopable};
+ }
+ return if scalar(@unscopables) == 0;
+
+ AddToImplIncludes("<runtime/ObjectConstructor.h>");
+ push(@implContent, " JSObject& unscopables = *constructEmptyObject(globalObject()->globalExec(), globalObject()->nullPrototypeObjectStructure());\n");
+ foreach my $unscopable (@unscopables) {
+ push(@implContent, " unscopables.putDirect(vm, Identifier::fromString(&vm, \"$unscopable\"), jsBoolean(true));\n");
+ }
+ push(@implContent, " putDirectWithoutTransition(vm, vm.propertyNames->unscopablesSymbol, &unscopables, DontEnum | ReadOnly);\n");
+}
+
+sub GetUnsafeArgumentType
+{
+ my ($interface, $type) = @_;
+
+ my $IDLType = GetIDLType($interface, $type);
+ return "DOMJIT::IDLJSArgumentType<${IDLType}>";
+}
+
+sub GetArgumentTypeFilter
+{
+ my ($interface, $type) = @_;
+
+ my $IDLType = GetIDLType($interface, $type);
+ return "DOMJIT::IDLArgumentTypeFilter<${IDLType}>::value";
+}
+
+sub GetResultTypeFilter
+{
+ my ($interface, $type) = @_;
+
+ my $IDLType = GetIDLType($interface, $type);
+ return "DOMJIT::IDLResultTypeFilter<${IDLType}>::value";
+}
+
+sub GetAttributeWithName
+{
+ my ($interface, $attributeName) = @_;
+
+ foreach my $attribute (@{$interface->attributes}) {
+ return $attribute if $attribute->name eq $attributeName;
+ }
+}
+
+# https://heycam.github.io/webidl/#es-iterator
+sub InterfaceNeedsIterator
+{
+ my ($interface) = @_;
+
+ return 1 if $interface->iterable;
+ if (GetIndexedGetterFunction($interface)) {
+ my $lengthAttribute = GetAttributeWithName($interface, "length");
+ return 1 if $lengthAttribute and $codeGenerator->IsIntegerType($lengthAttribute->type);
+ }
+ # FIXME: This should return 1 for maplike and setlike once we support them.
+ return 0;
}
sub GenerateImplementation
{
- my ($object, $interface) = @_;
+ my ($object, $interface, $enumerations, $dictionaries) = @_;
- my $interfaceName = $interface->name;
+ my $interfaceName = $interface->type->name;
my $className = "JS$interfaceName";
- my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"};
- my $hasRealParent = $interface->parent;
+ my $hasLegacyParent = $interface->extendedAttributes->{JSLegacyParent};
+ my $hasRealParent = $interface->parentType;
my $hasParent = $hasLegacyParent || $hasRealParent;
my $parentClassName = GetParentClassName($interface);
my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
- my $eventTarget = $interface->extendedAttributes->{"EventTarget"} || ($codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->name ne "EventTarget");
- my $needsMarkChildren = $interface->extendedAttributes->{"JSCustomMarkFunction"} || $interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget";
+ my $eventTarget = $codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->type->name ne "EventTarget";
+ my $needsVisitChildren = InstanceNeedsVisitChildren($interface);
my $namedGetterFunction = GetNamedGetterFunction($interface);
my $indexedGetterFunction = GetIndexedGetterFunction($interface);
- my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0;
# - Add default header template
push(@implContentHeader, GenerateImplementationContentHeader($interface));
+ $implIncludes{"JSDOMBinding.h"} = 1;
+ $implIncludes{"JSDOMBindingCaller.h"} = 1;
+ $implIncludes{"JSDOMExceptionHandling.h"} = 1;
+ $implIncludes{"JSDOMWrapperCache.h"} = 1;
$implIncludes{"<wtf/GetPtr.h>"} = 1;
$implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $indexedGetterFunction;
- AddIncludesForTypeInImpl($interfaceName);
+ my $implType = GetImplClassName($interface);
+
+ AddJSBuiltinIncludesIfNeeded($interface);
@implContent = ();
push(@implContent, "\nusing namespace JSC;\n\n");
push(@implContent, "namespace WebCore {\n\n");
- my $numAttributes = GenerateAttributesHashTable($object, $interface);
+ push(@implContent, GenerateEnumerationsImplementationContent($interface, $enumerations));
+ push(@implContent, GenerateDictionariesImplementationContent($interface, $dictionaries));
+
+ my @functions = @{$interface->functions};
+ push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
+ push(@functions, @{$interface->serializable->functions}) if $interface->serializable;
my $numConstants = @{$interface->constants};
- my $numFunctions = @{$interface->functions};
+ my $numFunctions = @functions;
+ my $numAttributes = @{$interface->attributes};
+
+ if ($numFunctions > 0) {
+ my $inAppleCopyright = 0;
+ push(@implContent,"// Functions\n\n");
+ foreach my $function (@functions) {
+ next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
+ next if $function->extendedAttributes->{ForwardDeclareInHeader};
+ next if IsJSBuiltin($interface, $function);
+
+ if ($function->extendedAttributes->{AppleCopyright}) {
+ if (!$inAppleCopyright) {
+ push(@implContent, $beginAppleCopyrightForHeaderFiles);
+ $inAppleCopyright = 1;
+ }
+ } elsif ($inAppleCopyright) {
+ push(@implContent, $endAppleCopyright);
+ $inAppleCopyright = 0;
+ }
+
+ my $conditionalAttribute = getConditionalForFunctionConsideringOverloads($function);
+ my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ my $functionName = GetFunctionName($interface, $className, $function);
+ push(@implContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
+ if ($function->extendedAttributes->{DOMJIT}) {
+ $implIncludes{"DOMJITIDLType.h"} = 1;
+ my $unsafeFunctionName = "unsafe" . $codeGenerator->WK_ucfirst($functionName);
+ my $functionSignature = "JSC::EncodedJSValue JIT_OPERATION ${unsafeFunctionName}(JSC::ExecState*, $className*";
+ foreach my $argument (@{$function->arguments}) {
+ my $type = $argument->type;
+ my $argumentType = GetUnsafeArgumentType($interface, $type);
+ $functionSignature .= ", ${argumentType}";
+ }
+ push(@implContent, $functionSignature . ");\n");
+ }
+ push(@implContent, "#endif\n") if $conditionalString;
+ }
+
+ push(@implContent, $endAppleCopyright) if $inAppleCopyright;
+ push(@implContent, "\n");
+ }
+
+ if ($numAttributes > 0 || NeedsConstructorProperty($interface)) {
+ push(@implContent, "// Attributes\n\n");
+
+ foreach my $attribute (@{$interface->attributes}) {
+ next if $attribute->extendedAttributes->{ForwardDeclareInHeader};
+ next if IsJSBuiltin($interface, $attribute);
- # - Add all constants
- if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
- my $hashSize = $numConstants;
+ my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ my $getter = GetAttributeGetterName($interface, $className, $attribute);
+ push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
+ if (!IsReadonly($attribute)) {
+ my $setter = GetAttributeSetterName($interface, $className, $attribute);
+ push(@implContent, "bool ${setter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
+ }
+ push(@implContent, "#endif\n") if $conditionalString;
+ }
+
+ if (NeedsConstructorProperty($interface)) {
+ my $getter = "js" . $interfaceName . "Constructor";
+ push(@implContent, "JSC::EncodedJSValue ${getter}(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);\n");
+ }
+
+ my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
+ push(@implContent, "bool ${constructorFunctionName}(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);\n");
+
+ push(@implContent, "\n");
+ }
+
+ if ($numFunctions > 0) {
+ foreach my $function (@functions) {
+ next unless $function->extendedAttributes->{DOMJIT};
+ $implIncludes{"DOMJITIDLTypeFilter.h"} = 1;
+ $implIncludes{"DOMJITCheckDOM.h"} = 1;
+ $implIncludes{"DOMJITAbstractHeapRepository.h"} = 1;
+
+ my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
+ die "Overloads is not supported in DOMJIT" if $isOverloaded;
+ die "Currently ReadDOM value is only allowed" unless $codeGenerator->ExtendedAttributeContains($function->extendedAttributes->{DOMJIT}, "ReadDOM");
+
+ my $interfaceName = $interface->type->name;
+ my $functionName = GetFunctionName($interface, $className, $function);
+ my $unsafeFunctionName = "unsafe" . $codeGenerator->WK_ucfirst($functionName);
+ my $domJITSignatureName = "DOMJITSignatureFor" . $interface->type->name . $codeGenerator->WK_ucfirst($function->name);
+ my $classInfo = "JS" . $interface->type->name . "::info()";
+ my $resultType = GetResultTypeFilter($interface, $function->type);
+ my $domJITSignatureHeader = "static const JSC::DOMJIT::Signature ${domJITSignatureName}((uintptr_t)${unsafeFunctionName},";
+ my $domJITSignatureFooter = "$classInfo, JSC::DOMJIT::Effect::forRead(DOMJIT::AbstractHeapRepository::DOM), ${resultType}";
+ foreach my $argument (@{$function->arguments}) {
+ my $type = $argument->type;
+ my $argumentType = GetArgumentTypeFilter($interface, $type);
+ $domJITSignatureFooter .= ", ${argumentType}";
+ }
+ $domJITSignatureFooter .= ");";
+ my $conditionalString = $codeGenerator->GenerateConditionalString($function);
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ push(@implContent, "#if ENABLE(JIT)\n");
+ push(@implContent, "$domJITSignatureHeader DOMJIT::checkDOM<$interfaceName>, $domJITSignatureFooter\n");
+ push(@implContent, "#else\n");
+ push(@implContent, "$domJITSignatureHeader nullptr, $domJITSignatureFooter\n");
+ push(@implContent, "#endif\n");
+ push(@implContent, "#endif\n") if $conditionalString;
+ push(@implContent, "\n");
+ }
+ }
+
+ GeneratePrototypeDeclaration(\@implContent, $className, $interface) if !HeaderNeedsPrototypeDeclaration($interface);
+
+ GenerateConstructorDeclaration(\@implContent, $className, $interface) if NeedsConstructorProperty($interface);
+
+ my @hashKeys = ();
+ my @hashValue1 = ();
+ my @hashValue2 = ();
+ my @hashSpecials = ();
+ my %conditionals = ();
+ my $hashName = $className . "Table";
+ my @runtimeEnabledFunctions = ();
+ my @runtimeEnabledAttributes = ();
+
+ # Generate hash table for properties on the instance.
+ my $numInstanceProperties = GeneratePropertiesHashTable($object, $interface, 1,
+ \@hashKeys, \@hashSpecials,
+ \@hashValue1, \@hashValue2,
+ \%conditionals, \@runtimeEnabledFunctions, \@runtimeEnabledAttributes);
+
+ $object->GenerateHashTable($hashName, $numInstanceProperties,
+ \@hashKeys, \@hashSpecials,
+ \@hashValue1, \@hashValue2,
+ \%conditionals, 0) if $numInstanceProperties > 0;
+
+ # - Add all interface object (aka constructor) properties (constants, static attributes, static operations).
+ if (NeedsConstructorProperty($interface)) {
+ my $hashSize = 0;
my $hashName = $className . "ConstructorTable";
my @hashKeys = ();
@@ -1601,855 +3185,762 @@ sub GenerateImplementation
my @hashSpecials = ();
my %conditionals = ();
- # FIXME: we should not need a function for every constant.
+ my $needsConstructorTable = 0;
+
foreach my $constant (@{$interface->constants}) {
my $name = $constant->name;
push(@hashKeys, $name);
- my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name);
- push(@hashValue1, $getter);
+ push(@hashValue1, $constant->value);
push(@hashValue2, "0");
- push(@hashSpecials, "DontDelete | ReadOnly");
+ push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
- my $implementedBy = $constant->extendedAttributes->{"ImplementedBy"};
- if ($implementedBy) {
- $implIncludes{"${implementedBy}.h"} = 1;
- }
- my $conditional = $constant->extendedAttributes->{"Conditional"};
- if ($conditional) {
- $conditionals{$name} = $conditional;
- }
+ my $implementedBy = $constant->extendedAttributes->{ImplementedBy};
+ $implIncludes{"${implementedBy}.h"} = 1 if $implementedBy;
+
+ my $conditional = $constant->extendedAttributes->{Conditional};
+ $conditionals{$name} = $conditional if $conditional;
+
+ $hashSize++;
}
foreach my $attribute (@{$interface->attributes}) {
next unless ($attribute->isStatic);
- my $name = $attribute->signature->name;
+ my $name = $attribute->name;
push(@hashKeys, $name);
my @specials = ();
- push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
+ push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute);
push(@specials, "ReadOnly") if IsReadonly($attribute);
+ push(@specials, "DOMJITAttribute") if $attribute->extendedAttributes->{"DOMJIT"};
my $special = (@specials > 0) ? join(" | ", @specials) : "0";
push(@hashSpecials, $special);
- my $getter = GetAttributeGetterName($interfaceName, $className, $attribute);
- push(@hashValue1, $getter);
-
- if (IsReadonly($attribute)) {
+ if ($attribute->extendedAttributes->{"DOMJIT"}) {
+ push(@hashValue1, "domJITGetterSetterFor" . $interface->type->name . $codeGenerator->WK_ucfirst($attribute->name));
push(@hashValue2, "0");
} else {
- my $setter = GetAttributeSetterName($interfaceName, $className, $attribute);
- push(@hashValue2, $setter);
- }
+ my $getter = GetAttributeGetterName($interface, $className, $attribute);
+ push(@hashValue1, $getter);
- my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
- if ($conditional) {
- $conditionals{$name} = $conditional;
+ if (IsReadonly($attribute)) {
+ push(@hashValue2, "0");
+ } else {
+ my $setter = GetAttributeSetterName($interface, $className, $attribute);
+ push(@hashValue2, $setter);
+ }
}
+
+ my $conditional = $attribute->extendedAttributes->{Conditional};
+ $conditionals{$name} = $conditional if $conditional;
+
+ $hashSize++;
}
foreach my $function (@{$interface->functions}) {
next unless ($function->isStatic);
next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
- my $name = $function->signature->name;
+ my $name = $function->name;
push(@hashKeys, $name);
- my $functionName = GetFunctionName($className, $function);
+ my $functionName = GetFunctionName($interface, $className, $function);
push(@hashValue1, $functionName);
my $functionLength = GetFunctionLength($function);
- push(@hashValue2, $functionLength);
+ if ($function->extendedAttributes->{DOMJIT}) {
+ push(@hashValue2, "DOMJITFunctionFor" . $interface->type->name . $codeGenerator->WK_ucfirst($function->name));
+ } else {
+ push(@hashValue2, $functionLength);
+ }
- my @specials = ();
- push(@specials, "DontDelete") if $interface->extendedAttributes->{"OperationsNotDeletable"}
- || $function->signature->extendedAttributes->{"NotDeletable"};
- push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"};
- push(@specials, "JSC::Function");
- my $special = (@specials > 0) ? join(" | ", @specials) : "0";
- push(@hashSpecials, $special);
+ push(@hashSpecials, ComputeFunctionSpecial($interface, $function));
- my $conditional = $function->signature->extendedAttributes->{"Conditional"};
- if ($conditional) {
- $conditionals{$name} = $conditional;
- }
+ my $conditional = $function->extendedAttributes->{Conditional};
+ $conditionals{$name} = $conditional if $conditional;
+
+ $hashSize++;
}
$object->GenerateHashTable($hashName, $hashSize,
\@hashKeys, \@hashSpecials,
\@hashValue1, \@hashValue2,
- \%conditionals);
+ \%conditionals, 1) if $hashSize > 0;
push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($interface));
my $protoClassName = "${className}Prototype";
- GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface);
- if ($interface->extendedAttributes->{"NamedConstructor"}) {
- GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interfaceName, $interface->extendedAttributes->{"NamedConstructor"}, $interface, "GeneratingNamedConstructor");
- }
+ GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $visibleInterfaceName, $interface);
+
+ my $namedConstructor = $interface->extendedAttributes->{NamedConstructor};
+ GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $namedConstructor, $interface, "GeneratingNamedConstructor") if $namedConstructor;
}
# - Add functions and constants to a hashtable definition
- my $hashSize = $numFunctions + $numConstants;
- my $hashName = $className . "PrototypeTable";
- my @hashKeys = ();
- my @hashValue1 = ();
- my @hashValue2 = ();
- my @hashSpecials = ();
- my %conditionals = ();
+ $hashName = $className . "PrototypeTable";
+
+ @hashKeys = ();
+ @hashValue1 = ();
+ @hashValue2 = ();
+ @hashSpecials = ();
+ %conditionals = ();
+ @runtimeEnabledFunctions = ();
+ @runtimeEnabledAttributes = ();
+
+ # Generate hash table for properties on the prototype.
+ my $numPrototypeProperties = GeneratePropertiesHashTable($object, $interface, 0,
+ \@hashKeys, \@hashSpecials,
+ \@hashValue1, \@hashValue2,
+ \%conditionals, \@runtimeEnabledFunctions, \@runtimeEnabledAttributes);
+ my $hashSize = $numPrototypeProperties;
- # FIXME: we should not need a function for every constant.
foreach my $constant (@{$interface->constants}) {
my $name = $constant->name;
- push(@hashKeys, $name);
- my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name);
- push(@hashValue1, $getter);
- push(@hashValue2, "0");
- push(@hashSpecials, "DontDelete | ReadOnly");
-
- my $conditional = $constant->extendedAttributes->{"Conditional"};
- if ($conditional) {
- $conditionals{$name} = $conditional;
- }
- }
- foreach my $function (@{$interface->functions}) {
- next if ($function->isStatic);
- next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
- my $name = $function->signature->name;
push(@hashKeys, $name);
+ push(@hashValue1, $constant->value);
+ push(@hashValue2, "0");
+ push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
- my $functionName = GetFunctionName($className, $function);
- push(@hashValue1, $functionName);
-
- my $functionLength = GetFunctionLength($function);
- push(@hashValue2, $functionLength);
-
- my @specials = ();
- push(@specials, "DontDelete") if $interface->extendedAttributes->{"OperationsNotDeletable"}
- || $function->signature->extendedAttributes->{"NotDeletable"};
- push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"};
- push(@specials, "JSC::Function");
- my $special = (@specials > 0) ? join(" | ", @specials) : "0";
- push(@hashSpecials, $special);
+ my $conditional = $constant->extendedAttributes->{Conditional};
+ $conditionals{$name} = $conditional if $conditional;
- my $conditional = $function->signature->extendedAttributes->{"Conditional"};
- if ($conditional) {
- $conditionals{$name} = $conditional;
- }
+ $hashSize++;
}
+ my $justGenerateValueArray = !IsDOMGlobalObject($interface);
+
$object->GenerateHashTable($hashName, $hashSize,
\@hashKeys, \@hashSpecials,
\@hashValue1, \@hashValue2,
- \%conditionals);
+ \%conditionals, $justGenerateValueArray);
- if ($interface->extendedAttributes->{"JSNoStaticTables"}) {
- push(@implContent, "static const HashTable& get${className}PrototypeTable(VM& vm)\n");
- push(@implContent, "{\n");
- push(@implContent, " return getHashTableForGlobalData(vm, ${className}PrototypeTable);\n");
- push(@implContent, "}\n\n");
- push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, 0, get${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
+ if ($justGenerateValueArray) {
+ push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
} else {
- push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, &${className}PrototypeTable, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
- }
- unless (IsDOMGlobalObject($interface)) {
- push(@implContent, "JSObject* ${className}Prototype::self(VM& vm, JSGlobalObject* globalObject)\n");
- push(@implContent, "{\n");
- push(@implContent, " return getDOMPrototype<${className}>(vm, globalObject);\n");
- push(@implContent, "}\n\n");
+ push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, &${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
}
- if (PrototypeOverridesGetOwnPropertySlot($interface)) {
- push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
+ if (PrototypeHasStaticPropertyTable($interface) && !IsGlobalOrPrimaryGlobalInterface($interface)) {
+ push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
push(@implContent, "{\n");
- push(@implContent, " ${className}Prototype* thisObject = jsCast<${className}Prototype*>(object);\n");
-
- if ($numConstants eq 0 && $numFunctions eq 0) {
- push(@implContent, " return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");
- } elsif ($numConstants eq 0) {
- push(@implContent, " return getStaticFunctionSlot<JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
- } elsif ($numFunctions eq 0) {
- push(@implContent, " return getStaticValueSlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
- } else {
- push(@implContent, " return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
+ push(@implContent, " Base::finishCreation(vm);\n");
+ push(@implContent, " reifyStaticProperties(vm, ${className}PrototypeTableValues, *this);\n");
+
+ my @runtimeEnabledProperties = @runtimeEnabledFunctions;
+ push(@runtimeEnabledProperties, @runtimeEnabledAttributes);
+ foreach my $functionOrAttribute (@runtimeEnabledProperties) {
+ my $conditionalString = $codeGenerator->GenerateConditionalString($functionOrAttribute);
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ AddToImplIncludes("RuntimeEnabledFeatures.h");
+ my $enable_function = GetRuntimeEnableFunctionName($functionOrAttribute);
+ my $name = $functionOrAttribute->name;
+ push(@implContent, " if (!${enable_function}()) {\n");
+ push(@implContent, " Identifier propertyName = Identifier::fromString(&vm, reinterpret_cast<const LChar*>(\"$name\"), strlen(\"$name\"));\n");
+ push(@implContent, " VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);\n");
+ push(@implContent, " JSObject::deleteProperty(this, globalObject()->globalExec(), propertyName);\n");
+ push(@implContent, " }\n");
+ push(@implContent, "#endif\n") if $conditionalString;
}
- push(@implContent, "}\n\n");
- }
- if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {
- push(@implContent, "void ${className}Prototype::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}Prototype* thisObject = jsCast<${className}Prototype*>(cell);\n");
- push(@implContent, " if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
- push(@implContent, " return;\n");
- push(@implContent, " Base::put(thisObject, exec, propertyName, value, slot);\n");
+ foreach my $function (@{$interface->functions}) {
+ next unless ($function->extendedAttributes->{PrivateIdentifier});
+ AddToImplIncludes("WebCoreJSClientData.h");
+ my $conditionalString = $codeGenerator->GenerateConditionalString($function);
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ push(@implContent, " putDirect(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames()." . $function->name . "PrivateName(), JSFunction::create(vm, globalObject(), 0, String(), " . GetFunctionName($interface, $className, $function) . "), ReadOnly | DontEnum);\n");
+ push(@implContent, "#endif\n") if $conditionalString;
+ }
+
+ if (InterfaceNeedsIterator($interface)) {
+ if (IsKeyValueIterableInterface($interface)) {
+ my $functionName = GetFunctionName($interface, $className, @{$interface->iterable->functions}[0]);
+ push(@implContent, " putDirect(vm, vm.propertyNames->iteratorSymbol, JSFunction::create(vm, globalObject(), 0, ASCIILiteral(\"[Symbol.Iterator]\"), $functionName), DontEnum);\n");
+ } else {
+ AddToImplIncludes("<builtins/BuiltinNames.h>");
+ push(@implContent, " putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayPrototype()->getDirect(vm, vm.propertyNames->builtinNames().valuesPrivateName()), DontEnum);\n");
+ }
+ }
+ push(@implContent, " addValueIterableMethods(*globalObject(), *this);\n") if $interface->iterable and !IsKeyValueIterableInterface($interface);
+
+ addUnscopableProperties($interface);
+
push(@implContent, "}\n\n");
}
- # - Initialize static ClassInfo object
- if ($numAttributes > 0 && $interface->extendedAttributes->{"JSNoStaticTables"}) {
- push(@implContent, "static const HashTable& get${className}Table(VM& vm)\n");
+ if ($interface->extendedAttributes->{JSCustomNamedGetterOnPrototype}) {
+ push(@implContent, "bool ${className}Prototype::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
push(@implContent, "{\n");
- push(@implContent, " return getHashTableForGlobalData(vm, ${className}Table);\n");
+ push(@implContent, " auto* thisObject = jsCast<${className}Prototype*>(cell);\n");
+ push(@implContent, " bool putResult = false;\n");
+ push(@implContent, " if (thisObject->putDelegate(state, propertyName, value, slot, putResult))\n");
+ push(@implContent, " return putResult;\n");
+ push(@implContent, " return Base::put(thisObject, state, propertyName, value, slot);\n");
push(@implContent, "}\n\n");
}
+ # - Initialize static ClassInfo object
push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleInterfaceName}\", &Base::s_info, ");
- if ($numAttributes > 0 && !$interface->extendedAttributes->{"JSNoStaticTables"}) {
+ if ($numInstanceProperties > 0) {
push(@implContent, "&${className}Table");
} else {
push(@implContent, "0");
}
- if ($numAttributes > 0 && $interface->extendedAttributes->{"JSNoStaticTables"}) {
- push(@implContent, ", get${className}Table ");
- } else {
- push(@implContent, ", 0 ");
- }
push(@implContent, ", CREATE_METHOD_TABLE($className) };\n\n");
- my $implType = $interfaceName;
- my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
- $implType = $svgNativeType if $svgNativeType;
-
- my $svgPropertyOrListPropertyType;
- $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
- $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
-
# Constructor
if ($interfaceName eq "DOMWindow") {
- AddIncludesForTypeInImpl("JSDOMWindowShell");
- push(@implContent, "${className}::$className(VM& vm, Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n");
- push(@implContent, " : $parentClassName(vm, structure, impl, shell)\n");
+ AddIncludesForImplementationTypeInImpl("JSDOMWindowShell");
+ push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl, JSDOMWindowShell* shell)\n");
+ push(@implContent, " : $parentClassName(vm, structure, WTFMove(impl), shell)\n");
push(@implContent, "{\n");
push(@implContent, "}\n\n");
} elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
- AddIncludesForTypeInImpl($interfaceName);
- push(@implContent, "${className}::$className(VM& vm, Structure* structure, PassRefPtr<$implType> impl)\n");
- push(@implContent, " : $parentClassName(vm, structure, impl)\n");
+ AddIncludesForImplementationTypeInImpl($interfaceName);
+ push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl)\n");
+ push(@implContent, " : $parentClassName(vm, structure, WTFMove(impl))\n");
push(@implContent, "{\n");
push(@implContent, "}\n\n");
+ } elsif (!NeedsImplementationClass($interface)) {
+ push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject& globalObject)\n");
+ push(@implContent, " : $parentClassName(structure, globalObject) { }\n\n");
} else {
- push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
- if ($hasParent) {
- push(@implContent, " : $parentClassName(structure, globalObject, impl)\n");
- } else {
- push(@implContent, " : $parentClassName(structure, globalObject)\n");
- push(@implContent, " , m_impl(impl.leakRef())\n");
- }
+ push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject& globalObject, Ref<$implType>&& impl)\n");
+ push(@implContent, " : $parentClassName(structure, globalObject, WTFMove(impl))\n");
push(@implContent, "{\n");
push(@implContent, "}\n\n");
+ }
+ if ($interfaceName eq "DOMWindow") {
+ push(@implContent, "void ${className}::finishCreation(VM& vm, JSDOMWindowShell* shell)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " Base::finishCreation(vm, shell);\n\n");
+ } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
+ push(@implContent, "void ${className}::finishCreation(VM& vm, JSProxy* proxy)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " Base::finishCreation(vm, proxy);\n\n");
+ } else {
push(@implContent, "void ${className}::finishCreation(VM& vm)\n");
push(@implContent, "{\n");
push(@implContent, " Base::finishCreation(vm);\n");
- push(@implContent, " ASSERT(inherits(info()));\n");
- push(@implContent, "}\n\n");
+ push(@implContent, " ASSERT(inherits(vm, info()));\n\n");
+ }
+
+ if ($interfaceName eq "Location") {
+ push(@implContent, " putDirect(vm, vm.propertyNames->valueOf, globalObject()->objectProtoValueOfFunction(), DontDelete | ReadOnly | DontEnum);\n");
+ push(@implContent, " putDirect(vm, vm.propertyNames->toPrimitiveSymbol, jsUndefined(), DontDelete | ReadOnly | DontEnum);\n");
}
- unless (IsDOMGlobalObject($interface)) {
+ # Support for RuntimeEnabled attributes on instances.
+ foreach my $attribute (@{$interface->attributes}) {
+ next unless NeedsRuntimeCheck($attribute);
+ next unless AttributeShouldBeOnInstance($interface, $attribute);
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ my $enable_function = GetRuntimeEnableFunctionName($attribute);
+ my $attributeName = $attribute->name;
+ push(@implContent, " if (${enable_function}()) {\n");
+ my $getter = GetAttributeGetterName($interface, $className, $attribute);
+ my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interface, $className, $attribute);
+ push(@implContent, " auto* customGetterSetter = CustomGetterSetter::create(vm, $getter, $setter);\n");
+ my $jscAttributes = GetJSCAttributesForAttribute($interface, $attribute);
+ push(@implContent, " putDirectCustomAccessor(vm, vm.propertyNames->$attributeName, customGetterSetter, attributesForStructure($jscAttributes));\n");
+ push(@implContent, " }\n");
+ push(@implContent, "#endif\n") if $conditionalString;
+ }
+
+ # Support PrivateIdentifier attributes on instances.
+ foreach my $attribute (@{$interface->attributes}) {
+ next unless $attribute->extendedAttributes->{PrivateIdentifier};
+ next unless AttributeShouldBeOnInstance($interface, $attribute);
+
+ AddToImplIncludes("WebCoreJSClientData.h");
+ my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
+ my $attributeName = $attribute->name;
+ my $getter = GetAttributeGetterName($interface, $className, $attribute);
+
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ push(@implContent, " putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames()." . $attributeName . "PrivateName(), CustomGetterSetter::create(vm, $getter, nullptr), attributesForStructure(DontDelete | ReadOnly));\n");
+ push(@implContent, "#endif\n") if $conditionalString;
+ }
+
+ # Support for RuntimeEnabled operations on instances.
+ foreach my $function (@{$interface->functions}) {
+ next unless NeedsRuntimeCheck($function);
+ next unless OperationShouldBeOnInstance($interface, $function);
+ next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($function);
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+ my $enable_function = GetRuntimeEnableFunctionName($function);
+ my $functionName = $function->name;
+ my $implementationFunction = GetFunctionName($interface, $className, $function);
+ my $functionLength = GetFunctionLength($function);
+ my $jsAttributes = ComputeFunctionSpecial($interface, $function);
+ push(@implContent, " if (${enable_function}())\n");
+
+ my $propertyName = "vm.propertyNames->$functionName";
+ $propertyName = "static_cast<JSVMClientData*>(vm.clientData)->builtinNames()." . $functionName . "PrivateName()" if $function->extendedAttributes->{PrivateIdentifier};
+ if (IsJSBuiltin($interface, $function)) {
+ push(@implContent, " putDirectBuiltinFunction(vm, this, $propertyName, $implementationFunction(vm), attributesForStructure($jsAttributes));\n");
+ } else {
+ push(@implContent, " putDirectNativeFunction(vm, this, $propertyName, $functionLength, $implementationFunction, NoIntrinsic, attributesForStructure($jsAttributes));\n");
+ }
+ push(@implContent, "#endif\n") if $conditionalString;
+ }
+ push(@implContent, "}\n\n");
+
+ unless (ShouldUseGlobalObjectPrototype($interface)) {
push(@implContent, "JSObject* ${className}::createPrototype(VM& vm, JSGlobalObject* globalObject)\n");
push(@implContent, "{\n");
- if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") {
- push(@implContent, " return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, ${parentClassName}Prototype::self(vm, globalObject)));\n");
+ if ($interface->parentType) {
+ my $parentClassNameForPrototype = "JS" . $interface->parentType->name;
+ push(@implContent, " return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, ${parentClassNameForPrototype}::prototype(vm, globalObject)));\n");
} else {
my $prototype = $interface->isException ? "errorPrototype" : "objectPrototype";
push(@implContent, " return ${className}Prototype::create(vm, globalObject, ${className}Prototype::createStructure(vm, globalObject, globalObject->${prototype}()));\n");
}
push(@implContent, "}\n\n");
+
+ push(@implContent, "JSObject* ${className}::prototype(VM& vm, JSGlobalObject* globalObject)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " return getDOMPrototype<${className}>(vm, globalObject);\n");
+ push(@implContent, "}\n\n");
}
if (!$hasParent) {
- # FIXME: This destroy function should not be necessary, as
- # a finalizer should be called for each DOM object wrapper.
- # However, that seems not to be the case, so this has been
- # added back to avoid leaking while we figure out why the
- # finalizers are not always getting called. The work tracking
- # the finalizer issue is being tracked in http://webkit.org/b/75451
push(@implContent, "void ${className}::destroy(JSC::JSCell* cell)\n");
push(@implContent, "{\n");
push(@implContent, " ${className}* thisObject = static_cast<${className}*>(cell);\n");
push(@implContent, " thisObject->${className}::~${className}();\n");
push(@implContent, "}\n\n");
-
- # We also need a destructor for the allocateCell to work properly with the destructor-free part of the heap.
- # Otherwise, these destroy functions/destructors won't get called.
- push(@implContent, "${className}::~${className}()\n");
- push(@implContent, "{\n");
- push(@implContent, " releaseImplIfNotNull();\n");
- push(@implContent, "}\n\n");
}
my $hasGetter = InstanceOverridesGetOwnPropertySlot($interface);
# Attributes
if ($hasGetter) {
- if (!$interface->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
- push(@implContent, "bool ${className}::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}* thisObject = jsCast<${className}*>(object);\n");
- push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
- push(@implContent, GenerateGetOwnPropertySlotBody($interface, $interfaceName, $className, $numAttributes > 0, 0));
- push(@implContent, "}\n\n");
+ if (!$interface->extendedAttributes->{CustomGetOwnPropertySlot}) {
+ push(@implContent, GenerateGetOwnPropertySlotBody($interface, $className, $indexedGetterFunction, $namedGetterFunction));
}
if ($indexedGetterFunction || $namedGetterFunction
- || $interface->extendedAttributes->{"CustomNamedGetter"}
- || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
- push(@implContent, "bool ${className}::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}* thisObject = jsCast<${className}*>(object);\n");
- push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
+ || $interface->extendedAttributes->{CustomNamedGetter}
+ || $interface->extendedAttributes->{JSCustomGetOwnPropertySlotAndDescriptor}) {
+ push(@implContent, GenerateGetOwnPropertySlotBodyByIndex($interface, $className, $indexedGetterFunction, $namedGetterFunction));
+ }
- # Sink the int-to-string conversion that happens when we create a PropertyName
- # to the point where we actually need it.
- my $generatedPropertyName = 0;
- my $propertyNameGeneration = sub {
- if ($generatedPropertyName) {
- return;
- }
- push(@implContent, " PropertyName propertyName = Identifier::from(exec, index);\n");
- $generatedPropertyName = 1;
- };
+ }
- if ($indexedGetterFunction) {
- if ($indexedGetterFunction->signature->type eq "DOMString") {
- push(@implContent, " if (index <= MAX_ARRAY_INDEX) {\n");
- } else {
- push(@implContent, " if (index < thisObject->impl().length()) {\n");
- }
- # Assume that if there's a setter, the index will be writable
- if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
- push(@implContent, " unsigned attributes = DontDelete;\n");
- } else {
- push(@implContent, " unsigned attributes = DontDelete | ReadOnly;\n");
- }
- if ($hasNumericIndexedGetter) {
- push(@implContent, " slot.setValue(thisObject, attributes, thisObject->getByIndex(exec, index));\n");
- } else {
- push(@implContent, " slot.setCustomIndex(thisObject, attributes, index, thisObject->indexGetter);\n");
- }
- push(@implContent, " return true;\n");
- push(@implContent, " }\n");
- }
- if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
- &$propertyNameGeneration();
- push(@implContent, " if (canGetItemsForName(exec, &thisObject->impl(), propertyName)) {\n");
- push(@implContent, " slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);\n");
- push(@implContent, " return true;\n");
- push(@implContent, " }\n");
- $implIncludes{"wtf/text/AtomicString.h"} = 1;
- }
+ if (($indexedGetterFunction || $namedGetterFunction) && !$interface->extendedAttributes->{CustomEnumerateProperty}) {
+ push(@implContent, GenerateGetOwnPropertyNames($interface, $className, $indexedGetterFunction, $namedGetterFunction));
+ }
- if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) {
- &$propertyNameGeneration();
- push(@implContent, " if (thisObject->getOwnPropertySlotDelegate(exec, propertyName, slot))\n");
- push(@implContent, " return true;\n");
+ my $namedSetterFunction = GetNamedSetterFunction($interface);
+ my $indexedSetterFunction = GetIndexedSetterFunction($interface);
+
+ my $hasSetter = InstanceOverridesPut($interface);
+ if ($hasSetter) {
+ if (!$interface->extendedAttributes->{CustomPutFunction}) {
+ push(@implContent, GeneratePut($interface, $className, $indexedSetterFunction, $namedSetterFunction));
+
+ if ($interface->extendedAttributes->{CustomIndexedSetter} || $interface->extendedAttributes->{CustomNamedSetter}) {
+ push(@implContent, GeneratePutByIndex($interface, $className, $indexedSetterFunction, $namedSetterFunction));
}
+ }
+ }
- push(@implContent, " return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot);\n");
+ if ($numAttributes > 0) {
+ my $castingFunction = $interface->extendedAttributes->{"CustomProxyToJSObject"} ? "to${className}" : GetCastingHelperForThisObject($interface);
+ # FIXME: Remove ImplicitThis keyword as it is no longer defined by WebIDL spec and is only used in DOMWindow.
+ if ($interface->extendedAttributes->{"ImplicitThis"}) {
+ push(@implContent, "template<> inline ${className}* BindingCaller<${className}>::castForAttribute(ExecState& state, EncodedJSValue thisValue)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " auto decodedThisValue = JSValue::decode(thisValue);\n");
+ push(@implContent, " if (decodedThisValue.isUndefinedOrNull())\n");
+ push(@implContent, " decodedThisValue = state.thisValue().toThis(&state, NotStrictMode);\n");
+ push(@implContent, " return $castingFunction(state.vm(), decodedThisValue);");
+ push(@implContent, "}\n\n");
+ } else {
+ push(@implContent, "template<> inline ${className}* BindingCaller<${className}>::castForAttribute(ExecState& state, EncodedJSValue thisValue)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " return $castingFunction(state.vm(), JSValue::decode(thisValue));\n");
push(@implContent, "}\n\n");
}
+ }
+ if ($numFunctions > 0 && $interfaceName ne "EventTarget") {
+ # FIXME: Make consistent castForAttibute and castForOperation in case of CustomProxyToJSObject.
+ my $castingFunction = $interface->extendedAttributes->{"CustomProxyToJSObject"} ? "to${className}" : GetCastingHelperForThisObject($interface);
+ my $thisValue = $interface->extendedAttributes->{"CustomProxyToJSObject"} ? "state.thisValue().toThis(&state, NotStrictMode)" : "state.thisValue()";
+ push(@implContent, "template<> inline ${className}* BindingCaller<${className}>::castForOperation(ExecState& state)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " return $castingFunction(state.vm(), $thisValue);\n");
+ push(@implContent, "}\n\n");
}
+
+ $numAttributes = $numAttributes + 1 if NeedsConstructorProperty($interface);
if ($numAttributes > 0) {
foreach my $attribute (@{$interface->attributes}) {
- my $name = $attribute->signature->name;
- my $type = $attribute->signature->type;
- my $isNullable = $attribute->signature->isNullable;
- $codeGenerator->AssertNotSequenceType($type);
- my $getFunctionName = GetAttributeGetterName($interfaceName, $className, $attribute);
- my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->extendedAttributes->{"ImplementedAs"} || $name);
-
- my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
- push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
+ next if IsJSBuiltin($interface, $attribute);
- push(@implContent, "EncodedJSValue ${getFunctionName}(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue thisValue, PropertyName)\n");
- push(@implContent, "{\n");
+ my $name = $attribute->name;
+ my $type = $attribute->type;
+ my $getFunctionName = GetAttributeGetterName($interface, $className, $attribute);
+ my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->extendedAttributes->{ImplementedAs} || $name);
- if (!$attribute->isStatic || $attribute->signature->type =~ /Constructor$/) {
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " ${className}* castedThis = jsCast<$className*>(JSValue::decode(slotBase));\n");
- push(@implContent, " UNUSED_PARAM(thisValue);\n");
- } else {
- push(@implContent, " ${className}* castedThis = jsDynamicCast<$className*>(JSValue::decode(thisValue));\n");
- push(@implContent, " UNUSED_PARAM(slotBase);\n");
- push(@implContent, " if (!castedThis)\n");
- push(@implContent, " return throwVMTypeError(exec);\n");
+ my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute);
+ push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
+
+ if (!$attribute->isStatic || $codeGenerator->IsConstructorType($type)) {
+ my $templateParameters = "${getFunctionName}Getter";
+ if ($attribute->extendedAttributes->{LenientThis}) {
+ $templateParameters .= ", CastedThisErrorBehavior::ReturnEarly";
+ } elsif (IsReturningPromise($attribute)) {
+ $templateParameters .= ", CastedThisErrorBehavior::RejectPromise";
}
+
+ push(@implContent, "static inline JSValue ${getFunctionName}Getter(ExecState&, ${className}&, ThrowScope& throwScope);\n\n");
+
+ push(@implContent, "EncodedJSValue ${getFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " return BindingCaller<${className}>::attribute<${templateParameters}>(state, thisValue, \"$name\");\n");
+ push(@implContent, "}\n\n");
+
+ push(@implContent, "static inline JSValue ${getFunctionName}Getter(ExecState& state, ${className}& thisObject, ThrowScope& throwScope)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " UNUSED_PARAM(throwScope);\n");
} else {
- push(@implContent, " UNUSED_PARAM(thisValue);\n");
- push(@implContent, " UNUSED_PARAM(slotBase);\n");
+ push(@implContent, "static inline JSValue ${getFunctionName}Getter(ExecState&);\n\n");
+
+ push(@implContent, "EncodedJSValue ${getFunctionName}(ExecState* state, EncodedJSValue, PropertyName)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " ASSERT(state);\n");
+ push(@implContent, " return JSValue::encode(${getFunctionName}Getter(*state));\n");
+ push(@implContent, "}\n\n");
+
+ push(@implContent, "static inline JSValue ${getFunctionName}Getter(ExecState& state)\n");
+ push(@implContent, "{\n");
}
+ push(@implContent, " UNUSED_PARAM(state);\n");
# Global constructors can be disabled at runtime.
- if ($attribute->signature->type =~ /Constructor$/) {
- if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
- AddToImplIncludes("RuntimeEnabledFeatures.h");
- my $enable_function = GetRuntimeEnableFunctionName($attribute->signature);
- push(@implContent, " if (!${enable_function}())\n");
- push(@implContent, " return JSValue::encode(jsUndefined());\n");
- } elsif ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) {
+ if ($codeGenerator->IsConstructorType($type)) {
+ if ($attribute->extendedAttributes->{EnabledBySetting}) {
AddToImplIncludes("Frame.h");
AddToImplIncludes("Settings.h");
- my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{"EnabledBySetting"}) . "Enabled";
- push(@implContent, " if (!castedThis->impl().frame())\n");
- push(@implContent, " return JSValue::encode(jsUndefined());\n");
- push(@implContent, " Settings& settings = castedThis->impl().frame()->settings();\n");
+ my $enable_function = ToMethodName($attribute->extendedAttributes->{EnabledBySetting}) . "Enabled";
+ push(@implContent, " if (UNLIKELY(!thisObject.wrapped().frame()))\n");
+ push(@implContent, " return jsUndefined();\n");
+ push(@implContent, " Settings& settings = thisObject.wrapped().frame()->settings();\n");
push(@implContent, " if (!settings.$enable_function())\n");
- push(@implContent, " return JSValue::encode(jsUndefined());\n");
+ push(@implContent, " return jsUndefined();\n");
}
}
- if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
- $needsMarkChildren = 1;
- }
-
- if ($interface->extendedAttributes->{"CheckSecurity"} &&
- !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"} &&
- !$attribute->signature->extendedAttributes->{"DoNotCheckSecurityOnGetter"}) {
- push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
- push(@implContent, " return JSValue::encode(jsUndefined());\n");
- }
+ $needsVisitChildren = 1 if $attribute->extendedAttributes->{CachedAttribute};
- if (HasCustomGetter($attribute->signature->extendedAttributes)) {
- push(@implContent, " return JSValue::encode(castedThis->$implGetterFunctionName(exec));\n");
- } elsif ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
- $implIncludes{"JSDOMBinding.h"} = 1;
- push(@implContent, " $interfaceName& impl = castedThis->impl();\n");
- push(@implContent, " return JSValue::encode(shouldAllowAccessToNode(exec, impl." . $attribute->signature->name . "()) ? " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName()", "castedThis") . " : jsNull());\n");
- } elsif ($type eq "EventListener") {
- $implIncludes{"EventListener.h"} = 1;
- push(@implContent, " UNUSED_PARAM(exec);\n");
- push(@implContent, " $interfaceName& impl = castedThis->impl();\n");
- push(@implContent, " if (EventListener* listener = impl.$implGetterFunctionName()) {\n");
- push(@implContent, " if (const JSEventListener* jsListener = JSEventListener::cast(listener)) {\n");
- if ($interfaceName eq "Document" || $codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
- push(@implContent, " if (JSObject* jsFunction = jsListener->jsFunction(&impl))\n");
+ if ($interface->extendedAttributes->{CheckSecurity} &&
+ !$attribute->extendedAttributes->{DoNotCheckSecurity} &&
+ !$attribute->extendedAttributes->{DoNotCheckSecurityOnGetter}) {
+ AddToImplIncludes("JSDOMBindingSecurity.h");
+ if ($interfaceName eq "DOMWindow") {
+ push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(&state, thisObject.wrapped(), ThrowSecurityError))\n");
} else {
- push(@implContent, " if (JSObject* jsFunction = jsListener->jsFunction(impl.scriptExecutionContext()))\n");
+ push(@implContent, " if (!BindingSecurity::shouldAllowAccessToFrame(&state, thisObject.wrapped().frame(), ThrowSecurityError))\n");
}
- push(@implContent, " return JSValue::encode(jsFunction);\n");
- push(@implContent, " }\n");
- push(@implContent, " }\n");
- push(@implContent, " return JSValue::encode(jsNull());\n");
- } elsif ($attribute->signature->type =~ /Constructor$/) {
- my $constructorType = $attribute->signature->type;
+ push(@implContent, " return jsUndefined();\n");
+ }
+
+ if (HasCustomGetter($attribute->extendedAttributes)) {
+ push(@implContent, " return thisObject.$implGetterFunctionName(state);\n");
+ } elsif ($type->name eq "EventHandler") {
+ $implIncludes{"EventNames.h"} = 1;
+ my $getter = $attribute->extendedAttributes->{WindowEventHandler} ? "windowEventHandlerAttribute"
+ : $attribute->extendedAttributes->{DocumentEventHandler} ? "documentEventHandlerAttribute"
+ : "eventHandlerAttribute";
+ my $eventName = EventHandlerAttributeEventName($attribute);
+ push(@implContent, " return $getter(thisObject.wrapped(), $eventName, worldForDOMObject(&thisObject));\n");
+ } elsif ($codeGenerator->IsConstructorType($attribute->type)) {
+ my $constructorType = $attribute->type->name;
$constructorType =~ s/Constructor$//;
- # When Constructor attribute is used by DOMWindow.idl, it's correct to pass castedThis as the global object
- # When JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject()
+ # When Constructor attribute is used by DOMWindow.idl, it's correct to pass thisObject as the global object
+ # When JSDOMWrappers have a back-pointer to the globalObject we can pass thisObject->globalObject()
if ($interfaceName eq "DOMWindow") {
my $named = ($constructorType =~ /Named$/) ? "Named" : "";
$constructorType =~ s/Named$//;
- push(@implContent, " return JSValue::encode(JS" . $constructorType . "::get${named}Constructor(exec->vm(), castedThis));\n");
+ push(@implContent, " return JS" . $constructorType . "::get${named}Constructor(state.vm(), &thisObject);\n");
} else {
- AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
- push(@implContent, " return JSValue::encode(JS" . $constructorType . "::getConstructor(exec->vm(), castedThis->globalObject()));\n");
- }
- } elsif (!$attribute->signature->extendedAttributes->{"GetterRaisesException"}) {
- push(@implContent, " UNUSED_PARAM(exec);\n") if !$attribute->signature->extendedAttributes->{"CallWith"};
- push(@implContent, " bool isNull = false;\n") if $isNullable;
-
- my $cacheIndex = 0;
- if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
- $cacheIndex = $currentCachedAttribute;
- $currentCachedAttribute++;
- push(@implContent, " if (JSValue cachedValue = castedThis->m_" . $attribute->signature->name . ".get())\n");
- push(@implContent, " return JSValue::encode(cachedValue);\n");
+ AddToImplIncludes("JS" . $constructorType . ".h", $attribute->extendedAttributes->{Conditional});
+ push(@implContent, " return JS" . $constructorType . "::getConstructor(state.vm(), thisObject.globalObject());\n");
}
-
- my @callWithArgs = GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "JSValue::encode(jsUndefined())");
-
- if ($svgListPropertyType) {
- push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "castedThis->impl().$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
- } elsif ($svgPropertyOrListPropertyType) {
- push(@implContent, " $svgPropertyOrListPropertyType& impl = castedThis->impl().propertyReference();\n");
- if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
- push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl", "castedThis") . ";\n");
- } else {
- push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n");
-
- }
- } else {
- my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
- push(@arguments, "isNull") if $isNullable;
- if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
- my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
- $implIncludes{"${implementedBy}.h"} = 1;
- $functionName = "${implementedBy}::${functionName}";
- unshift(@arguments, "&impl") if !$attribute->isStatic;
- } elsif ($attribute->isStatic) {
- $functionName = "${interfaceName}::${functionName}";
- } else {
- $functionName = "impl.${functionName}";
- }
-
- unshift(@arguments, @callWithArgs);
- my $jsType = NativeToJSValue($attribute->signature, 0, $interfaceName, "${functionName}(" . join(", ", @arguments) . ")", "castedThis");
- push(@implContent, " $interfaceName& impl = castedThis->impl();\n") if !$attribute->isStatic;
- if ($codeGenerator->IsSVGAnimatedType($type)) {
- push(@implContent, " RefPtr<$type> obj = $jsType;\n");
- push(@implContent, " JSValue result = toJS(exec, castedThis->globalObject(), obj.get());\n");
- } else {
- push(@implContent, " JSValue result = $jsType;\n");
- }
-
- if ($isNullable) {
- push(@implContent, " if (isNull)\n");
- push(@implContent, " return JSValue::encode(jsNull());\n");
- }
- }
-
- push(@implContent, " castedThis->m_" . $attribute->signature->name . ".set(exec->vm(), castedThis, result);\n") if ($attribute->signature->extendedAttributes->{"CachedAttribute"});
- push(@implContent, " return JSValue::encode(result);\n");
-
} else {
- my @arguments = ("ec");
- push(@implContent, " ExceptionCode ec = 0;\n");
-
- if ($isNullable) {
- push(@implContent, " bool isNull = false;\n");
- unshift(@arguments, "isNull");
+ if ($attribute->extendedAttributes->{CachedAttribute}) {
+ push(@implContent, " if (JSValue cachedValue = thisObject.m_" . $attribute->name . ".get())\n");
+ push(@implContent, " return cachedValue;\n");
}
- unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "JSValue::encode(jsUndefined())"));
+ my @callWithArgs = GenerateCallWithUsingReferences($attribute->extendedAttributes->{CallWith}, \@implContent, "jsUndefined()");
- if ($svgPropertyOrListPropertyType) {
- push(@implContent, " $svgPropertyOrListPropertyType impl(*castedThis->impl());\n");
- push(@implContent, " JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
+ my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
+ my $implementedBy = $attribute->extendedAttributes->{ImplementedBy};
+ if ($implementedBy) {
+ $implIncludes{"${implementedBy}.h"} = 1;
+ $functionName = "WebCore::${implementedBy}::${functionName}";
+ unshift(@arguments, "impl") if !$attribute->isStatic;
+ } elsif ($attribute->isStatic) {
+ $functionName = "${interfaceName}::${functionName}";
} else {
- push(@implContent, " $interfaceName& impl = castedThis->impl();\n");
- push(@implContent, " JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
+ $functionName = "impl.${functionName}";
}
- if ($isNullable) {
- push(@implContent, " if (isNull)\n");
- push(@implContent, " return JSValue::encode(jsNull());\n");
- }
+ unshift(@arguments, @callWithArgs);
+ my $jsType = NativeToJSValueUsingReferences($attribute, $interface, "${functionName}(" . join(", ", @arguments) . ")", "thisObject");
+ push(@implContent, " auto& impl = thisObject.wrapped();\n") if !$attribute->isStatic;
+ push(@implContent, " JSValue result = $jsType;\n");
- push(@implContent, " setDOMException(exec, ec);\n");
- push(@implContent, " return JSValue::encode(result);\n");
+ push(@implContent, " thisObject.m_" . $attribute->name . ".set(state.vm(), &thisObject, result);\n") if $attribute->extendedAttributes->{CachedAttribute};
+ push(@implContent, " return result;\n");
}
push(@implContent, "}\n\n");
- push(@implContent, "#endif\n") if $attributeConditionalString;
+ if ($attribute->extendedAttributes->{"DOMJIT"}) {
+ assert("Only DOMJIT=Getter is supported for attributes") unless $codeGenerator->ExtendedAttributeContains($attribute->extendedAttributes->{DOMJIT}, "Getter");
+
+ $implIncludes{"<wtf/NeverDestroyed.h>"} = 1;
+ $implIncludes{"DOMJITIDLTypeFilter.h"} = 1;
+ my $generatorName = $interface->type->name . $codeGenerator->WK_ucfirst($attribute->name);
+ my $domJITClassName = $generatorName . "DOMJIT";
+ my $getter = GetAttributeGetterName($interface, $generatorName, $attribute);
+ my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interface, $generatorName, $attribute);
+ my $resultType = GetResultTypeFilter($interface, $attribute->type);
+ push(@implContent, "${domJITClassName}::${domJITClassName}()\n");
+ push(@implContent, " : JSC::DOMJIT::GetterSetter($getter, $setter, ${className}::info(), $resultType)\n");
+ push(@implContent, "{\n");
+ push(@implContent, "}\n\n");
- push(@implContent, "\n");
+ push(@implContent, "JSC::DOMJIT::GetterSetter* domJITGetterSetterFor" . $generatorName . "()\n");
+ push(@implContent, "{\n");
+ push(@implContent, " static NeverDestroyed<${domJITClassName}> compiler;\n");
+ push(@implContent, " return &compiler.get();\n");
+ push(@implContent, "}\n\n");
+ }
+
+ push(@implContent, "#endif\n\n") if $attributeConditionalString;
}
- if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
+ if (NeedsConstructorProperty($interface)) {
my $constructorFunctionName = "js" . $interfaceName . "Constructor";
- push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue, PropertyName)\n");
+ push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
push(@implContent, "{\n");
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " ${className}* domObject = jsDynamicCast<$className*>(JSValue::decode(thisValue));\n");
- push(@implContent, " if (!domObject) {\n");
- push(@implContent, " if (JSDOMWindowShell* shell = jsDynamicCast<JSDOMWindowShell*>(JSValue::decode(thisValue)))\n");
- push(@implContent, " domObject = shell->window();\n");
- push(@implContent, " }\n");
+ push(@implContent, " VM& vm = state->vm();\n");
+ push(@implContent, " auto throwScope = DECLARE_THROW_SCOPE(vm);\n");
+ push(@implContent, " ${className}Prototype* domObject = jsDynamicDowncast<${className}Prototype*>(vm, JSValue::decode(thisValue));\n");
+ push(@implContent, " if (UNLIKELY(!domObject))\n");
+ push(@implContent, " return throwVMTypeError(state, throwScope);\n");
+
+ if (!$interface->extendedAttributes->{NoInterfaceObject}) {
+ push(@implContent, " return JSValue::encode(${className}::getConstructor(state->vm(), domObject->globalObject()));\n");
} else {
- push(@implContent, " ${className}* domObject = jsDynamicCast<$className*>(JSValue::decode(thisValue));\n");
- push(@implContent, " if (!domObject)\n");
- push(@implContent, " return throwVMTypeError(exec);\n");
- }
- push(@implContent, " if (!domObject)\n");
- push(@implContent, " return throwVMTypeError(exec);\n");
-
- if ($interface->extendedAttributes->{"CheckSecurity"}) {
- push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, domObject->impl()))\n");
- push(@implContent, " return JSValue::encode(jsUndefined());\n");
+ push(@implContent, " JSValue constructor = ${className}Constructor::create(state->vm(), ${className}Constructor::createStructure(state->vm(), *domObject->globalObject(), domObject->globalObject()->objectPrototype()), *jsCast<JSDOMGlobalObject*>(domObject->globalObject()));\n");
+ push(@implContent, " // Shadowing constructor property to ensure reusing the same constructor object\n");
+ push(@implContent, " domObject->putDirect(state->vm(), state->propertyNames().constructor, constructor, DontEnum | ReadOnly);\n");
+ push(@implContent, " return JSValue::encode(constructor);\n");
}
-
- push(@implContent, " return JSValue::encode(${className}::getConstructor(exec->vm(), domObject->globalObject()));\n");
push(@implContent, "}\n\n");
}
+ my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
- # Check if we have any writable attributes
- my $hasReadWriteProperties = 0;
- foreach my $attribute (@{$interface->attributes}) {
- $hasReadWriteProperties = 1 if !IsReadonly($attribute) && !$attribute->isStatic;
- }
+ push(@implContent, "bool ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " VM& vm = state->vm();\n");
+ push(@implContent, " auto throwScope = DECLARE_THROW_SCOPE(vm);\n");
+ push(@implContent, " JSValue value = JSValue::decode(encodedValue);\n");
+ push(@implContent, " ${className}Prototype* domObject = jsDynamicDowncast<${className}Prototype*>(vm, JSValue::decode(thisValue));\n");
+ push(@implContent, " if (UNLIKELY(!domObject)) {\n");
+ push(@implContent, " throwVMTypeError(state, throwScope);\n");
+ push(@implContent, " return false;\n");
+ push(@implContent, " }\n");
- my $overridesPutImplementation = InstanceOverridesPutImplementation($interface);
- my $hasSetter = $hasReadWriteProperties;
+ push(@implContent, " // Shadowing a built-in constructor\n");
- if ($hasSetter || $overridesPutImplementation) {
- if ($overridesPutImplementation) {
- push(@implContent, "void ${className}::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}* thisObject = jsCast<${className}*>(cell);\n");
- push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
- if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
- push(@implContent, " unsigned index = propertyName.asIndex();\n");
- push(@implContent, " if (index != PropertyName::NotAnIndex) {\n");
- push(@implContent, " thisObject->indexSetter(exec, index, value);\n");
- push(@implContent, " return;\n");
- push(@implContent, " }\n");
- }
- if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
- push(@implContent, " if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
- push(@implContent, " return;\n");
- }
+ push(@implContent, " return domObject->putDirect(state->vm(), state->propertyNames().constructor, value);\n");
+ push(@implContent, "}\n\n");
+ }
+
+ foreach my $attribute (@{$interface->attributes}) {
+ if (!IsReadonly($attribute)) {
+ next if IsJSBuiltin($interface, $attribute);
+
+ my $name = $attribute->name;
+ my $type = $attribute->type;
+ my $putFunctionName = GetAttributeSetterName($interface, $className, $attribute);
+ my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
- push(@implContent, " Base::put(thisObject, exec, propertyName, value, slot);\n");
+ my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute);
+ push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
+
+ if (!$attribute->isStatic) {
+ my $setterFunction = "${putFunctionName}Function";
+ my $templateParameters = $setterFunction;
+ $templateParameters .= ", CastedThisErrorBehavior::ReturnEarly" if $attribute->extendedAttributes->{LenientThis};
+ push(@implContent, "static inline bool ${setterFunction}(ExecState&, ${className}&, JSValue, ThrowScope&);\n\n");
+
+ push(@implContent, "bool ${putFunctionName}(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " return BindingCaller<${className}>::setAttribute<${templateParameters}>(state, thisValue, encodedValue, \"$name\");\n");
push(@implContent, "}\n\n");
- if ($interface->extendedAttributes->{"CustomIndexedSetter"} || $interface->extendedAttributes->{"CustomNamedSetter"}) {
- push(@implContent, "void ${className}::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}* thisObject = jsCast<${className}*>(cell);\n");
- push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
- if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
- push(@implContent, " if (index <= MAX_ARRAY_INDEX) {\n");
- push(@implContent, " UNUSED_PARAM(shouldThrow);\n");
- push(@implContent, " thisObject->indexSetter(exec, index, value);\n");
- push(@implContent, " return;\n");
- push(@implContent, " }\n");
- }
+ push(@implContent, "static inline bool ${setterFunction}(ExecState& state, ${className}& thisObject, JSValue value, ThrowScope& throwScope)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " UNUSED_PARAM(state);\n");
+ push(@implContent, " UNUSED_PARAM(throwScope);\n");
+ } else {
+ push(@implContent, "bool ${putFunctionName}(ExecState* statePointer, EncodedJSValue, EncodedJSValue encodedValue)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " ASSERT(statePointer);\n");
+ push(@implContent, " auto& state = *statePointer;\n");
+ push(@implContent, " UNUSED_PARAM(state);\n");
+ push(@implContent, " auto value = JSValue::decode(encodedValue);\n");
+ }
- if ($interface->extendedAttributes->{"CustomNamedSetter"}) {
- push(@implContent, " PropertyName propertyName = Identifier::from(exec, index);\n");
- push(@implContent, " PutPropertySlot slot(thisObject, shouldThrow);\n");
- push(@implContent, " if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
- push(@implContent, " return;\n");
- }
+ if ($attribute->extendedAttributes->{CEReactions}) {
+ push(@implContent, " CustomElementReactionStack customElementReactionStack;\n");
+ $implIncludes{"CustomElementReactionQueue.h"} = 1;
+ }
- push(@implContent, " Base::putByIndex(cell, exec, index, value, shouldThrow);\n");
- push(@implContent, "}\n\n");
+ if ($interface->extendedAttributes->{CheckSecurity} && !$attribute->extendedAttributes->{DoNotCheckSecurity} && !$attribute->extendedAttributes->{DoNotCheckSecurityOnSetter}) {
+ AddToImplIncludes("JSDOMBindingSecurity.h");
+ if ($interfaceName eq "DOMWindow") {
+ push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(&state, thisObject.wrapped(), ThrowSecurityError))\n");
+ } else {
+ push(@implContent, " if (!BindingSecurity::shouldAllowAccessToFrame(&state, thisObject.wrapped().frame(), ThrowSecurityError))\n");
}
+ push(@implContent, " return false;\n");
}
- if ($hasReadWriteProperties) {
- foreach my $attribute (@{$interface->attributes}) {
- if (!IsReadonly($attribute)) {
- my $name = $attribute->signature->name;
- my $type = $attribute->signature->type;
- my $putFunctionName = GetAttributeSetterName($interfaceName, $className, $attribute);
- my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
- my $setterRaisesException = $attribute->signature->extendedAttributes->{"SetterRaisesException"};
-
- my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
- push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
-
- push(@implContent, "void ${putFunctionName}(ExecState* exec, JSObject* /* baseObject */, EncodedJSValue");
- push(@implContent, " thisValue") if !$attribute->isStatic;
- push(@implContent, ", EncodedJSValue encodedValue)\n");
- push(@implContent, "{\n");
- push(@implContent, " JSValue value = JSValue::decode(encodedValue);\n");
- push(@implContent, " UNUSED_PARAM(exec);\n");
- if (!$attribute->isStatic) {
- push(@implContent, " ${className}* castedThis = jsDynamicCast<${className}*>(JSValue::decode(thisValue));\n");
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " if (!castedThis) {\n");
- push(@implContent, " if (JSDOMWindowShell* shell = jsDynamicCast<JSDOMWindowShell*>(JSValue::decode(thisValue)))\n");
- push(@implContent, " castedThis = shell->window();\n");
- push(@implContent, " }\n");
- }
- push(@implContent, " if (!castedThis) {\n");
- push(@implContent, " throwVMTypeError(exec);\n");
- push(@implContent, " return;\n");
- push(@implContent, " }\n");
- }
- if ($interface->extendedAttributes->{"CheckSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
- } else {
- push(@implContent, " if (!shouldAllowAccessToFrame(exec, castedThis->impl().frame()))\n");
- }
- push(@implContent, " return;\n");
+ if (HasCustomSetter($attribute->extendedAttributes)) {
+ push(@implContent, " thisObject.set$implSetterFunctionName(state, value);\n");
+ push(@implContent, " return true;\n");
+ } elsif ($type->name eq "EventHandler") {
+ $implIncludes{"JSEventListener.h"} = 1;
+ my $eventName = EventHandlerAttributeEventName($attribute);
+ # FIXME: Find a way to do this special case without hardcoding the class and attribute names here.
+ if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerGlobalScope")) and $name eq "onerror") {
+ $implIncludes{"JSErrorHandler.h"} = 1;
+ push(@implContent, " thisObject.wrapped().setAttributeEventListener($eventName, createJSErrorHandler(&state, value, &thisObject), worldForDOMObject(&thisObject));\n");
+ } else {
+ $implIncludes{"JSEventListener.h"} = 1;
+ my $setter = $attribute->extendedAttributes->{WindowEventHandler} ? "setWindowEventHandlerAttribute"
+ : $attribute->extendedAttributes->{DocumentEventHandler} ? "setDocumentEventHandlerAttribute"
+ : "setEventHandlerAttribute";
+ push(@implContent, " $setter(state, thisObject, thisObject.wrapped(), $eventName, value);\n");
+ }
+ push(@implContent, " return true;\n");
+ } elsif ($codeGenerator->IsConstructorType($type)) {
+ my $constructorType = $type->name;
+ $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 ne "any" and $constructorType !~ /Named$/) {
+ AddToImplIncludes("JS" . $constructorType . ".h", $attribute->extendedAttributes->{Conditional});
+ }
+ push(@implContent, " // Shadowing a built-in constructor.\n");
+ push(@implContent, " return thisObject.putDirect(state.vm(), Identifier::fromString(&state, \"$name\"), value);\n");
+ } elsif ($attribute->extendedAttributes->{Replaceable}) {
+ push(@implContent, " // Shadowing a built-in property.\n");
+ if (AttributeShouldBeOnInstance($interface, $attribute)) {
+ push(@implContent, " return replaceStaticPropertySlot(state.vm(), &thisObject, Identifier::fromString(&state, \"$name\"), value);\n");
+ } else {
+ push(@implContent, " return thisObject.putDirect(state.vm(), Identifier::fromString(&state, \"$name\"), value);\n");
+ }
+ } else {
+ if (!$attribute->isStatic) {
+ my $putForwards = $attribute->extendedAttributes->{PutForwards};
+ if ($putForwards) {
+ my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->extendedAttributes->{ImplementedAs} || $name);
+ my $forwardedAttribute = $codeGenerator->GetAttributeFromInterface($interface, $type->name, $putForwards);
+
+ if ($forwardedAttribute->extendedAttributes->{CEReactions}) {
+ push(@implContent, " CustomElementReactionStack customElementReactionStack;\n");
+ $implIncludes{"CustomElementReactionQueue.h"} = 1;
}
- if (HasCustomSetter($attribute->signature->extendedAttributes)) {
- push(@implContent, " castedThis->set$implSetterFunctionName(exec, value);\n");
- } elsif ($type eq "EventListener") {
- $implIncludes{"JSEventListener.h"} = 1;
- push(@implContent, " UNUSED_PARAM(exec);\n");
- my $windowEventListener = $attribute->signature->extendedAttributes->{"JSWindowEventListener"};
- if ($windowEventListener) {
- push(@implContent, " JSDOMGlobalObject* globalObject = castedThis->globalObject();\n");
- }
- push(@implContent, " $interfaceName& impl = castedThis->impl();\n");
- if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerGlobalScope")) and $name eq "onerror") {
- $implIncludes{"JSErrorHandler.h"} = 1;
- push(@implContent, " impl.set$implSetterFunctionName(createJSErrorHandler(exec, value, castedThis));\n");
- } else {
- push(@implContent, GenerateAttributeEventListenerCall($className, $implSetterFunctionName, $windowEventListener));
- }
- } elsif ($attribute->signature->type =~ /Constructor$/) {
- my $constructorType = $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 ne "any" and $constructorType !~ /Named$/) {
- AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
- }
- push(@implContent, " // Shadowing a built-in constructor\n");
- if ($interfaceName eq "DOMWindow" && $className eq "JSblah") {
- # FIXME: This branch never executes and should be removed.
- push(@implContent, " castedThis->putDirect(exec->vm(), exec->propertyNames().constructor, value);\n");
- } else {
- push(@implContent, " castedThis->putDirect(exec->vm(), Identifier(exec, \"$name\"), value);\n");
- }
- } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
- push(@implContent, " // Shadowing a built-in object\n");
- push(@implContent, " castedThis->putDirect(exec->vm(), Identifier(exec, \"$name\"), value);\n");
+ if ($type->isNullable) {
+ push(@implContent, " RefPtr<" . $type->name . "> forwardedImpl = thisObject.wrapped().${implGetterFunctionName}();\n");
+ push(@implContent, " if (!forwardedImpl)\n");
+ push(@implContent, " return false;\n");
+ push(@implContent, " auto& impl = *forwardedImpl;\n");
} else {
- if (!$attribute->isStatic) {
- push(@implContent, " $implType& impl = castedThis->impl();\n");
- }
- push(@implContent, " ExceptionCode ec = 0;\n") if $setterRaisesException;
-
- # 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"}) {
- $implIncludes{"<runtime/Error.h>"} = 1;
-
- my $argType = $attribute->signature->type;
- if ($codeGenerator->IsWrapperType($argType)) {
- push(@implContent, " if (!value.isUndefinedOrNull() && !value.inherits(JS${argType}::info())) {\n");
- push(@implContent, " throwVMTypeError(exec);\n");
- push(@implContent, " return;\n");
- push(@implContent, " };\n");
- }
- }
-
- push(@implContent, " " . GetNativeTypeFromSignature($attribute->signature) . " nativeValue(" . JSValueToNative($attribute->signature, "value") . ");\n");
- push(@implContent, " if (exec->hadException())\n");
- push(@implContent, " return;\n");
-
- if ($codeGenerator->IsEnumType($type)) {
- my @enumValues = $codeGenerator->ValidEnumValues($type);
- my @enumChecks = ();
- foreach my $enumValue (@enumValues) {
- push(@enumChecks, "nativeValue != \"$enumValue\"");
- }
- push (@implContent, " if (" . join(" && ", @enumChecks) . ")\n");
- push (@implContent, " return;\n");
- }
-
- if ($svgPropertyOrListPropertyType) {
- if ($svgPropertyType) {
- push(@implContent, " if (impl.isReadOnly()) {\n");
- push(@implContent, " setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
- push(@implContent, " return;\n");
- push(@implContent, " }\n");
- $implIncludes{"ExceptionCode.h"} = 1;
- }
- push(@implContent, " $svgPropertyOrListPropertyType& podImpl = impl.propertyReference();\n");
- if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
- push(@implContent, " podImpl = nativeValue;\n");
- } else {
- push(@implContent, " podImpl.set$implSetterFunctionName(nativeValue");
- push(@implContent, ", ec") if $setterRaisesException;
- push(@implContent, ");\n");
- push(@implContent, " setDOMException(exec, ec);\n") if $setterRaisesException;
- }
- if ($svgPropertyType) {
- if ($setterRaisesException) {
- push(@implContent, " if (!ec)\n");
- push(@implContent, " impl.commitChange();\n");
- } else {
- push(@implContent, " impl.commitChange();\n");
- }
- }
- } else {
- my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
- if ($codeGenerator->IsTypedArrayType($attribute->signature->type) and not $attribute->signature->type eq "ArrayBuffer") {
- push(@arguments, "nativeValue.get()");
- } else {
- push(@arguments, "nativeValue");
- }
- if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
- my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
- $implIncludes{"${implementedBy}.h"} = 1;
- unshift(@arguments, "&impl") if !$attribute->isStatic;
- $functionName = "${implementedBy}::${functionName}";
- } elsif ($attribute->isStatic) {
- $functionName = "${interfaceName}::${functionName}";
- } else {
- $functionName = "impl.${functionName}";
- }
-
- unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, ""));
-
- push(@arguments, "ec") if $setterRaisesException;
- push(@implContent, " ${functionName}(" . join(", ", @arguments) . ");\n");
- push(@implContent, " setDOMException(exec, ec);\n") if $setterRaisesException;
- }
+ # Attribute is not nullable, the implementation is expected to return a reference.
+ push(@implContent, " Ref<" . $type->name . "> forwardedImpl = thisObject.wrapped().${implGetterFunctionName}();\n");
+ push(@implContent, " auto& impl = forwardedImpl.get();\n");
}
-
- push(@implContent, "}\n\n");
- push(@implContent, "#endif\n") if $attributeConditionalString;
- push(@implContent, "\n");
+ $attribute = $forwardedAttribute;
+ $type = $attribute->type;
+ } else {
+ push(@implContent, " auto& impl = thisObject.wrapped();\n");
}
}
- }
- }
- if ($interface->extendedAttributes->{"ReplaceableConstructor"}) {
- my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
+ my $globalObjectReference = $attribute->isStatic ? "*jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())" : "*thisObject.globalObject()";
+ my $exceptionThrower = GetAttributeExceptionThrower($interface, $attribute);
- push(@implContent, "void ${constructorFunctionName}(ExecState* exec, JSObject*, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
- push(@implContent, "{\n");
- push(@implContent, " JSValue value = JSValue::decode(encodedValue);");
- push(@implContent, " ${className}* castedThis = jsDynamicCast<${className}*>(JSValue::decode(thisValue));\n");
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " if (!castedThis) {\n");
- push(@implContent, " if (JSDOMWindowShell* shell = jsDynamicCast<JSDOMWindowShell*>(JSValue::decode(thisValue)))\n");
- push(@implContent, " castedThis = shell->window();\n");
- push(@implContent, " }\n");
- }
- push(@implContent, " if (!castedThis) {\n");
- push(@implContent, " throwVMTypeError(exec);\n");
- push(@implContent, " return;\n");
- push(@implContent, " }\n");
- if ($interface->extendedAttributes->{"CheckSecurity"}) {
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
+ my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $attribute, "value", $attribute->extendedAttributes->{Conditional}, "&state", "state", "thisObject", $globalObjectReference, $exceptionThrower);
+
+ push(@implContent, " auto nativeValue = $nativeValue;\n");
+ push(@implContent, " RETURN_IF_EXCEPTION(throwScope, false);\n") if $mayThrowException;
+
+ if ($codeGenerator->IsEnumType($type)) {
+ push (@implContent, " if (UNLIKELY(!nativeValue))\n");
+ push (@implContent, " return false;\n");
+ }
+
+ my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
+
+ push(@arguments, PassArgumentExpression("nativeValue", $attribute));
+
+ my $implementedBy = $attribute->extendedAttributes->{ImplementedBy};
+ if ($implementedBy) {
+ AddToImplIncludes("${implementedBy}.h", $attribute->extendedAttributes->{Conditional});
+ unshift(@arguments, "impl") if !$attribute->isStatic;
+ $functionName = "WebCore::${implementedBy}::${functionName}";
+ } elsif ($attribute->isStatic) {
+ $functionName = "${interfaceName}::${functionName}";
} else {
- push(@implContent, " if (!shouldAllowAccessToFrame(exec, castedThis->impl().frame()))\n");
+ $functionName = "impl.${functionName}";
}
- push(@implContent, " return;\n");
- }
- push(@implContent, " // Shadowing a built-in constructor\n");
+ unshift(@arguments, GenerateCallWithUsingReferences($attribute->extendedAttributes->{SetterCallWith}, \@implContent, "false"));
+ unshift(@arguments, GenerateCallWithUsingReferences($attribute->extendedAttributes->{CallWith}, \@implContent, "false"));
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " castedThis->putDirect(exec->vm(), exec->propertyNames().constructor, value);\n");
- } else {
- die "No way to handle interface with ReplaceableConstructor extended attribute: $interfaceName";
+ my $functionString = "$functionName(" . join(", ", @arguments) . ")";
+ $functionString = "propagateException(state, throwScope, $functionString)" if $attribute->extendedAttributes->{SetterMayThrowException};
+
+ push(@implContent, " $functionString;\n");
+ push(@implContent, " return true;\n");
}
+
push(@implContent, "}\n\n");
+ push(@implContent, "#endif\n") if $attributeConditionalString;
+ push(@implContent, "\n");
}
}
- if ($indexedGetterFunction && !$interface->extendedAttributes->{"CustomEnumerateProperty"}) {
- push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}* thisObject = jsCast<${className}*>(object);\n");
- push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
- push(@implContent, " for (unsigned i = 0, count = thisObject->impl().length(); i < count; ++i)\n");
- push(@implContent, " propertyNames.add(Identifier::from(exec, i));\n");
- push(@implContent, " Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);\n");
- push(@implContent, "}\n\n");
- }
-
- if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
- push(@implContent, "JSValue ${className}::getConstructor(VM& vm, JSGlobalObject* globalObject)\n{\n");
- push(@implContent, " return getDOMConstructor<${className}Constructor>(vm, jsCast<JSDOMGlobalObject*>(globalObject));\n");
+ if (!$interface->extendedAttributes->{NoInterfaceObject}) {
+ push(@implContent, "JSValue ${className}::getConstructor(VM& vm, const JSGlobalObject* globalObject)\n{\n");
+ push(@implContent, " return getDOMConstructor<${className}Constructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));\n");
push(@implContent, "}\n\n");
- if ($interface->extendedAttributes->{"NamedConstructor"}) {
+ if ($interface->extendedAttributes->{NamedConstructor}) {
push(@implContent, "JSValue ${className}::getNamedConstructor(VM& vm, JSGlobalObject* globalObject)\n{\n");
- push(@implContent, " return getDOMConstructor<${className}NamedConstructor>(vm, jsCast<JSDOMGlobalObject*>(globalObject));\n");
+ push(@implContent, " return getDOMConstructor<${className}NamedConstructor>(vm, *jsCast<JSDOMGlobalObject*>(globalObject));\n");
push(@implContent, "}\n\n");
}
}
@@ -2458,8 +3949,8 @@ sub GenerateImplementation
if ($numFunctions > 0) {
my $inAppleCopyright = 0;
foreach my $function (@{$interface->functions}) {
- my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"};
- if ($needsAppleCopyright) {
+ next if IsJSBuiltin($interface, $function);
+ if ($function->extendedAttributes->{AppleCopyright}) {
if (!$inAppleCopyright) {
push(@implContent, $beginAppleCopyrightForSourceFiles);
$inAppleCopyright = 1;
@@ -2469,240 +3960,271 @@ sub GenerateImplementation
$inAppleCopyright = 0;
}
- my $isCustom = HasCustomMethod($function->signature->extendedAttributes);
+ my $isCustom = HasCustomMethod($function->extendedAttributes);
my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
- my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
next if $isCustom && $isOverloaded && $function->{overloadIndex} > 1;
- AddIncludesForTypeInImpl($function->signature->type) unless $isCustom;
+ AddToImplIncludesForIDLType($function->type) unless $isCustom or IsReturningPromise($function);
- my $functionName = GetFunctionName($className, $function);
+ my $functionName = GetFunctionName($interface, $className, $function);
- my $conditional = $function->signature->extendedAttributes->{"Conditional"};
+ my $conditional = $function->extendedAttributes->{Conditional};
if ($conditional) {
my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
push(@implContent, "#if ${conditionalString}\n");
}
-
+ my $functionReturn = "EncodedJSValue JSC_HOST_CALL";
if (!$isCustom && $isOverloaded) {
# Append a number to an overloaded method's name to make it unique:
$functionName = $functionName . $function->{overloadIndex};
- # Make this function static to avoid compiler warnings, since we
- # don't generate a prototype for it in the header.
- push(@implContent, "static ");
+ # Make this function static to avoid compiler warnings, since we don't generate a prototype for it in the header.
+ $functionReturn = "static inline EncodedJSValue";
+ }
+
+ my $functionImplementationName = $function->extendedAttributes->{ImplementedAs} || $codeGenerator->WK_lcfirst($function->name);
+
+ AddToImplIncludes("JSDOMPromise.h") if IsReturningPromise($function);
+
+ if (!$function->isStatic) {
+ my $classParameterType = $className eq "JSEventTarget" ? "JSEventTargetWrapper*" : "${className}*";
+ my $optionalPromiseParameter = (IsReturningPromise($function) && !$isCustom) ? " Ref<DeferredPromise>&&," : "";
+ push(@implContent, "static inline JSC::EncodedJSValue ${functionName}Caller(JSC::ExecState*, ${classParameterType},${optionalPromiseParameter} JSC::ThrowScope&);\n");
+ push(@implContent, "\n");
}
- my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name);
+ if (IsReturningPromise($function) && !$isCustom) {
+ my $scope = $interface->extendedAttributes->{Exposed} ? "WindowOrWorker" : "WindowOnly";
+ push(@implContent, <<END);
+static EncodedJSValue ${functionName}Promise(ExecState*, Ref<DeferredPromise>&&);
+
+${functionReturn} ${functionName}(ExecState* state)
+{
+ ASSERT(state);
+ return JSValue::encode(callPromiseFunction<${functionName}Promise, PromiseExecutionScope::${scope}>(*state));
+}
+
+static inline EncodedJSValue ${functionName}Promise(ExecState* state, Ref<DeferredPromise>&& promise)
+END
+ } else {
+ push(@implContent, "${functionReturn} ${functionName}(ExecState* state)\n");
+ }
- push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
push(@implContent, "{\n");
$implIncludes{"<runtime/Error.h>"} = 1;
+ if ($function->extendedAttributes->{CEReactions}) {
+ push(@implContent, " CustomElementReactionStack customElementReactionStack;\n");
+ $implIncludes{"CustomElementReactionQueue.h"} = 1;
+ }
+
if ($function->isStatic) {
if ($isCustom) {
GenerateArgumentsCountCheck(\@implContent, $function, $interface);
- push(@implContent, " return JSValue::encode(${className}::" . $functionImplementationName . "(exec));\n");
+ push(@implContent, " return JSValue::encode(${className}::" . $functionImplementationName . "(state));\n");
} else {
- GenerateArgumentsCountCheck(\@implContent, $function, $interface);
+ push(@implContent, " VM& vm = state->vm();\n");
+ push(@implContent, " auto throwScope = DECLARE_THROW_SCOPE(vm);\n");
+ push(@implContent, " UNUSED_PARAM(throwScope);\n");
- push(@implContent, " ExceptionCode ec = 0;\n") if $raisesException;
+ GenerateArgumentsCountCheck(\@implContent, $function, $interface);
- my $numParameters = @{$function->parameters};
- my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
- GenerateImplementationFunctionCall($function, $functionString, " ", $svgPropertyType, $interfaceName);
+ my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $functionImplementationName);
+ GenerateImplementationFunctionCall($function, $functionString, " ", $interface);
}
} else {
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " $className* castedThis = toJSDOMWindow(exec->hostThisValue().toThis(exec, NotStrictMode));\n");
- push(@implContent, " if (!castedThis)\n");
- push(@implContent, " return throwVMTypeError(exec);\n");
- } elsif ($interface->extendedAttributes->{"WorkerGlobalScope"}) {
- push(@implContent, " $className* castedThis = to${className}(exec->hostThisValue().toThis(exec, NotStrictMode));\n");
- push(@implContent, " if (!castedThis)\n");
- push(@implContent, " return throwVMTypeError(exec);\n");
+ my $methodName = $function->name;
+ if (IsReturningPromise($function) && !$isCustom) {
+ my $templateParameters = "${functionName}Caller";
+ $templateParameters .= ", CastedThisErrorBehavior::Assert" if ($function->extendedAttributes->{PrivateIdentifier} and not $function->extendedAttributes->{PublicIdentifier});
+ push(@implContent, " return BindingCaller<$className>::callPromiseOperation<${templateParameters}>(state, WTFMove(promise), \"${methodName}\");\n");
+ push(@implContent, "}\n");
+ push(@implContent, "\n");
+ push(@implContent, "static inline JSC::EncodedJSValue ${functionName}Caller(JSC::ExecState* state, ${className}* castedThis, Ref<DeferredPromise>&& promise, JSC::ThrowScope& throwScope)\n");
} else {
- push(@implContent, " JSValue thisValue = exec->hostThisValue();\n");
- push(@implContent, " $className* castedThis = jsDynamicCast<$className*>(thisValue);\n");
- push(@implContent, " if (!castedThis)\n");
- push(@implContent, " return throwVMTypeError(exec);\n");
+ my $classParameterType = $className eq "JSEventTarget" ? "JSEventTargetWrapper*" : "${className}*";
+ my $templateParameters = "${functionName}Caller";
+ if ($function->extendedAttributes->{PrivateIdentifier} and not $function->extendedAttributes->{PublicIdentifier}) {
+ $templateParameters .= ", CastedThisErrorBehavior::Assert";
+ } elsif (IsReturningPromise($function)) {
+ # FIXME: We need this specific handling for custom promise-returning functions.
+ # It would be better to have the casted-this code calling the promise-specific code.
+ $templateParameters .= ", CastedThisErrorBehavior::RejectPromise" if IsReturningPromise($function);
+ }
+
+ push(@implContent, " return BindingCaller<$className>::callOperation<${templateParameters}>(state, \"${methodName}\");\n");
+ push(@implContent, "}\n");
+ push(@implContent, "\n");
+ push(@implContent, "static inline JSC::EncodedJSValue ${functionName}Caller(JSC::ExecState* state, ${classParameterType} castedThis, JSC::ThrowScope& throwScope)\n");
}
- push(@implContent, " ASSERT_GC_OBJECT_INHERITS(castedThis, ${className}::info());\n");
+ push(@implContent, "{\n");
+ push(@implContent, " UNUSED_PARAM(state);\n");
+ push(@implContent, " UNUSED_PARAM(throwScope);\n");
- if ($interface->extendedAttributes->{"CheckSecurity"} and
- !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
- push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n");
+ if ($interface->extendedAttributes->{CheckSecurity} and !$function->extendedAttributes->{DoNotCheckSecurity}) {
+ AddToImplIncludes("JSDOMBindingSecurity.h");
+ if ($interfaceName eq "DOMWindow") {
+ push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, castedThis->wrapped(), ThrowSecurityError))\n");
+ } else {
+ push(@implContent, " if (!BindingSecurity::shouldAllowAccessToFrame(state, castedThis->wrapped().frame(), ThrowSecurityError))\n");
+ }
push(@implContent, " return JSValue::encode(jsUndefined());\n");
}
if ($isCustom) {
- push(@implContent, " return JSValue::encode(castedThis->" . $functionImplementationName . "(exec));\n");
+ push(@implContent, " return JSValue::encode(castedThis->" . $functionImplementationName . "(*state));\n");
} else {
- push(@implContent, " $implType& impl = castedThis->impl();\n");
- if ($svgPropertyType) {
- push(@implContent, " if (impl.isReadOnly()) {\n");
- push(@implContent, " setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
- push(@implContent, " return JSValue::encode(jsUndefined());\n");
- push(@implContent, " }\n");
- push(@implContent, " $svgPropertyType& podImpl = impl.propertyReference();\n");
- $implIncludes{"ExceptionCode.h"} = 1;
- }
+ push(@implContent, " auto& impl = castedThis->wrapped();\n");
- # For compatibility with legacy content, the EventListener calls are generated without GenerateArgumentsCountCheck.
- if ($function->signature->name eq "addEventListener") {
- push(@implContent, GenerateEventListenerCall($className, "add"));
- } elsif ($function->signature->name eq "removeEventListener") {
- push(@implContent, GenerateEventListenerCall($className, "remove"));
- } else {
- GenerateArgumentsCountCheck(\@implContent, $function, $interface);
+ GenerateArgumentsCountCheck(\@implContent, $function, $interface);
+
+ my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $functionImplementationName);
+ GenerateImplementationFunctionCall($function, $functionString, " ", $interface);
+ }
+ }
- push(@implContent, " ExceptionCode ec = 0;\n") if $raisesException;
+ push(@implContent, "}\n\n");
- if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) {
- push(@implContent, " if (!shouldAllowAccessToNode(exec, impl." . $function->signature->name . "(" . ($raisesException ? "ec" : "") .")))\n");
- push(@implContent, " return JSValue::encode(jsNull());\n");
- $implIncludes{"JSDOMBinding.h"} = 1;
- }
+ if ($function->extendedAttributes->{DOMJIT}) {
+ $implIncludes{"<interpreter/FrameTracers.h>"} = 1;
+ my $unsafeFunctionName = "unsafe" . $codeGenerator->WK_ucfirst($functionName);
+ push(@implContent, "JSC::EncodedJSValue JIT_OPERATION ${unsafeFunctionName}(JSC::ExecState* state, $className* castedThis");
+ foreach my $argument (@{$function->arguments}) {
+ my $type = $argument->type;
+ my $argumentType = GetUnsafeArgumentType($interface, $type);
+ my $name = $argument->name;
+ my $encodedName = "encoded" . $codeGenerator->WK_ucfirst($name);
+ push(@implContent, ", ${argumentType} ${encodedName}");
+ }
+ push(@implContent, ")\n");
+ push(@implContent, "{\n");
+ push(@implContent, " UNUSED_PARAM(state);\n");
+ push(@implContent, " VM& vm = state->vm();\n");
+ push(@implContent, " JSC::NativeCallFrameTracer tracer(&vm, state);\n");
+ push(@implContent, " auto throwScope = DECLARE_THROW_SCOPE(vm);\n");
+ push(@implContent, " UNUSED_PARAM(throwScope);\n");
+ push(@implContent, " auto& impl = castedThis->wrapped();\n");
+ my @arguments;
+ my $implFunctionName;
+ my $implementedBy = $function->extendedAttributes->{ImplementedBy};
+
+ if ($implementedBy) {
+ AddToImplIncludes("${implementedBy}.h", $function->extendedAttributes->{Conditional});
+ unshift(@arguments, "impl") if !$function->isStatic;
+ $implFunctionName = "WebCore::${implementedBy}::${functionImplementationName}";
+ } elsif ($function->isStatic) {
+ $implFunctionName = "${interfaceName}::${functionImplementationName}";
+ } else {
+ $implFunctionName = "impl.${functionImplementationName}";
+ }
- my $numParameters = @{$function->parameters};
- my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
- GenerateImplementationFunctionCall($function, $functionString, " ", $svgPropertyType, $interfaceName);
+ foreach my $argument (@{$function->arguments}) {
+ my $value = "";
+ my $type = $argument->type;
+ my $name = $argument->name;
+ my $encodedName = "encoded" . $codeGenerator->WK_ucfirst($name);
+ my $nativeType = GetNativeType($interface, $argument->type);
+ my $shouldPassByReference = ShouldPassArgumentByReference($argument);
+
+ if (!$shouldPassByReference && ($codeGenerator->IsWrapperType($type) || $codeGenerator->IsTypedArrayType($type))) {
+ $implIncludes{"<runtime/Error.h>"} = 1;
+ my ($nativeValue, $mayThrowException) = UnsafeToNative($interface, $argument, $encodedName, $function->extendedAttributes->{Conditional});
+ push(@implContent, " $nativeType $name = nullptr;\n");
+ push(@implContent, " $name = $nativeValue;\n");
+ push(@implContent, " RETURN_IF_EXCEPTION(throwScope, encodedJSValue());\n") if $mayThrowException;
+ $value = "WTFMove($name)";
+ } else {
+ my ($nativeValue, $mayThrowException) = UnsafeToNative($interface, $argument, $encodedName, $function->extendedAttributes->{Conditional});
+ push(@implContent, " auto $name = ${nativeValue};\n");
+ $value = "WTFMove($name)";
+ push(@implContent, " RETURN_IF_EXCEPTION(throwScope, encodedJSValue());\n") if $mayThrowException;
+ }
+
+ if ($shouldPassByReference) {
+ $value = "*$name";
}
+ push(@arguments, $value);
}
+ my $functionString = "$implFunctionName(" . join(", ", @arguments) . ")";
+ $functionString = "propagateException(*state, throwScope, $functionString)" if NeedsExplicitPropagateExceptionCall($function);
+ push(@implContent, " return JSValue::encode(" . NativeToJSValueUsingPointers($function, $interface, $functionString, "castedThis") . ");\n");
+ push(@implContent, "}\n\n");
}
- push(@implContent, "}\n\n");
push(@implContent, "#endif\n\n") if $conditional;
- if (!$isCustom && $isOverloaded && $function->{overloadIndex} == @{$function->{overloads}}) {
- # Generate a function dispatching call to the rest of the overloads.
- GenerateOverloadedFunction($function, $interface, $interfaceName);
- }
-
+ # Generate a function dispatching call to the rest of the overloads.
+ GenerateOverloadedFunctionOrConstructor($function, $interface, 0) if !$isCustom && $isOverloaded && $function->{overloadIndex} == @{$function->{overloads}};
}
push(@implContent, $endAppleCopyright) if $inAppleCopyright;
}
- if ($needsMarkChildren && !$interface->extendedAttributes->{"JSCustomMarkFunction"}) {
+
+ GenerateImplementationIterableFunctions($interface) if $interface->iterable;
+ GenerateSerializerFunction($interface, $className) if $interface->serializable;
+
+ if ($needsVisitChildren) {
push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n");
push(@implContent, "{\n");
- push(@implContent, " ${className}* thisObject = jsCast<${className}*>(cell);\n");
+ push(@implContent, " auto* thisObject = jsCast<${className}*>(cell);\n");
push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
- push(@implContent, " COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);\n");
- push(@implContent, " ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());\n");
push(@implContent, " Base::visitChildren(thisObject, visitor);\n");
- if ($interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget") {
- push(@implContent, " thisObject->impl().visitJSEventListeners(visitor);\n");
+ push(@implContent, " thisObject->visitAdditionalChildren(visitor);\n") if $interface->extendedAttributes->{JSCustomMarkFunction};
+ if ($interface->extendedAttributes->{ReportExtraMemoryCost}) {
+ push(@implContent, " visitor.reportExtraMemoryVisited(thisObject->wrapped().memoryCost());\n");
+ if ($interface->extendedAttributes->{ReportExternalMemoryCost}) {;
+ push(@implContent, "#if ENABLE(RESOURCE_USAGE)\n");
+ push(@implContent, " visitor.reportExternalMemoryVisited(thisObject->wrapped().externalMemoryCost());\n");
+ push(@implContent, "#endif\n");
+ }
}
if ($numCachedAttributes > 0) {
foreach (@{$interface->attributes}) {
my $attribute = $_;
- if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
- push(@implContent, " visitor.append(&thisObject->m_" . $attribute->signature->name . ");\n");
+ if ($attribute->extendedAttributes->{CachedAttribute}) {
+ push(@implContent, " visitor.append(thisObject->m_" . $attribute->name . ");\n");
}
}
}
push(@implContent, "}\n\n");
- }
-
- # Cached attributes are indeed allowed when there is a custom mark/visitChildren function.
- # The custom function must make sure to account for the cached attribute.
- # Uncomment the below line to temporarily enforce generated mark functions when cached attributes are present.
- # die "Can't generate binding for class with cached attribute and custom mark." if (($numCachedAttributes > 0) and ($interface->extendedAttributes->{"JSCustomMarkFunction"}));
-
- if ($numConstants > 0) {
- push(@implContent, "// Constant getters\n\n");
-
- foreach my $constant (@{$interface->constants}) {
- my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
- my $conditional = $constant->extendedAttributes->{"Conditional"};
-
- if ($conditional) {
- my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
- push(@implContent, "#if ${conditionalString}\n");
- }
-
- # FIXME: this casts into int to match our previous behavior which turned 0xFFFFFFFF in -1 for NodeFilter.SHOW_ALL
- push(@implContent, "EncodedJSValue ${getter}(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName)\n");
+ if ($interface->extendedAttributes->{JSCustomMarkFunction}) {
+ push(@implContent, "void ${className}::visitOutputConstraints(JSCell* cell, SlotVisitor& visitor)\n");
push(@implContent, "{\n");
- if ($constant->type eq "DOMString") {
- push(@implContent, " return JSValue::encode(jsStringOrNull(exec, String(" . $constant->value . ")));\n");
- } else {
- push(@implContent, " UNUSED_PARAM(exec);\n");
- push(@implContent, " return JSValue::encode(jsNumber(static_cast<int>(" . $constant->value . ")));\n");
- }
+ push(@implContent, " auto* thisObject = jsCast<${className}*>(cell);\n");
+ push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
+ push(@implContent, " Base::visitOutputConstraints(thisObject, visitor);\n");
+ push(@implContent, " thisObject->visitAdditionalChildren(visitor);\n");
push(@implContent, "}\n\n");
- push(@implContent, "#endif\n") if $conditional;
}
}
- if ($indexedGetterFunction && !$hasNumericIndexedGetter) {
- push(@implContent, "\nEncodedJSValue ${className}::indexGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, unsigned index)\n");
+ if (InstanceNeedsEstimatedSize($interface)) {
+ push(@implContent, "size_t ${className}::estimatedSize(JSCell* cell)\n");
push(@implContent, "{\n");
- push(@implContent, " ${className}* thisObj = jsCast<$className*>(JSValue::decode(slotBase));\n");
- push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObj, info());\n");
- if ($indexedGetterFunction->signature->type eq "DOMString") {
- $implIncludes{"URL.h"} = 1;
- push(@implContent, " return JSValue::encode(jsStringOrUndefined(exec, thisObj->impl().item(index)));\n");
- } else {
- push(@implContent, " return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().item(index)));\n");
- }
+ push(@implContent, " auto* thisObject = jsCast<${className}*>(cell);\n");
+ push(@implContent, " return Base::estimatedSize(thisObject) + thisObject->wrapped().memoryCost();\n");
push(@implContent, "}\n\n");
- if ($interfaceName =~ /^HTML\w*Collection$/ or $interfaceName eq "RadioNodeList") {
- $implIncludes{"JSNode.h"} = 1;
- $implIncludes{"Node.h"} = 1;
- }
}
- if ($hasNumericIndexedGetter) {
- push(@implContent, "\nJSValue ${className}::getByIndex(ExecState*, unsigned index)\n");
- push(@implContent, "{\n");
- push(@implContent, " ASSERT_GC_OBJECT_INHERITS(this, info());\n");
- push(@implContent, " double result = impl().item(index);\n");
- # jsNumber conversion doesn't suppress signalling NaNs, so enforce that here.
- push(@implContent, " if (std::isnan(result))\n");
- push(@implContent, " return jsNaN();\n");
- push(@implContent, " return JSValue(result);\n");
- push(@implContent, "}\n\n");
- if ($interfaceName =~ /^HTML\w*Collection$/) {
+ # Cached attributes are indeed allowed when there is a custom mark/visitChildren function.
+ # The custom function must make sure to account for the cached attribute.
+ # Uncomment the below line to temporarily enforce generated mark functions when cached attributes are present.
+ # die "Can't generate binding for class with cached attribute and custom mark." if $numCachedAttributes > 0 and $interface->extendedAttributes->{JSCustomMarkFunction};
+
+ if ($indexedGetterFunction) {
+ $implIncludes{"URL.h"} = 1 if $indexedGetterFunction->type->name eq "DOMString";
+ if ($interfaceName =~ /^HTML\w*Collection$/ or $interfaceName eq "RadioNodeList") {
$implIncludes{"JSNode.h"} = 1;
$implIncludes{"Node.h"} = 1;
}
}
- if ($interfaceName eq "DOMNamedFlowCollection") {
- if ($namedGetterFunction) {
- push(@implContent, "bool ${className}::canGetItemsForName(ExecState*, $interfaceName* collection, PropertyName propertyName)\n");
- push(@implContent, "{\n");
- push(@implContent, " return collection->hasNamedItem(propertyNameToAtomicString(propertyName));\n");
- push(@implContent, "}\n\n");
- push(@implContent, "EncodedJSValue ${className}::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}* thisObj = jsCast<$className*>(JSValue::decode(slotBase));\n");
- push(@implContent, " return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().namedItem(propertyNameToAtomicString(propertyName))));\n");
- push(@implContent, "}\n\n");
- }
- }
-
- if ((!$hasParent && !GetCustomIsReachable($interface)) || GetGenerateIsReachable($interface) || $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
- if (GetGenerateIsReachable($interface)) {
- push(@implContent, "static inline bool isObservable(JS${interfaceName}* js${interfaceName})\n");
- push(@implContent, "{\n");
- push(@implContent, " if (js${interfaceName}->hasCustomProperties())\n");
- push(@implContent, " return true;\n");
- if ($eventTarget) {
- push(@implContent, " if (js${interfaceName}->impl().hasEventListeners())\n");
- push(@implContent, " return true;\n");
- }
- push(@implContent, " return false;\n");
- push(@implContent, "}\n\n");
- }
-
+ if (ShouldGenerateWrapperOwnerCode($hasParent, $interface) && !GetCustomIsReachable($interface)) {
push(@implContent, "bool JS${interfaceName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)\n");
push(@implContent, "{\n");
# All ActiveDOMObjects implement hasPendingActivity(), but not all of them
@@ -2711,25 +4233,25 @@ sub GenerateImplementation
# their pending activities complete. To wallpaper over this bug, JavaScript
# wrappers unconditionally keep ActiveDOMObjects with pending activity alive.
# FIXME: Fix this lifetime issue in the DOM, and move this hasPendingActivity
- # check below the isObservable check.
+ # check just above the (GetGenerateIsReachable($interface) eq "Impl") check below.
my $emittedJSCast = 0;
if ($codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
- push(@implContent, " JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
+ push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
$emittedJSCast = 1;
- push(@implContent, " if (js${interfaceName}->impl().hasPendingActivity())\n");
+ push(@implContent, " if (js${interfaceName}->wrapped().hasPendingActivity())\n");
push(@implContent, " return true;\n");
}
- if ($codeGenerator->InheritsExtendedAttribute($interface, "EventTarget")) {
+ if ($codeGenerator->InheritsInterface($interface, "EventTarget")) {
if (!$emittedJSCast) {
- push(@implContent, " JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
+ push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
$emittedJSCast = 1;
}
- push(@implContent, " if (js${interfaceName}->impl().isFiringEventListeners())\n");
+ push(@implContent, " if (js${interfaceName}->wrapped().isFiringEventListeners())\n");
push(@implContent, " return true;\n");
}
if ($codeGenerator->InheritsInterface($interface, "Node")) {
if (!$emittedJSCast) {
- push(@implContent, " JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
+ push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
$emittedJSCast = 1;
}
push(@implContent, " if (JSNodeOwner::isReachableFromOpaqueRoots(handle, 0, visitor))\n");
@@ -2737,40 +4259,40 @@ sub GenerateImplementation
}
if (GetGenerateIsReachable($interface)) {
if (!$emittedJSCast) {
- push(@implContent, " JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
+ push(@implContent, " auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
$emittedJSCast = 1;
}
- push(@implContent, " if (!isObservable(js${interfaceName}))\n");
- push(@implContent, " return false;\n");
my $rootString;
if (GetGenerateIsReachable($interface) eq "Impl") {
- $rootString = " ${implType}* root = &js${interfaceName}->impl();\n";
+ $rootString = " ${implType}* root = &js${interfaceName}->wrapped();\n";
} elsif (GetGenerateIsReachable($interface) eq "ImplWebGLRenderingContext") {
- $rootString = " WebGLRenderingContext* root = js${interfaceName}->impl().context();\n";
+ $rootString = " WebGLRenderingContextBase* root = WTF::getPtr(js${interfaceName}->wrapped().context());\n";
} elsif (GetGenerateIsReachable($interface) eq "ImplFrame") {
- $rootString = " Frame* root = js${interfaceName}->impl().frame();\n";
+ $rootString = " Frame* root = WTF::getPtr(js${interfaceName}->wrapped().frame());\n";
$rootString .= " if (!root)\n";
$rootString .= " return false;\n";
} elsif (GetGenerateIsReachable($interface) eq "ImplDocument") {
- $rootString = " Document* root = js${interfaceName}->impl().document();\n";
+ $rootString = " Document* root = WTF::getPtr(js${interfaceName}->wrapped().document());\n";
$rootString .= " if (!root)\n";
$rootString .= " return false;\n";
} elsif (GetGenerateIsReachable($interface) eq "ImplElementRoot") {
$implIncludes{"Element.h"} = 1;
$implIncludes{"JSNodeCustom.h"} = 1;
- $rootString = " Element* element = js${interfaceName}->impl().element();\n";
+ $rootString = " Element* element = WTF::getPtr(js${interfaceName}->wrapped().element());\n";
$rootString .= " if (!element)\n";
$rootString .= " return false;\n";
$rootString .= " void* root = WebCore::root(element);\n";
- } elsif ($interfaceName eq "CanvasRenderingContext") {
- $rootString = " void* root = WebCore::root(js${interfaceName}->impl().canvas());\n";
} elsif (GetGenerateIsReachable($interface) eq "ImplOwnerNodeRoot") {
$implIncludes{"Element.h"} = 1;
$implIncludes{"JSNodeCustom.h"} = 1;
- $rootString = " void* root = WebCore::root(js${interfaceName}->impl().ownerNode());\n";
+ $rootString = " void* root = WebCore::root(js${interfaceName}->wrapped().ownerNode());\n";
+ } elsif (GetGenerateIsReachable($interface) eq "ImplScriptExecutionContext") {
+ $rootString = " ScriptExecutionContext* root = WTF::getPtr(js${interfaceName}->wrapped().scriptExecutionContext());\n";
+ $rootString .= " if (!root)\n";
+ $rootString .= " return false;\n";
} else {
- $rootString = " void* root = WebCore::root(&js${interfaceName}->impl());\n";
+ $rootString = " void* root = WebCore::root(&js${interfaceName}->wrapped());\n";
}
push(@implContent, $rootString);
@@ -2785,17 +4307,12 @@ sub GenerateImplementation
push(@implContent, "}\n\n");
}
- if (!$interface->extendedAttributes->{"JSCustomFinalize"} &&
- (!$hasParent ||
- GetGenerateIsReachable($interface) ||
- GetCustomIsReachable($interface) ||
- $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject"))) {
+ if (ShouldGenerateWrapperOwnerCode($hasParent, $interface) && !$interface->extendedAttributes->{JSCustomFinalize}) {
push(@implContent, "void JS${interfaceName}Owner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)\n");
push(@implContent, "{\n");
- push(@implContent, " JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n");
- push(@implContent, " DOMWrapperWorld& world = *static_cast<DOMWrapperWorld*>(context);\n");
- push(@implContent, " uncacheWrapper(world, &js${interfaceName}->impl(), js${interfaceName});\n");
- push(@implContent, " js${interfaceName}->releaseImpl();\n");
+ push(@implContent, " auto* js${interfaceName} = static_cast<JS${interfaceName}*>(handle.slot()->asCell());\n");
+ push(@implContent, " auto& world = *static_cast<DOMWrapperWorld*>(context);\n");
+ push(@implContent, " uncacheWrapper(world, &js${interfaceName}->wrapped(), js${interfaceName});\n");
push(@implContent, "}\n\n");
}
@@ -2813,26 +4330,15 @@ extern "C" { extern void (*const ${vtableRefWin}[])(); }
extern "C" { extern void* ${vtableNameGnu}[]; }
#endif
#endif
-END
- push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n");
- push(@implContent, "{\n");
- push(@implContent, <<END);
- if (!impl)
- return jsNull();
END
- if ($svgPropertyType) {
- push(@implContent, " if (JSValue result = getExistingWrapper<$className, $implType>(exec, impl))\n");
- push(@implContent, " return result;\n");
- } else {
- push(@implContent, " if (JSValue result = getExistingWrapper<$className>(exec, impl))\n");
- push(@implContent, " return result;\n");
- }
+ push(@implContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<$implType>&& impl)\n");
+ push(@implContent, "{\n");
push(@implContent, <<END) if $vtableNameGnu;
#if ENABLE(BINDING_INTEGRITY)
- void* actualVTablePointer = *(reinterpret_cast<void**>(impl));
+ void* actualVTablePointer = *(reinterpret_cast<void**>(impl.ptr()));
#if PLATFORM(WIN)
void* expectedVTablePointer = reinterpret_cast<void*>(${vtableRefWin});
#else
@@ -2840,7 +4346,7 @@ END
#if COMPILER(CLANG)
// If this fails $implType does not have a vtable, so you need to add the
// ImplementationLacksVTable attribute to the interface definition
- COMPILE_ASSERT(__is_polymorphic($implType), ${implType}_is_not_polymorphic);
+ static_assert(__is_polymorphic($implType), "${implType} is not polymorphic");
#endif
#endif
// If you hit this assertion you either have a use after free bug, or
@@ -2850,33 +4356,35 @@ END
RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer);
#endif
END
- push(@implContent, <<END) if $interface->extendedAttributes->{"ImplementationLacksVTable"};
+ push(@implContent, <<END) if $interface->extendedAttributes->{ImplementationLacksVTable};
#if COMPILER(CLANG)
// If you hit this failure the interface definition has the ImplementationLacksVTable
// attribute. You should remove that attribute. If the class has subclasses
// that may be passed through this toJS() function you should use the SkipVTableValidation
// attribute to $interfaceName.
- COMPILE_ASSERT(!__is_polymorphic($implType), ${implType}_is_polymorphic_but_idl_claims_not_to_be);
+ static_assert(!__is_polymorphic($implType), "${implType} is polymorphic but the IDL claims it is not");
#endif
END
- push(@implContent, <<END);
- ReportMemoryCost<$implType>::reportMemoryCost(exec, impl);
+ push(@implContent, <<END) if $interface->extendedAttributes->{ReportExtraMemoryCost};
+ globalObject->vm().heap.reportExtraMemoryAllocated(impl->memoryCost());
END
- if ($svgPropertyType) {
- push(@implContent, " return createNewWrapper<$className, $implType>(exec, globalObject, impl);\n");
- } else {
- push(@implContent, " return createNewWrapper<$className>(exec, globalObject, impl);\n");
- }
+ push(@implContent, " return createWrapper<$implType>(globalObject, WTFMove(impl));\n");
+ push(@implContent, "}\n\n");
+ push(@implContent, "JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, $implType& impl)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " return wrap(state, globalObject, impl);\n");
push(@implContent, "}\n\n");
}
- if ((!$hasParent or $interface->extendedAttributes->{"JSGenerateToNativeObject"}) and !$interface->extendedAttributes->{"JSCustomToNativeObject"}) {
- push(@implContent, "$implType* to${interfaceName}(JSC::JSValue value)\n");
+ if (ShouldGenerateToWrapped($hasParent, $interface) and !$interface->extendedAttributes->{JSCustomToNativeObject}) {
+ push(@implContent, "$implType* ${className}::toWrapped(JSC::VM& vm, JSC::JSValue value)\n");
push(@implContent, "{\n");
- push(@implContent, " return value.inherits(${className}::info()) ? &jsCast<$className*>(value)->impl() : 0");
- push(@implContent, ";\n}\n");
+ push(@implContent, " if (auto* wrapper = " . GetCastingHelperForThisObject($interface) . "(vm, value))\n");
+ push(@implContent, " return &wrapper->wrapped();\n");
+ push(@implContent, " return nullptr;\n");
+ push(@implContent, "}\n");
}
push(@implContent, "\n}\n");
@@ -2885,30 +4393,160 @@ END
push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
}
+sub GenerateSerializerFunction
+{
+ my ($interface, $className) = @_;
+
+ my $interfaceName = $interface->type->name;
+
+ my $parentSerializerInterface = 0;
+ if ($interface->serializable->hasInherit) {
+ $codeGenerator->ForAllParents($interface, sub {
+ my $parentInterface = shift;
+ if ($parentInterface->serializable && !$parentSerializerInterface) {
+ $parentSerializerInterface = $parentInterface;
+ }
+ }, 0);
+ die "Failed to find parent interface with \"serializer\" for \"inherit\" serializer in $interfaceName\n" if !$parentSerializerInterface;
+ }
+
+ my @serializedAttributes = ();
+
+ foreach my $attributeName (@{$interface->serializable->attributes}) {
+ my $foundAttribute = 0;
+ foreach my $attribute (@{$interface->attributes}) {
+ if ($attributeName eq $attribute->name) {
+ $foundAttribute = 1;
+ if ($codeGenerator->IsSerializableAttribute($interface, $attribute)) {
+ push(@serializedAttributes, $attribute);
+ last;
+ }
+ die "Explicit \"serializer\" attribute \"$attributeName\" is not serializable\n" if !$interface->serializable->hasAttribute;
+ last;
+ }
+ }
+ die "Failed to find \"serializer\" attribute \"$attributeName\" in $interfaceName\n" if !$foundAttribute;
+ }
+
+ my $serializerFunctionName = "toJSON";
+ my $serializerNativeFunctionName = $codeGenerator->WK_lcfirst($className) . "PrototypeFunction" . $codeGenerator->WK_ucfirst($serializerFunctionName);
+
+ AddToImplIncludes("<runtime/ObjectConstructor.h>");
+
+ push(@implContent, "JSC::JSObject* JS${interfaceName}::serialize(ExecState* state, JS${interfaceName}* thisObject, ThrowScope& throwScope)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " auto& vm = state->vm();\n");
+
+ if ($interface->serializable->hasInherit) {
+ my $parentSerializerInterfaceName = $parentSerializerInterface->type->name;
+ push(@implContent, " auto* result = JS${parentSerializerInterfaceName}::serialize(state, thisObject, throwScope);\n");
+ } else {
+ push(@implContent, " auto* result = constructEmptyObject(state);\n");
+ }
+ push(@implContent, "\n");
+
+ foreach my $attribute (@serializedAttributes) {
+ my $name = $attribute->name;
+ my $getFunctionName = GetAttributeGetterName($interface, $className, $attribute);
+ push(@implContent, " auto ${name}Value = ${getFunctionName}Getter(*state, *thisObject, throwScope);\n");
+ push(@implContent, " ASSERT(!throwScope.exception());\n");
+ push(@implContent, " result->putDirect(vm, Identifier::fromString(&vm, \"${name}\"), ${name}Value);\n");
+ push(@implContent, "\n");
+ }
+
+ push(@implContent, " return result;\n");
+ push(@implContent, "}\n");
+ push(@implContent, "\n");
+
+ push(@implContent, "static inline EncodedJSValue ${serializerNativeFunctionName}Caller(ExecState* state, JS${interfaceName}* thisObject, JSC::ThrowScope& throwScope)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " return JSValue::encode(JS${interfaceName}::serialize(state, thisObject, throwScope));\n");
+ push(@implContent, "}\n");
+ push(@implContent, "\n");
+ push(@implContent, "EncodedJSValue JSC_HOST_CALL ${serializerNativeFunctionName}(ExecState* state)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " return BindingCaller<JS$interfaceName>::callOperation<${serializerNativeFunctionName}Caller>(state, \"$serializerFunctionName\");\n");
+ push(@implContent, "}\n");
+ push(@implContent, "\n");
+}
+
+sub GenerateCallWithUsingReferences
+{
+ my ($callWith, $outputArray, $returnValue, $function) = @_;
+
+ my $statePointer = "&state";
+ my $stateReference = "state";
+ my $globalObject = "jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())";
+
+ return GenerateCallWith($callWith, $outputArray, $returnValue, $function, $statePointer, $stateReference, $globalObject);
+}
+
+# FIXME: We should remove GenerateCallWithUsingPointers and combine GenerateCallWithUsingReferences and GenerateCallWith
+sub GenerateCallWithUsingPointers
+{
+ my ($callWith, $outputArray, $returnValue, $function) = @_;
+
+ my $statePointer = "state";
+ my $stateReference = "*state";
+ my $globalObject = "jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())";
+
+ return GenerateCallWith($callWith, $outputArray, $returnValue, $function, $statePointer, $stateReference, $globalObject);
+}
+
sub GenerateCallWith
{
- my $callWith = shift;
+ my ($callWith, $outputArray, $returnValue, $function, $statePointer, $stateReference, $globalObject) = @_;
+
return () unless $callWith;
- my $outputArray = shift;
- my $returnValue = shift;
- my $function = shift;
my @callWithArgs;
- if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
- push(@callWithArgs, "exec");
- }
+ push(@callWithArgs, $stateReference) if $codeGenerator->ExtendedAttributeContains($callWith, "ScriptState");
+ push(@callWithArgs, "*${globalObject}") if $codeGenerator->ExtendedAttributeContains($callWith, "GlobalObject");
if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptExecutionContext")) {
- push(@$outputArray, " ScriptExecutionContext* scriptContext = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();\n");
- push(@$outputArray, " if (!scriptContext)\n");
+ push(@$outputArray, " auto* context = $globalObject->scriptExecutionContext();\n");
+ push(@$outputArray, " if (!context)\n");
push(@$outputArray, " return" . ($returnValue ? " " . $returnValue : "") . ";\n");
- push(@callWithArgs, "scriptContext");
+ push(@callWithArgs, "*context");
+ }
+ if ($codeGenerator->ExtendedAttributeContains($callWith, "Document")) {
+ $implIncludes{"Document.h"} = 1;
+ push(@$outputArray, " auto* context = $globalObject->scriptExecutionContext();\n");
+ push(@$outputArray, " if (!context)\n");
+ push(@$outputArray, " return" . ($returnValue ? " " . $returnValue : "") . ";\n");
+ push(@$outputArray, " ASSERT(context->isDocument());\n");
+ push(@$outputArray, " auto& document = downcast<Document>(*context);\n");
+ push(@callWithArgs, "document");
+ }
+ if ($codeGenerator->ExtendedAttributeContains($callWith, "CallerDocument")) {
+ $implIncludes{"Document.h"} = 1;
+ $implIncludes{"JSDOMWindowBase.h"} = 1;
+ push(@$outputArray, " auto* document = callerDOMWindow($statePointer).document();\n");
+ push(@$outputArray, " if (!document)\n");
+ push(@$outputArray, " return" . ($returnValue ? " " . $returnValue : "") . ";\n");
+ push(@callWithArgs, "*document");
}
if ($function and $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments")) {
- push(@$outputArray, " RefPtr<ScriptArguments> scriptArguments(createScriptArguments(exec, " . @{$function->parameters} . "));\n");
- $implIncludes{"ScriptArguments.h"} = 1;
- $implIncludes{"ScriptCallStackFactory.h"} = 1;
- push(@callWithArgs, "scriptArguments.release()");
+ push(@$outputArray, " Ref<Inspector::ScriptArguments> scriptArguments(Inspector::createScriptArguments($statePointer, " . @{$function->arguments} . "));\n");
+ $implIncludes{"<inspector/ScriptArguments.h>"} = 1;
+ $implIncludes{"<inspector/ScriptCallStackFactory.h>"} = 1;
+ push(@callWithArgs, "WTFMove(scriptArguments)");
+ }
+ if ($codeGenerator->ExtendedAttributeContains($callWith, "ActiveWindow")) {
+ $implIncludes{"JSDOMWindowBase.h"} = 1;
+ push(@callWithArgs, "activeDOMWindow($statePointer)");
+
}
+ if ($codeGenerator->ExtendedAttributeContains($callWith, "FirstWindow")) {
+ $implIncludes{"JSDOMWindowBase.h"} = 1;
+ push(@callWithArgs, "firstDOMWindow($statePointer)");
+
+ }
+ if ($codeGenerator->ExtendedAttributeContains($callWith, "CallerWindow")) {
+ $implIncludes{"JSDOMWindowBase.h"} = 1;
+ push(@callWithArgs, "callerDOMWindow($statePointer)");
+
+ }
+
return @callWithArgs;
}
@@ -2918,795 +4556,1132 @@ sub GenerateArgumentsCountCheck
my $function = shift;
my $interface = shift;
- my $numMandatoryParams = @{$function->parameters};
- foreach my $param (reverse(@{$function->parameters})) {
- if ($param->isOptional or $param->isVariadic) {
- $numMandatoryParams--;
+ my $numMandatoryArguments = @{$function->arguments};
+ foreach my $argument (reverse(@{$function->arguments})) {
+ if ($argument->isOptional or $argument->isVariadic) {
+ $numMandatoryArguments--;
} else {
last;
}
}
- if ($numMandatoryParams >= 1)
- {
- push(@$outputArray, " if (exec->argumentCount() < $numMandatoryParams)\n");
- push(@$outputArray, " return throwVMError(exec, createNotEnoughArgumentsError(exec));\n");
+ if ($numMandatoryArguments >= 1) {
+ push(@$outputArray, " if (UNLIKELY(state->argumentCount() < $numMandatoryArguments))\n");
+ push(@$outputArray, " return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));\n");
}
}
-sub GenerateParametersCheck
+my %automaticallyGeneratedDefaultValues = (
+ "any" => "undefined",
+
+ # toString() will convert undefined to the string "undefined";
+ # (note that this optimizes a behavior that is almost never useful)
+ "DOMString" => "\"undefined\"",
+ "USVString" => "\"undefined\"",
+
+ # JSValue::toBoolean() will convert undefined to false.
+ "boolean" => "false",
+
+ # JSValue::toInt*() / JSValue::toUint*() will convert undefined to 0.
+ "byte" => "0",
+ "long long" => "0",
+ "long" => "0",
+ "octet" => "0",
+ "short" => "0",
+ "unsigned long long" => "0",
+ "unsigned long" => "0",
+ "unsigned short" => "0",
+
+ # toNumber() / toFloat() convert undefined to NaN.
+ "double" => "NaN",
+ "float" => "NaN",
+ "unrestricted double" => "NaN",
+ "unrestricted float" => "NaN",
+);
+
+sub WillConvertUndefinedToDefaultParameterValue
{
- my $outputArray = shift;
- my $function = shift;
- my $interface = shift;
- my $numParameters = shift;
- my $interfaceName = shift;
- my $functionImplementationName = shift;
- my $svgPropertyType = shift;
- my $svgPropertyOrListPropertyType = shift;
- my $svgListPropertyType = shift;
+ my ($parameterType, $defaultValue) = @_;
+
+ my $automaticallyGeneratedDefaultValue = $automaticallyGeneratedDefaultValues{$parameterType->name};
+ return 1 if defined $automaticallyGeneratedDefaultValue && $automaticallyGeneratedDefaultValue eq $defaultValue;
- my $argsIndex = 0;
- my $hasOptionalArguments = 0;
- my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
+ return 1 if $defaultValue eq "null" && $codeGenerator->IsWrapperType($parameterType);
+ return 1 if $defaultValue eq "[]" && $codeGenerator->IsDictionaryType($parameterType);
+ return 0;
+}
+
+sub NeedsExplicitPropagateExceptionCall
+{
+ my ($function) = @_;
+
+ return 0 unless $function->extendedAttributes->{MayThrowException};
+
+ return 1 if $function->type && $function->type->name eq "void";
+ return 1 if IsReturningPromise($function);
+
+ return 0;
+}
+
+sub GenerateParametersCheck
+{
+ my ($outputArray, $function, $interface, $functionImplementationName) = @_;
+
+ my $interfaceName = $interface->type->name;
+ my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
my @arguments;
my $functionName;
- my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
+ my $implementedBy = $function->extendedAttributes->{ImplementedBy};
+ my $numArguments = @{$function->arguments};
+ my $conditional = $function->extendedAttributes->{Conditional};
+
if ($implementedBy) {
- AddToImplIncludes("${implementedBy}.h");
- unshift(@arguments, "&impl") if !$function->isStatic;
- $functionName = "${implementedBy}::${functionImplementationName}";
+ AddToImplIncludes("${implementedBy}.h", $conditional);
+ unshift(@arguments, "impl") if !$function->isStatic;
+ $functionName = "WebCore::${implementedBy}::${functionImplementationName}";
} elsif ($function->isStatic) {
$functionName = "${interfaceName}::${functionImplementationName}";
- } elsif ($svgPropertyOrListPropertyType and !$svgListPropertyType) {
- $functionName = "podImpl.${functionImplementationName}";
} else {
$functionName = "impl.${functionImplementationName}";
}
- if (!$function->signature->extendedAttributes->{"Constructor"}) {
- push(@arguments, GenerateCallWith($function->signature->extendedAttributes->{"CallWith"}, \@$outputArray, "JSValue::encode(jsUndefined())", $function));
+ my $quotedFunctionName;
+ if (!$function->extendedAttributes->{Constructor}) {
+ my $name = $function->name;
+ $quotedFunctionName = "\"$name\"";
+ push(@arguments, GenerateCallWithUsingPointers($function->extendedAttributes->{CallWith}, \@$outputArray, "JSValue::encode(jsUndefined())", $function));
+ } else {
+ $quotedFunctionName = "nullptr";
}
- $implIncludes{"ExceptionCode.h"} = 1;
- $implIncludes{"JSDOMBinding.h"} = 1;
+ my $argumentIndex = 0;
+ foreach my $argument (@{$function->arguments}) {
+ my $type = $argument->type;
- foreach my $parameter (@{$function->parameters}) {
- my $argType = $parameter->type;
-
- # Optional arguments with [Optional] should generate an early call with fewer arguments.
- # Optional arguments with [Optional=...] should not generate the early call.
- # Optional Dictionary arguments always considered to have default of empty dictionary.
- my $optional = $parameter->isOptional;
- my $defaultAttribute = $parameter->extendedAttributes->{"Default"};
- if ($optional && !$defaultAttribute && $argType ne "Dictionary" && !$codeGenerator->IsCallbackInterface($parameter->type)) {
- # Generate early call if there are enough parameters.
- if (!$hasOptionalArguments) {
- push(@$outputArray, "\n size_t argsCount = exec->argumentCount();\n");
- $hasOptionalArguments = 1;
- }
- push(@$outputArray, " if (argsCount <= $argsIndex) {\n");
+ die "Optional arguments of non-nullable wrapper types are not supported" if $argument->isOptional && !$type->isNullable && $codeGenerator->IsWrapperType($type);
+ die "Optional arguments preceding variadic arguments are not supported" if ($argument->isOptional && @{$function->arguments}[$numArguments - 1]->isVariadic);
+
+ if ($argument->isOptional && !defined($argument->default)) {
+ # As per Web IDL, optional dictionary arguments are always considered to have a default value of an empty dictionary, unless otherwise specified.
+ $argument->default("[]") if $codeGenerator->IsDictionaryType($type);
- my @optionalCallbackArguments = @arguments;
- push(@optionalCallbackArguments, "ec") if $raisesException;
- my $functionString = "$functionName(" . join(", ", @optionalCallbackArguments) . ")";
- GenerateImplementationFunctionCall($function, $functionString, " " x 2, $svgPropertyType, $interfaceName);
- push(@$outputArray, " }\n\n");
+ # Treat undefined the same as an empty sequence Or frozen array.
+ $argument->default("[]") if $codeGenerator->IsSequenceOrFrozenArrayType($type);
+
+ # We use undefined as default value for optional arguments of type 'any' unless specified otherwise.
+ $argument->default("undefined") if $type->name eq "any";
+
+ # We use the null string as default value for arguments of type DOMString unless specified otherwise.
+ $argument->default("null") if $codeGenerator->IsStringType($type);
+
+ # As per Web IDL, passing undefined for a nullable argument is treated as null. Therefore, use null as
+ # default value for nullable arguments unless otherwise specified.
+ $argument->default("null") if $type->isNullable;
+
+ # For callback arguments, the generated bindings treat undefined as null, so use null as implicit default value.
+ $argument->default("null") if $codeGenerator->IsCallbackInterface($type) || $codeGenerator->IsCallbackFunction($type);
}
- my $name = $parameter->name;
-
- if ($argType eq "XPathNSResolver") {
- push(@$outputArray, " RefPtr<XPathNSResolver> customResolver;\n");
- push(@$outputArray, " XPathNSResolver* resolver = toXPathNSResolver(exec->argument($argsIndex));\n");
- push(@$outputArray, " if (!resolver) {\n");
- push(@$outputArray, " customResolver = JSCustomXPathNSResolver::create(exec, exec->argument($argsIndex));\n");
- push(@$outputArray, " if (exec->hadException())\n");
- push(@$outputArray, " return JSValue::encode(jsUndefined());\n");
- push(@$outputArray, " resolver = customResolver.get();\n");
- push(@$outputArray, " }\n");
- } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) {
- my $callbackClassName = GetCallbackClassName($argType);
- $implIncludes{"$callbackClassName.h"} = 1;
- if ($optional) {
- push(@$outputArray, " RefPtr<$argType> $name;\n");
- push(@$outputArray, " if (!exec->argument($argsIndex).isUndefinedOrNull()) {\n");
- push(@$outputArray, " if (!exec->uncheckedArgument($argsIndex).isFunction())\n");
- push(@$outputArray, " return throwVMTypeError(exec);\n");
- if ($function->isStatic) {
- AddToImplIncludes("CallbackFunction.h");
- push(@$outputArray, " $name = createFunctionOnlyCallback<${callbackClassName}>(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->uncheckedArgument($argsIndex));\n");
- } else {
- push(@$outputArray, " $name = ${callbackClassName}::create(asObject(exec->uncheckedArgument($argsIndex)), castedThis->globalObject());\n");
- }
- push(@$outputArray, " }\n");
- } else {
- push(@$outputArray, " if (!exec->argument($argsIndex).isFunction())\n");
- push(@$outputArray, " return throwVMTypeError(exec);\n");
- if ($function->isStatic) {
- AddToImplIncludes("CallbackFunction.h");
- push(@$outputArray, " RefPtr<$argType> $name = createFunctionOnlyCallback<${callbackClassName}>(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->uncheckedArgument($argsIndex));\n");
- } else {
- push(@$outputArray, " RefPtr<$argType> $name = ${callbackClassName}::create(asObject(exec->uncheckedArgument($argsIndex)), castedThis->globalObject());\n");
- }
- }
- } elsif ($parameter->extendedAttributes->{"Clamp"}) {
- my $nativeValue = "${name}NativeValue";
- push(@$outputArray, " $argType $name = 0;\n");
- push(@$outputArray, " double $nativeValue = exec->argument($argsIndex).toNumber(exec);\n");
- push(@$outputArray, " if (exec->hadException())\n");
- push(@$outputArray, " return JSValue::encode(jsUndefined());\n\n");
- push(@$outputArray, " if (!std::isnan($nativeValue))\n");
- push(@$outputArray, " $name = clampTo<$argType>($nativeValue);\n\n");
- } elsif ($parameter->isVariadic) {
- my $nativeElementType;
- if ($argType eq "DOMString") {
- $nativeElementType = "String";
- } else {
- $nativeElementType = GetNativeType($argType);
- if ($nativeElementType =~ />$/) {
- $nativeElementType .= " ";
- }
- }
+ my $name = $argument->name;
+ my $value = $name;
- if (!IsNativeType($argType)) {
- push(@$outputArray, " Vector<$nativeElementType> $name;\n");
- push(@$outputArray, " for (unsigned i = $argsIndex, count = exec->argumentCount(); i < count; ++i) {\n");
- push(@$outputArray, " if (!exec->uncheckedArgument(i).inherits(JS${argType}::info()))\n");
- push(@$outputArray, " return throwVMTypeError(exec);\n");
- push(@$outputArray, " $name.append(to$argType(exec->uncheckedArgument(i)));\n");
- push(@$outputArray, " }\n")
- } else {
- push(@$outputArray, " Vector<$nativeElementType> $name = toNativeArguments<$nativeElementType>(exec, $argsIndex);\n");
- # Check if the type conversion succeeded.
- push(@$outputArray, " if (exec->hadException())\n");
- push(@$outputArray, " return JSValue::encode(jsUndefined());\n");
- }
+ if ($argument->isVariadic) {
+ AddToImplIncludes("JSDOMConvertVariadic.h", $conditional);
+ AddToImplIncludesForIDLType($type, $conditional);
+
+ my $IDLType = GetIDLType($interface, $type);
- } elsif ($codeGenerator->IsEnumType($argType)) {
- $implIncludes{"<runtime/Error.h>"} = 1;
+ push(@$outputArray, " auto ${name} = convertVariadicArguments<${IDLType}>(*state, ${argumentIndex});\n");
+ push(@$outputArray, " RETURN_IF_EXCEPTION(throwScope, encodedJSValue());\n");
+
+ $value = "WTFMove(${name}.arguments.value())";
+
+ } elsif ($codeGenerator->IsEnumType($type)) {
+ AddToImplIncludes("<runtime/Error.h>", $conditional);
+
+ my $className = GetEnumerationClassName($type, $interface);
+ my $nativeType = $className;
+ my $optionalValue = "optionalValue";
+ my $defineOptionalValue = "auto optionalValue";
+ my $indent = "";
- my $argValue = "exec->argument($argsIndex)";
- push(@$outputArray, " const String ${name}(${argValue}.isEmpty() ? String() : ${argValue}.toString(exec)->value(exec));\n");
- push(@$outputArray, " if (exec->hadException())\n");
- push(@$outputArray, " return JSValue::encode(jsUndefined());\n");
+ die "Variadic argument is already handled here" if $argument->isVariadic;
+ my $argumentLookupMethod = $argument->isOptional ? "argument" : "uncheckedArgument";
- my @enumValues = $codeGenerator->ValidEnumValues($argType);
- my @enumChecks = ();
- foreach my $enumValue (@enumValues) {
- push(@enumChecks, "${name} != \"$enumValue\"");
+ if ($argument->isOptional && !defined($argument->default)) {
+ $nativeType = "std::optional<$className>";
+ $optionalValue = $name;
+ $defineOptionalValue = $name;
}
- push (@$outputArray, " if (" . join(" && ", @enumChecks) . ")\n");
- push (@$outputArray, " return throwVMTypeError(exec);\n");
- } else {
- # 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 semantics, 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"}) {
- $implIncludes{"<runtime/Error.h>"} = 1;
-
- my $argValue = "exec->argument($argsIndex)";
- if ($codeGenerator->IsWrapperType($argType)) {
- push(@$outputArray, " if (exec->argumentCount() > $argsIndex && !${argValue}.isUndefinedOrNull() && !${argValue}.inherits(JS${argType}::info()))\n");
- push(@$outputArray, " return throwVMTypeError(exec);\n");
+
+ push(@$outputArray, " auto ${name}Value = state->$argumentLookupMethod($argumentIndex);\n");
+ push(@$outputArray, " $nativeType $name;\n");
+
+ if ($argument->isOptional) {
+ if (!defined $argument->default) {
+ push(@$outputArray, " if (!${name}Value.isUndefined()) {\n");
+ } else {
+ push(@$outputArray, " if (${name}Value.isUndefined())\n");
+ push(@$outputArray, " $name = " . GenerateDefaultValue($interface, $argument, $argument->type, $argument->default) . ";\n");
+ push(@$outputArray, " else {\n");
}
+ $indent = " ";
}
- push(@$outputArray, " " . GetNativeTypeFromSignature($parameter) . " $name(" . JSValueToNative($parameter, $optional && $defaultAttribute && $defaultAttribute eq "NullString" ? "argumentOrNull(exec, $argsIndex)" : "exec->argument($argsIndex)") . ");\n");
+ $implIncludes{"JS$className.h"} = 1 if $codeGenerator->IsExternalEnumType($type);
+ push(@$outputArray, "$indent $defineOptionalValue = parseEnumeration<$className>(*state, ${name}Value);\n");
+ push(@$outputArray, "$indent RETURN_IF_EXCEPTION(throwScope, encodedJSValue());\n");
+ push(@$outputArray, "$indent if (UNLIKELY(!$optionalValue))\n");
+ push(@$outputArray, "$indent return throwArgumentMustBeEnumError(*state, throwScope, $argumentIndex, \"$name\", \"$visibleInterfaceName\", $quotedFunctionName, expectedEnumerationValues<$className>());\n");
+ push(@$outputArray, "$indent $name = optionalValue.value();\n") if $optionalValue ne $name;
- # If a parameter is "an index" and it's negative it should throw an INDEX_SIZE_ERR exception.
- # But this needs to be done in the bindings, because the type is unsigned and the fact that it
- # was negative will be lost by the time we're inside the DOM.
- if ($parameter->extendedAttributes->{"IsIndex"}) {
- push(@$outputArray, " if ($name < 0) {\n");
- push(@$outputArray, " setDOMException(exec, INDEX_SIZE_ERR);\n");
- push(@$outputArray, " return JSValue::encode(jsUndefined());\n");
- push(@$outputArray, " }\n");
- }
+ push(@$outputArray, " }\n") if $indent ne "";
+ } else {
+ my $outer;
+ my $inner;
+ my $nativeType = GetNativeType($interface, $argument->type);
+
+ die "Variadic argument is already handled here" if $argument->isVariadic;
+ my $argumentLookupMethod = $argument->isOptional ? "argument" : "uncheckedArgument";
+
+ if ($argument->isOptional && defined($argument->default) && !WillConvertUndefinedToDefaultParameterValue($type, $argument->default)) {
+ my $defaultValue = $argument->default;
- # Check if the type conversion succeeded.
- push(@$outputArray, " if (exec->hadException())\n");
- push(@$outputArray, " return JSValue::encode(jsUndefined());\n");
+ $defaultValue = GenerateDefaultValue($interface, $argument, $argument->type, $argument->default);
- if ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $interfaceName =~ /List$/) {
- push(@$outputArray, " if (!$name) {\n");
- push(@$outputArray, " setDOMException(exec, TYPE_MISMATCH_ERR);\n");
- push(@$outputArray, " return JSValue::encode(jsUndefined());\n");
- push(@$outputArray, " }\n");
+ $outer = "state->$argumentLookupMethod($argumentIndex).isUndefined() ? $defaultValue : ";
+ $inner = "state->uncheckedArgument($argumentIndex)";
+ } elsif ($argument->isOptional && !defined($argument->default)) {
+ # Use std::optional<>() for optional arguments that are missing or undefined and that do not have a default value in the IDL.
+ $outer = "state->$argumentLookupMethod($argumentIndex).isUndefined() ? std::optional<$nativeType>() : ";
+ $inner = "state->uncheckedArgument($argumentIndex)";
+ } else {
+ $outer = "";
+ $inner = "state->$argumentLookupMethod($argumentIndex)";
}
+
+ my $globalObjectReference = $function->isStatic ? "*jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())" : "*castedThis->globalObject()";
+ my $argumentExceptionThrower = GetArgumentExceptionThrower($interface, $argument, $argumentIndex, $quotedFunctionName);
+
+ my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $argument, $inner, $conditional, "state", "*state", "*castedThis", $globalObjectReference, $argumentExceptionThrower);
+
+ push(@$outputArray, " auto $name = ${outer}${nativeValue};\n");
+ push(@$outputArray, " RETURN_IF_EXCEPTION(throwScope, encodedJSValue());\n") if $mayThrowException;
+
+ $value = PassArgumentExpression($name, $argument);
}
- if ($argType eq "NodeFilter" || ($codeGenerator->IsTypedArrayType($argType) and not $argType eq "ArrayBuffer")) {
- push @arguments, "$name.get()";
- } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $interfaceName =~ /List$/) {
- push @arguments, "$name->propertyReference()";
- } else {
- push @arguments, $name;
+ push(@arguments, $value);
+ $argumentIndex++;
+ }
+
+ push(@arguments, "WTFMove(promise)") if IsReturningPromise($function);
+
+ my $functionString = "$functionName(" . join(", ", @arguments) . ")";
+ $functionString = "propagateException(*state, throwScope, $functionString)" if NeedsExplicitPropagateExceptionCall($function);
+
+ return ($functionString, scalar @arguments);
+}
+
+sub GenerateDictionaryHeader
+{
+ my ($object, $dictionary, $className, $enumerations, $otherDictionaries) = @_;
+
+ # - Add default header template and header protection.
+ push(@headerContentHeader, GenerateHeaderContentHeader($dictionary));
+
+ $headerIncludes{"$className.h"} = 1;
+ $headerIncludes{"JSDOMConvert.h"} = 1;
+
+ push(@headerContent, "\nnamespace WebCore {\n\n");
+ push(@headerContent, GenerateDictionaryHeaderContent($dictionary, $className));
+ push(@headerContent, GenerateEnumerationsHeaderContent($dictionary, $enumerations));
+ push(@headerContent, GenerateDictionariesHeaderContent($dictionary, $otherDictionaries)) if $otherDictionaries;
+ push(@headerContent, "} // namespace WebCore\n");
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
+ push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+
+ # - Generate dependencies.
+ if ($writeDependencies) {
+ my @ancestors;
+ my $parentType = $dictionary->parentType;
+ while (defined($parentType)) {
+ push(@ancestors, $parentType->name) if $codeGenerator->IsExternalDictionaryType($parentType);
+ my $parentDictionary = $codeGenerator->GetDictionaryByType($parentType);
+ assert("Unable to find definition for dictionary named '" . $parentType->name . "'!") unless $parentDictionary;
+ $parentType = $parentDictionary->parentType;
}
- $argsIndex++;
+ push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestors), "\n");
+ push(@depsContent, map { "$_.idl :\n" } @ancestors);
}
+}
+
+sub GenerateDictionaryImplementation
+{
+ my ($object, $dictionary, $className, $enumerations, $otherDictionaries) = @_;
+
+ # - Add default header template
+ push(@implContentHeader, GenerateImplementationContentHeader($dictionary));
- push(@arguments, "ec") if $raisesException;
+ push(@implContent, "\nusing namespace JSC;\n\n");
+ push(@implContent, "namespace WebCore {\n\n");
+ push(@implContent, GenerateDictionaryImplementationContent($dictionary, $className));
+ push(@implContent, GenerateEnumerationsImplementationContent($dictionary, $enumerations));
+ push(@implContent, GenerateDictionariesImplementationContent($dictionary, $otherDictionaries)) if $otherDictionaries;
+ push(@implContent, "} // namespace WebCore\n");
- return ("$functionName(" . join(", ", @arguments) . ")", scalar @arguments);
+ my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
+ push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
}
-sub GenerateCallbackHeader
+sub GenerateCallbackFunctionHeader
{
- my $object = shift;
- my $interface = shift;
+ my ($object, $callbackFunction, $enumerations, $dictionaries) = @_;
- my $interfaceName = $interface->name;
- my $className = "JS$interfaceName";
+ push(@headerContentHeader, GenerateHeaderContentHeader($callbackFunction));
- # - Add default header template and header protection
- push(@headerContentHeader, GenerateHeaderContentHeader($interface));
+ push(@headerContent, "\nnamespace WebCore {\n\n");
+
+ my @functions = ();
+ push(@functions, $callbackFunction->operation);
+ my @constants = ();
- $headerIncludes{"ActiveDOMCallback.h"} = 1;
- $headerIncludes{"$interfaceName.h"} = 1;
- $headerIncludes{"JSCallbackData.h"} = 1;
- $headerIncludes{"<wtf/Forward.h>"} = 1;
+ $object->GenerateCallbackHeaderContent($callbackFunction, \@functions, \@constants, \@headerContent, \%headerIncludes);
+
+ push(@headerContent, GenerateEnumerationsHeaderContent($callbackFunction, $enumerations));
+ push(@headerContent, GenerateDictionariesHeaderContent($callbackFunction, $dictionaries));
+
+ push(@headerContent, "} // namespace WebCore\n");
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($callbackFunction);
+ push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+}
+
+sub GenerateCallbackFunctionImplementation
+{
+ my ($object, $callbackFunction, $enumerations, $dictionaries) = @_;
+
+ push(@implContentHeader, GenerateImplementationContentHeader($callbackFunction));
+
+ push(@implContent, "\nusing namespace JSC;\n\n");
+ push(@implContent, "namespace WebCore {\n\n");
+
+ push(@implContent, GenerateEnumerationsImplementationContent($callbackFunction, $enumerations));
+ push(@implContent, GenerateDictionariesImplementationContent($callbackFunction, $dictionaries));
+
+ my @functions = ();
+ push(@functions, $callbackFunction->operation);
+ my @constants = ();
+
+ $object->GenerateCallbackImplementationContent($callbackFunction, \@functions, \@constants, \@implContent, \%implIncludes);
+
+ push(@implContent, "} // namespace WebCore\n");
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($callbackFunction);
+ push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+}
+
+sub GenerateCallbackInterfaceHeader
+{
+ my ($object, $callbackInterface, $enumerations, $dictionaries) = @_;
+
+ push(@headerContentHeader, GenerateHeaderContentHeader($callbackInterface));
push(@headerContent, "\nnamespace WebCore {\n\n");
- push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
- push(@headerContent, "public:\n");
+
+ $object->GenerateCallbackHeaderContent($callbackInterface, $callbackInterface->functions, $callbackInterface->constants, \@headerContent, \%headerIncludes);
+
+ push(@headerContent, GenerateEnumerationsHeaderContent($callbackInterface, $enumerations));
+ push(@headerContent, GenerateDictionariesHeaderContent($callbackInterface, $dictionaries));
+
+ push(@headerContent, "} // namespace WebCore\n");
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($callbackInterface);
+ push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+}
+
+sub GenerateCallbackInterfaceImplementation
+{
+ my ($object, $callbackInterface, $enumerations, $dictionaries) = @_;
+
+ push(@implContentHeader, GenerateImplementationContentHeader($callbackInterface));
+
+ push(@implContent, "\nusing namespace JSC;\n\n");
+ push(@implContent, "namespace WebCore {\n\n");
+
+ push(@implContent, GenerateEnumerationsImplementationContent($callbackInterface, $enumerations));
+ push(@implContent, GenerateDictionariesImplementationContent($callbackInterface, $dictionaries));
+
+ $object->GenerateCallbackImplementationContent($callbackInterface, $callbackInterface->functions, $callbackInterface->constants, \@implContent, \%implIncludes);
+
+ push(@implContent, "} // namespace WebCore\n");
+
+ my $conditionalString = $codeGenerator->GenerateConditionalString($callbackInterface);
+ push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+}
+
+sub GenerateCallbackHeaderContent
+{
+ my ($object, $interfaceOrCallback, $functions, $constants, $contentRef, $includesRef) = @_;
+
+ my $name = $interfaceOrCallback->type->name;
+ my $callbackDataType = GetJSCallbackDataType($interfaceOrCallback);
+ my $className = "JS${name}";
+
+ $includesRef->{"ActiveDOMCallback.h"} = 1;
+ $includesRef->{"JSCallbackData.h"} = 1;
+ $includesRef->{"<wtf/Forward.h>"} = 1;
+ $includesRef->{"${name}.h"} = 1;
+
+ push(@$contentRef, "class $className : public ${name}, public ActiveDOMCallback {\n");
+ push(@$contentRef, "public:\n");
# The static create() method.
- push(@headerContent, " static PassRefPtr<$className> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject)\n");
- push(@headerContent, " {\n");
- push(@headerContent, " return adoptRef(new $className(callback, globalObject));\n");
- push(@headerContent, " }\n\n");
+ push(@$contentRef, " static Ref<$className> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject)\n");
+ push(@$contentRef, " {\n");
+ push(@$contentRef, " return adoptRef(*new ${className}(callback, globalObject));\n");
+ push(@$contentRef, " }\n\n");
- # ScriptExecutionContext
- push(@headerContent, " virtual ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); }\n\n");
+ push(@$contentRef, " virtual ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); }\n\n");
- # Destructor
- push(@headerContent, " virtual ~$className();\n");
+ push(@$contentRef, " virtual ~$className();\n");
- if ($interface->extendedAttributes->{"CallbackNeedsOperatorEqual"}) {
- push(@headerContent, " virtual bool operator==(const $interfaceName&) const;\n\n")
- }
+ push(@$contentRef, " ${callbackDataType}* callbackData() { return m_data; }\n");
+
+ push(@$contentRef, " static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);\n") if @{$constants};
+
+ push(@$contentRef, " virtual bool operator==(const ${name}&) const;\n\n") if $interfaceOrCallback->extendedAttributes->{CallbackNeedsOperatorEqual};
# Functions
- my $numFunctions = @{$interface->functions};
+ my $numFunctions = @{$functions};
if ($numFunctions > 0) {
- push(@headerContent, "\n // Functions\n");
- foreach my $function (@{$interface->functions}) {
- my @params = @{$function->parameters};
- if (!$function->signature->extendedAttributes->{"Custom"} &&
- !(GetNativeType($function->signature->type) eq "bool")) {
- push(@headerContent, " COMPILE_ASSERT(false)");
+ push(@$contentRef, "\n // Functions\n");
+ foreach my $function (@{$functions}) {
+ my @arguments = ();
+ foreach my $argument (@{$function->arguments}) {
+ push(@arguments, GetNativeTypeForCallbacks($argument->type, $interfaceOrCallback) . " " . $argument->name);
}
- push(@headerContent, " virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "(");
+ # FIXME: Add support for non-void return types (the bool actually is returning exception state), for non-custom functions.
+ my $nativeReturnType = $function->extendedAttributes->{Custom} ? GetNativeTypeForCallbacks($function->type, $interfaceOrCallback) : "bool";
+
+ # FIXME: Change the default name (used for callback functions) to something other than handleEvent. It makes little sense.
+ my $functionName = $function->name ? $function->name : "handleEvent";
- my @args = ();
- foreach my $param (@params) {
- push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
- }
- push(@headerContent, join(", ", @args));
-
- push(@headerContent, ");\n");
+ push(@$contentRef, " virtual ${nativeReturnType} ${functionName}(" . join(", ", @arguments) . ");\n");
}
}
- push(@headerContent, "\nprivate:\n");
+ push(@$contentRef, "\nprivate:\n");
# Constructor
- push(@headerContent, " $className(JSC::JSObject* callback, JSDOMGlobalObject*);\n\n");
+ push(@$contentRef, " ${className}(JSC::JSObject*, JSDOMGlobalObject*);\n\n");
# Private members
- push(@headerContent, " JSCallbackData* m_data;\n");
- push(@headerContent, "};\n\n");
+ push(@$contentRef, " ${callbackDataType}* m_data;\n");
+ push(@$contentRef, "};\n\n");
- push(@headerContent, "} // namespace WebCore\n\n");
- my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
- push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
- push(@headerContent, "#endif\n");
+ # toJS().
+ push(@$contentRef, "JSC::JSValue toJS(${name}&);\n");
+ push(@$contentRef, "inline JSC::JSValue toJS(${name}* impl) { return impl ? toJS(*impl) : JSC::jsNull(); }\n\n");
}
-sub GenerateCallbackImplementation
+sub GenerateCallbackImplementationContent
{
- my ($object, $interface) = @_;
+ my ($object, $interfaceOrCallback, $functions, $constants, $contentRef, $includesRef) = @_;
- my $interfaceName = $interface->name;
- my $className = "JS$interfaceName";
+ my $name = $interfaceOrCallback->type->name;
+ my $callbackDataType = GetJSCallbackDataType($interfaceOrCallback);
+ my $visibleName = $codeGenerator->GetVisibleInterfaceName($interfaceOrCallback);
+ my $className = "JS${name}";
- # - Add default header template
- push(@implContentHeader, GenerateImplementationContentHeader($interface));
-
- $implIncludes{"ScriptExecutionContext.h"} = 1;
- $implIncludes{"<runtime/JSLock.h>"} = 1;
-
- @implContent = ();
-
- push(@implContent, "\nusing namespace JSC;\n\n");
- push(@implContent, "namespace WebCore {\n\n");
+ $includesRef->{"ScriptExecutionContext.h"} = 1;
+ $includesRef->{"<runtime/JSLock.h>"} = 1;
# Constructor
- push(@implContent, "${className}::${className}(JSObject* callback, JSDOMGlobalObject* globalObject)\n");
- if ($interface->extendedAttributes->{"CallbackNeedsOperatorEqual"}) {
- push(@implContent, " : ${interfaceName}(${className}Type)\n");
+ push(@$contentRef, "${className}::${className}(JSObject* callback, JSDOMGlobalObject* globalObject)\n");
+ if ($interfaceOrCallback->extendedAttributes->{CallbackNeedsOperatorEqual}) {
+ push(@$contentRef, " : ${name}(${className}Type)\n");
} else {
- push(@implContent, " : ${interfaceName}()\n");
+ push(@$contentRef, " : ${name}()\n");
}
- push(@implContent, " , ActiveDOMCallback(globalObject->scriptExecutionContext())\n");
- push(@implContent, " , m_data(new JSCallbackData(callback, globalObject))\n");
- push(@implContent, "{\n");
- push(@implContent, "}\n\n");
+ push(@$contentRef, " , ActiveDOMCallback(globalObject->scriptExecutionContext())\n");
+ push(@$contentRef, " , m_data(new ${callbackDataType}(callback, globalObject, this))\n");
+ push(@$contentRef, "{\n");
+ push(@$contentRef, "}\n\n");
# Destructor
- push(@implContent, "${className}::~${className}()\n");
- push(@implContent, "{\n");
- push(@implContent, " ScriptExecutionContext* context = scriptExecutionContext();\n");
- push(@implContent, " // When the context is destroyed, all tasks with a reference to a callback\n");
- push(@implContent, " // should be deleted. So if the context is 0, we are on the context thread.\n");
- push(@implContent, " if (!context || context->isContextThread())\n");
- push(@implContent, " delete m_data;\n");
- push(@implContent, " else\n");
- push(@implContent, " context->postTask(DeleteCallbackDataTask::create(m_data));\n");
- push(@implContent, "#ifndef NDEBUG\n");
- push(@implContent, " m_data = 0;\n");
- push(@implContent, "#endif\n");
- push(@implContent, "}\n\n");
+ push(@$contentRef, "${className}::~${className}()\n");
+ push(@$contentRef, "{\n");
+ push(@$contentRef, " ScriptExecutionContext* context = scriptExecutionContext();\n");
+ push(@$contentRef, " // When the context is destroyed, all tasks with a reference to a callback\n");
+ push(@$contentRef, " // should be deleted. So if the context is 0, we are on the context thread.\n");
+ push(@$contentRef, " if (!context || context->isContextThread())\n");
+ push(@$contentRef, " delete m_data;\n");
+ push(@$contentRef, " else\n");
+ push(@$contentRef, " context->postTask(DeleteCallbackDataTask(m_data));\n");
+ push(@$contentRef, "#ifndef NDEBUG\n");
+ push(@$contentRef, " m_data = nullptr;\n");
+ push(@$contentRef, "#endif\n");
+ push(@$contentRef, "}\n\n");
+
+ if ($interfaceOrCallback->extendedAttributes->{CallbackNeedsOperatorEqual}) {
+ push(@$contentRef, "bool ${className}::operator==(const ${name}& other) const\n");
+ push(@$contentRef, "{\n");
+ push(@$contentRef, " if (other.type() != type())\n");
+ push(@$contentRef, " return false;\n");
+ push(@$contentRef, " return static_cast<const ${className}*>(&other)->m_data->callback() == m_data->callback();\n");
+ push(@$contentRef, "}\n\n");
+ }
+
+ # Constants.
+ my $numConstants = @{$constants};
+ if ($numConstants > 0) {
+ GenerateConstructorDeclaration($contentRef, $className, $interfaceOrCallback, $name);
- if ($interface->extendedAttributes->{"CallbackNeedsOperatorEqual"}) {
- push(@implContent, "bool ${className}::operator==(const ${interfaceName}& other) const\n");
- push(@implContent, "{\n");
- push(@implContent, " if (other.type() != type())\n");
- push(@implContent, " return false;\n");
- push(@implContent, " return static_cast<const ${className}*>(&other)->m_data->callback() == m_data->callback();\n");
- push(@implContent, "}\n\n");
+ my $hashSize = 0;
+ my $hashName = $className . "ConstructorTable";
+
+ my @hashKeys = ();
+ my @hashValue1 = ();
+ my @hashValue2 = ();
+ my @hashSpecials = ();
+ my %conditionals = ();
+
+ foreach my $constant (@{$constants}) {
+ my $name = $constant->name;
+ push(@hashKeys, $name);
+ push(@hashValue1, $constant->value);
+ push(@hashValue2, "0");
+ push(@hashSpecials, "DontDelete | ReadOnly | ConstantInteger");
+
+ my $implementedBy = $constant->extendedAttributes->{ImplementedBy};
+ $implIncludes{"${implementedBy}.h"} = 1 if $implementedBy;
+
+ my $conditional = $constant->extendedAttributes->{Conditional};
+ $conditionals{$name} = $conditional if $conditional;
+
+ $hashSize++;
+ }
+ $object->GenerateHashTable($hashName, $hashSize, \@hashKeys, \@hashSpecials, \@hashValue1, \@hashValue2, \%conditionals, 1) if $hashSize > 0;
+
+ push(@$contentRef, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($interfaceOrCallback));
+
+ GenerateConstructorDefinitions($contentRef, $className, "", $visibleName, $interfaceOrCallback);
+
+ push(@$contentRef, "JSValue ${className}::getConstructor(VM& vm, const JSGlobalObject* globalObject)\n{\n");
+ push(@$contentRef, " return getDOMConstructor<${className}Constructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));\n");
+ push(@$contentRef, "}\n\n");
}
- # Functions
- my $numFunctions = @{$interface->functions};
+
+ # Functions.
+ my $numFunctions = @{$functions};
if ($numFunctions > 0) {
- push(@implContent, "\n// Functions\n");
- foreach my $function (@{$interface->functions}) {
- my @params = @{$function->parameters};
- if ($function->signature->extendedAttributes->{"Custom"} ||
- !(GetNativeType($function->signature->type) eq "bool")) {
- next;
- }
+ foreach my $function (@{$functions}) {
+ next if $function->extendedAttributes->{Custom};
+
+ assert("Unsupport return type: " . $function->type->name . ".") unless $function->type->name eq "void";
- AddIncludesForTypeInImpl($function->signature->type);
- push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "(");
+ AddToIncludesForIDLType($function->type, $includesRef);
+
+ # FIXME: Change the default name (used for callback functions) to something other than handleEvent. It makes little sense.
+ my $functionName = $function->name ? $function->name : "handleEvent";
my @args = ();
- my @argsCheck = ();
- foreach my $param (@params) {
- my $paramName = $param->name;
- AddIncludesForTypeInImpl($param->type, 1);
- push(@args, GetNativeTypeForCallbacks($param->type) . " " . $paramName);
+ foreach my $argument (@{$function->arguments}) {
+ AddToIncludesForIDLType($argument->type, $includesRef, 1);
+ push(@args, GetNativeTypeForCallbacks($argument->type, $interfaceOrCallback) . " " . $argument->name);
}
- 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, " Ref<$className> protect(*this);\n\n");
- push(@implContent, " JSLockHolder lock(m_data->globalObject()->vm());\n\n");
- if (@params) {
- push(@implContent, " ExecState* exec = m_data->globalObject()->globalExec();\n");
+ push(@$contentRef, "bool ${className}::${functionName}(" . join(", ", @args) . ")\n");
+ push(@$contentRef, "{\n");
+ push(@$contentRef, " if (!canInvokeCallback())\n");
+ push(@$contentRef, " return true;\n\n");
+ push(@$contentRef, " Ref<$className> protectedThis(*this);\n\n");
+ push(@$contentRef, " JSLockHolder lock(m_data->globalObject()->vm());\n\n");
+ push(@$contentRef, " ExecState* state = m_data->globalObject()->globalExec();\n");
+ push(@$contentRef, " MarkedArgumentBuffer args;\n");
+
+ foreach my $argument (@{$function->arguments}) {
+ push(@$contentRef, " args.append(" . NativeToJSValueUsingPointers($argument, $interfaceOrCallback, $argument->name, "m_data") . ");\n");
}
- push(@implContent, " MarkedArgumentBuffer args;\n");
-
- foreach my $param (@params) {
- my $paramName = $param->name;
- if ($param->type eq "DOMString") {
- push(@implContent, " args.append(jsStringWithCache(exec, ${paramName}));\n");
- } elsif ($param->type eq "boolean") {
- push(@implContent, " args.append(jsBoolean(${paramName}));\n");
- } elsif ($param->type eq "SerializedScriptValue") {
- push(@implContent, " args.append($paramName ? $paramName->deserialize(exec, m_data->globalObject(), 0) : jsNull());\n");
- } else {
- push(@implContent, " args.append(toJS(exec, m_data->globalObject(), ${paramName}));\n");
- }
+
+ push(@$contentRef, "\n NakedPtr<JSC::Exception> returnedException;\n");
+
+ if (ref($interfaceOrCallback) eq "IDLCallbackFunction") {
+ push(@$contentRef, " m_data->invokeCallback(args, JSCallbackData::CallbackType::Function, Identifier(), returnedException);\n");
+ } else {
+ my $callbackType = $numFunctions > 1 ? "Object" : "FunctionOrObject";
+ push(@$contentRef, " m_data->invokeCallback(args, JSCallbackData::CallbackType::${callbackType}, Identifier::fromString(state, \"${functionName}\"), returnedException);\n");
}
- push(@implContent, "\n bool raisedException = false;\n");
- push(@implContent, " m_data->invokeCallback(args, &raisedException);\n");
- push(@implContent, " return !raisedException;\n");
- push(@implContent, "}\n");
+ # FIXME: We currently just report the exception. We should probably add an extended attribute to indicate when
+ # we want the exception to be rethrown instead.
+ $includesRef->{"JSDOMExceptionHandling.h"} = 1;
+ push(@$contentRef, " if (returnedException)\n");
+ push(@$contentRef, " reportException(state, returnedException);\n");
+ push(@$contentRef, " return !returnedException;\n");
+ push(@$contentRef, "}\n\n");
}
}
- push(@implContent, "\n}\n");
- my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
- push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
-
- if ($interface->extendedAttributes->{"AppleCopyright"}) {
- push(@implContent, split("\r", $endAppleCopyright));
- }
+ # toJS() implementation.
+ push(@$contentRef, "JSC::JSValue toJS(${name}& impl)\n");
+ push(@$contentRef, "{\n");
+ push(@$contentRef, " if (!static_cast<${className}&>(impl).callbackData())\n");
+ push(@$contentRef, " return jsNull();\n\n");
+ push(@$contentRef, " return static_cast<${className}&>(impl).callbackData()->callback();\n\n");
+ push(@$contentRef, "}\n\n");
}
sub GenerateImplementationFunctionCall()
{
- my $function = shift;
- my $functionString = shift;
- my $indent = shift;
- my $svgPropertyType = shift;
- my $interfaceName = shift;
+ my ($function, $functionString, $indent, $interface) = @_;
- my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
-
- if ($function->signature->type eq "void") {
+ if ($function->type->name eq "void" || IsReturningPromise($function)) {
push(@implContent, $indent . "$functionString;\n");
- push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException;
-
- if ($svgPropertyType and !$function->isStatic) {
- if ($raisesException) {
- push(@implContent, $indent . "if (!ec)\n");
- push(@implContent, $indent . " impl.commitChange();\n");
- } else {
- push(@implContent, $indent . "impl.commitChange();\n");
- }
- }
-
push(@implContent, $indent . "return JSValue::encode(jsUndefined());\n");
} else {
my $thisObject = $function->isStatic ? 0 : "castedThis";
- push(@implContent, "\n" . $indent . "JSC::JSValue result = " . NativeToJSValue($function->signature, 1, $interfaceName, $functionString, $thisObject) . ";\n");
- push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException;
+ push(@implContent, $indent . "return JSValue::encode(" . NativeToJSValueUsingPointers($function, $interface, $functionString, $thisObject) . ");\n");
+ }
+}
- if ($codeGenerator->ExtendedAttributeContains($function->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
- push(@implContent, $indent . "if (exec->hadException())\n");
- push(@implContent, $indent . " return JSValue::encode(jsUndefined());\n");
- }
+sub IsValueIterableInterface
+{
+ my $interface = shift;
+ return 0 unless $interface->iterable;
+ return 0 if length $interface->iterable->keyType;
+ # FIXME: See https://webkit.org/b/159140, we should die if the next check is false.
+ return 0 unless GetIndexedGetterFunction($interface);
+ return 1;
+}
- push(@implContent, $indent . "return JSValue::encode(result);\n");
- }
+sub IsKeyValueIterableInterface
+{
+ my $interface = shift;
+ return 0 unless $interface->iterable;
+ return 0 if IsValueIterableInterface($interface);
+ return 1;
}
-sub GetNativeTypeFromSignature
+sub GenerateImplementationIterableFunctions
{
- my $signature = shift;
- my $type = $signature->type;
+ my $interface = shift;
- 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";
- }
+ my $interfaceName = $interface->type->name;
+ my $className = "JS$interfaceName";
+ my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
+
+ AddToImplIncludes("JSDOMIterator.h");
+
+ return unless IsKeyValueIterableInterface($interface);
+
+ my $iteratorName = "${interfaceName}Iterator";
+ my $iteratorPrototypeName = "${interfaceName}IteratorPrototype";
+
+ my $iteratorTraitsName = "${interfaceName}IteratorTraits";
+ my $iteratorTraitsType = $interface->iterable->isKeyValue ? "JSDOMIteratorType::Map" : "JSDOMIteratorType::Set";
+ my $iteratorTraitsKeyType = $interface->iterable->isKeyValue ? GetIDLType($interface, $interface->iterable->keyType) : "void";
+ my $iteratorTraitsValueType = GetIDLType($interface, $interface->iterable->valueType);
+
+ push(@implContent, <<END);
+struct ${iteratorTraitsName} {
+ static constexpr JSDOMIteratorType type = ${iteratorTraitsType};
+ using KeyType = ${iteratorTraitsKeyType};
+ using ValueType = ${iteratorTraitsValueType};
+};
+
+using ${iteratorName} = JSDOMIterator<${className}, ${iteratorTraitsName}>;
+using ${iteratorPrototypeName} = JSDOMIteratorPrototype<${className}, ${iteratorTraitsName}>;
+
+template<>
+const JSC::ClassInfo ${iteratorName}::s_info = { "${visibleInterfaceName} Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(${iteratorName}) };
+
+template<>
+const JSC::ClassInfo ${iteratorPrototypeName}::s_info = { "${visibleInterfaceName} Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(${iteratorPrototypeName}) };
+
+END
+
+ foreach my $function (@{$interface->iterable->functions}) {
+ my $propertyName = $function->name;
+ my $functionName = GetFunctionName($interface, $className, $function);
+
+ if ($propertyName eq "forEach") {
+ push(@implContent, <<END);
+static inline EncodedJSValue ${functionName}Caller(ExecState* state, JS$interfaceName* thisObject, JSC::ThrowScope& throwScope)
+{
+ return JSValue::encode(iteratorForEach<${iteratorName}>(*state, *thisObject, throwScope));
+}
+
+END
+ } else {
+ my $iterationKind = "KeyValue";
+ $iterationKind = "Key" if $propertyName eq "keys";
+ $iterationKind = "Value" if $propertyName eq "values";
+ $iterationKind = "Value" if $propertyName eq "[Symbol.Iterator]" and not $interface->iterable->isKeyValue;
+
+ push(@implContent, <<END);
+static inline EncodedJSValue ${functionName}Caller(ExecState*, JS$interfaceName* thisObject, JSC::ThrowScope&)
+{
+ return JSValue::encode(iteratorCreate<${iteratorName}>(*thisObject, IterationKind::${iterationKind}));
+}
+
+END
+ }
+
+ push(@implContent, <<END);
+JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState* state)
+{
+ return BindingCaller<$className>::callOperation<${functionName}Caller>(state, "${propertyName}");
+}
- return GetNativeType($type);
+END
+ }
}
my %nativeType = (
- "CompareHow" => "Range::CompareHow",
- "DOMString" => "const String&",
- "NodeFilter" => "RefPtr<NodeFilter>",
- "SerializedScriptValue" => "RefPtr<SerializedScriptValue>",
+ "ByteString" => "String",
+ "DOMString" => "String",
+ "USVString" => "String",
"Date" => "double",
- "Dictionary" => "Dictionary",
- "any" => "Deprecated::ScriptValue",
+ "EventListener" => "RefPtr<EventListener>",
+ "SerializedScriptValue" => "RefPtr<SerializedScriptValue>",
+ "XPathNSResolver" => "RefPtr<XPathNSResolver>",
+ "any" => "JSC::JSValue",
+ "object" => "JSC::Strong<JSC::JSObject>",
"boolean" => "bool",
+ "byte" => "int8_t",
"double" => "double",
"float" => "float",
+ "long long" => "int64_t",
+ "long" => "int32_t",
+ "octet" => "uint8_t",
"short" => "int16_t",
- "long" => "int",
- "unsigned long" => "unsigned",
+ "unrestricted double" => "double",
+ "unrestricted float" => "float",
+ "unsigned long long" => "uint64_t",
+ "unsigned long" => "uint32_t",
"unsigned short" => "uint16_t",
- "long long" => "long long",
- "unsigned long long" => "unsigned long long",
- "byte" => "int8_t",
- "octet" => "uint8_t",
- "DOMTimeStamp" => "DOMTimeStamp",
);
-sub GetNativeType
+# http://heycam.github.io/webidl/#dfn-flattened-union-member-types
+sub GetFlattenedMemberTypes
{
- my $type = shift;
+ my ($idlUnionType) = @_;
- my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
- return "${svgNativeType}*" if $svgNativeType;
- return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
- return "RefPtr<${type}>" if $codeGenerator->IsTypedArrayType($type) and not $type eq "ArrayBuffer";
- return $nativeType{$type} if exists $nativeType{$type};
+ my @flattenedMemberTypes = ();
- my $arrayType = $codeGenerator->GetArrayType($type);
- my $sequenceType = $codeGenerator->GetSequenceType($type);
- my $arrayOrSequenceType = $arrayType || $sequenceType;
+ foreach my $memberType (@{$idlUnionType->subtypes}) {
+ if ($memberType->isUnion) {
+ push(@flattenedMemberTypes, GetFlattenedMemberTypes($memberType));
+ } else {
+ push(@flattenedMemberTypes, $memberType);
+ }
+ }
- return "Vector<" . GetNativeVectorInnerType($arrayOrSequenceType) . ">" if $arrayOrSequenceType;
+ return @flattenedMemberTypes;
+}
- if ($codeGenerator->IsEnumType($type)) {
- return "const String";
+# http://heycam.github.io/webidl/#dfn-number-of-nullable-member-types
+sub GetNumberOfNullableMemberTypes
+{
+ my ($idlUnionType) = @_;
+
+ my $count = 0;
+
+ foreach my $memberType (@{$idlUnionType->subtypes}) {
+ $count++ if $memberType->isNullable;
+ $count += GetNumberOfNullableMemberTypes($memberType) if $memberType->isUnion;
}
- # For all other types, the native type is a pointer with same type name as the IDL type.
- return "${type}*";
+ return $count;
+}
+
+sub GetIDLUnionMemberTypes
+{
+ my ($interface, $idlUnionType) = @_;
+
+ my $numberOfNullableMembers = GetNumberOfNullableMemberTypes($idlUnionType);
+ assert("Union types must only have 0 or 1 nullable types.") if $numberOfNullableMembers > 1;
+
+ my @idlUnionMemberTypes = ();
+
+ push(@idlUnionMemberTypes, "IDLNull") if $numberOfNullableMembers == 1;
+
+ foreach my $memberType (GetFlattenedMemberTypes($idlUnionType)) {
+ push(@idlUnionMemberTypes, GetBaseIDLType($interface, $memberType));
+ }
+
+ return @idlUnionMemberTypes;
+}
+
+sub GetBaseIDLType
+{
+ my ($interface, $type, $context) = @_;
+
+ if ($context && $context->extendedAttributes->{OverrideIDLType}) {
+ return $context->extendedAttributes->{OverrideIDLType};
+ }
+
+ my %IDLTypes = (
+ "any" => "IDLAny",
+ "boolean" => "IDLBoolean",
+ "byte" => "IDLByte",
+ "octet" => "IDLOctet",
+ "short" => "IDLShort",
+ "unsigned short" => "IDLUnsignedShort",
+ "long" => "IDLLong",
+ "unsigned long" => "IDLUnsignedLong",
+ "long long" => "IDLLongLong",
+ "unsigned long long" => "IDLUnsignedLongLong",
+ "float" => "IDLFloat",
+ "unrestricted float" => "IDLUnrestrictedFloat",
+ "double" => "IDLDouble",
+ "unrestricted double" => "IDLUnrestrictedDouble",
+ "DOMString" => "IDLDOMString",
+ "ByteString" => "IDLByteString",
+ "USVString" => "IDLUSVString",
+ "object" => "IDLObject",
+
+ # Non-WebIDL extensions
+ "Date" => "IDLDate",
+ "EventListener" => "IDLEventListener<JSEventListener>",
+ "JSON" => "IDLJSON",
+ "SerializedScriptValue" => "IDLSerializedScriptValue<SerializedScriptValue>",
+ "XPathNSResolver" => "IDLXPathNSResolver<XPathNSResolver>",
+
+ # Convenience type aliases
+ "BufferSource" => "IDLBufferSource",
+ );
+
+ return $IDLTypes{$type->name} if exists $IDLTypes{$type->name};
+ return "IDLEnumeration<" . GetEnumerationClassName($type, $interface) . ">" if $codeGenerator->IsEnumType($type);
+ return "IDLDictionary<" . GetDictionaryClassName($type, $interface) . ">" if $codeGenerator->IsDictionaryType($type);
+ return "IDLSequence<" . GetIDLType($interface, @{$type->subtypes}[0]) . ">" if $codeGenerator->IsSequenceType($type);
+ return "IDLFrozenArray<" . GetIDLType($interface, @{$type->subtypes}[0]) . ">" if $codeGenerator->IsFrozenArrayType($type);
+ return "IDLRecord<" . GetIDLType($interface, @{$type->subtypes}[0]) . ", " . GetIDLType($interface, @{$type->subtypes}[1]) . ">" if $codeGenerator->IsRecordType($type);
+ return "IDLUnion<" . join(", ", GetIDLUnionMemberTypes($interface, $type)) . ">" if $type->isUnion;
+ return "IDLCallbackFunction<" . GetCallbackClassName($type->name) . ">" if $codeGenerator->IsCallbackFunction($type);
+ return "IDLCallbackInterface<" . GetCallbackClassName($type->name) . ">" if $codeGenerator->IsCallbackInterface($type);
+
+ assert("Unknown type '" . $type->name . "'.\n") unless $codeGenerator->IsInterfaceType($type) || $codeGenerator->IsTypedArrayType($type);
+ return "IDLInterface<" . $type->name . ">";
+}
+
+sub GetIDLType
+{
+ my ($interface, $type, $context) = @_;
+
+ my $baseIDLType = GetBaseIDLType($interface, $type, $context);
+ return "IDLNullable<" . $baseIDLType . ">" if $type->isNullable;
+ return $baseIDLType;
}
-sub GetNativeVectorInnerType
+sub GetNativeType
{
- my $arrayOrSequenceType = shift;
+ my ($interface, $type) = @_;
+
+ assert("Not a type") if ref($type) ne "IDLType";
- return "String" if $arrayOrSequenceType eq "DOMString";
- return $nativeType{$arrayOrSequenceType} if exists $nativeType{$arrayOrSequenceType};
- return "RefPtr<${arrayOrSequenceType}> ";
+ my $typeName = $type->name;
+
+ return $nativeType{$typeName} if exists $nativeType{$typeName};
+
+ return GetEnumerationClassName($type, $interface) if $codeGenerator->IsEnumType($type);
+ return GetDictionaryClassName($type, $interface) if $codeGenerator->IsDictionaryType($type);
+ return "Vector<" . GetNativeInnerType(@{$type->subtypes}[0], $interface) . ">" if $codeGenerator->IsSequenceOrFrozenArrayType($type);
+ return "Vector<WTF::KeyValuePair<" . GetNativeInnerType(@{$type->subtypes}[0], $interface) . ", " . GetNativeInnerType(@{$type->subtypes}[1], $interface) . ">>" if $codeGenerator->IsRecordType($type);
+
+ return "RefPtr<${typeName}>" if $codeGenerator->IsTypedArrayType($type) and $typeName ne "ArrayBuffer";
+ return "${typeName}*";
+}
+
+sub GetNativeInnerType
+{
+ my ($innerType, $interface) = @_;
+
+ my $innerTypeName = $innerType->name;
+
+ return $nativeType{$innerTypeName} if exists $nativeType{$innerTypeName};
+
+ return GetEnumerationClassName($innerType, $interface) if $codeGenerator->IsEnumType($innerType);
+ return GetDictionaryClassName($innerType, $interface) if $codeGenerator->IsDictionaryType($innerType);
+ return "Vector<" . GetNativeInnerType(@{$innerType->subtypes}[0], $interface) . ">" if $codeGenerator->IsSequenceOrFrozenArrayType($innerType);
+ return "Vector<WTF::KeyValuePair<" . GetNativeInnerType(@{$innerType->subtypes}[0], $interface) . ", " . GetNativeInnerType(@{$innerType->subtypes}[1], $interface) . ">>" if $codeGenerator->IsRecordType($innerType);
+ return "RefPtr<$innerTypeName>";
}
sub GetNativeTypeForCallbacks
{
- my $type = shift;
- return "PassRefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue";
- return "PassRefPtr<DOMStringList>" if $type eq "DOMStringList";
+ my ($type, $interface) = @_;
- return GetNativeType($type);
+ return "RefPtr<SerializedScriptValue>&&" if $type->name eq "SerializedScriptValue";
+ return "const String&" if $codeGenerator->IsStringType($type);
+ return GetNativeType($interface, $type);
}
-sub GetSVGPropertyTypes
+sub ShouldPassArgumentByReference
{
- my $implType = shift;
+ my ($argument) = @_;
- my $svgPropertyType;
- my $svgListPropertyType;
- my $svgNativeType;
+ my $type = $argument->type;
- 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;
- $headerIncludes{"$svgWrappedNativeType.h"} = 1;
- $headerIncludes{"SVGAnimatedPropertyTearOff.h"} = 1;
- } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
- $svgListPropertyType = $svgWrappedNativeType;
- $headerIncludes{"$svgWrappedNativeType.h"} = 1;
- $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
- } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
- $svgListPropertyType = $svgWrappedNativeType;
- $headerIncludes{"$svgWrappedNativeType.h"} = 1;
- $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
- $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
- } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
- $svgListPropertyType = $svgWrappedNativeType;
- $headerIncludes{"$svgWrappedNativeType.h"} = 1;
- $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
- $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
- }
-
- return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
-}
-
-sub IsNativeType
+ return 0 if $type->isNullable;
+ return 0 if $codeGenerator->IsCallbackInterface($type);
+ return 0 if $codeGenerator->IsCallbackFunction($type);
+ return 0 if !$codeGenerator->IsWrapperType($type) && !$codeGenerator->IsTypedArrayType($type);
+
+ return 1;
+}
+
+sub GetIntegerConversionConfiguration
{
- my $type = shift;
- return exists $nativeType{$type};
+ my $context = shift;
+
+ return "IntegerConversionConfiguration::EnforceRange" if $context->extendedAttributes->{EnforceRange};
+ return "IntegerConversionConfiguration::Clamp" if $context->extendedAttributes->{Clamp};
+ return "IntegerConversionConfiguration::Normal";
}
-sub JSValueToNative
+sub GetStringConversionConfiguration
{
- my $signature = shift;
- my $value = shift;
-
- my $conditional = $signature->extendedAttributes->{"Conditional"};
- my $type = $signature->type;
-
- return "$value.toBoolean(exec)" if $type eq "boolean";
- return "$value.toNumber(exec)" if $type eq "double";
- return "$value.toFloat(exec)" if $type eq "float";
-
- my $intConversion = $signature->extendedAttributes->{"EnforceRange"} ? "EnforceRange" : "NormalConversion";
- return "toInt8(exec, $value, $intConversion)" if $type eq "byte";
- return "toUInt8(exec, $value, $intConversion)" if $type eq "octet";
- return "toInt16(exec, $value, $intConversion)" if $type eq "short";
- return "toUInt16(exec, $value, $intConversion)" if $type eq "unsigned short";
- return "toInt32(exec, $value, $intConversion)" if $type eq "long";
- return "toUInt32(exec, $value, $intConversion)" if $type eq "unsigned long";
- return "toInt64(exec, $value, $intConversion)" if $type eq "long long";
- return "toUInt64(exec, $value, $intConversion)" if $type eq "unsigned long long";
-
- return "valueToDate(exec, $value)" if $type eq "Date";
- return "static_cast<Range::CompareHow>($value.toInt32(exec))" if $type eq "CompareHow";
-
- if ($type eq "DOMString") {
- # FIXME: This implements [TreatNullAs=NullString] and [TreatUndefinedAs=NullString],
- # but the Web IDL spec requires [TreatNullAs=EmptyString] and [TreatUndefinedAs=EmptyString].
- if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") and ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString")) {
- return "valueToStringWithUndefinedOrNullCheck(exec, $value)"
- }
- if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") or $signature->extendedAttributes->{"Reflect"}) {
- return "valueToStringWithNullCheck(exec, $value)"
- }
- # FIXME: Add the case for 'if ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString"))'.
- return "$value.isEmpty() ? String() : $value.toString(exec)->value(exec)";
- }
+ my $context = shift;
- if ($type eq "any") {
- return "exec->vm(), $value";
- }
+ return "StringConversionConfiguration::TreatNullAsEmptyString" if $context->extendedAttributes->{TreatNullAs} && $context->extendedAttributes->{TreatNullAs} eq "EmptyString";
+ return "StringConversionConfiguration::Normal";
+}
- if ($type eq "NodeFilter") {
- AddToImplIncludes("JS$type.h", $conditional);
- return "to$type(exec->vm(), $value)";
- }
+sub JSValueToNativeDOMConvertNeedsThisObject
+{
+ my $type = shift;
- if ($type eq "SerializedScriptValue") {
- AddToImplIncludes("SerializedScriptValue.h", $conditional);
- return "SerializedScriptValue::create(exec, $value, 0, 0)";
- }
+ return 1 if $type->name eq "EventListener";
+ return 0;
+}
- if ($type eq "Dictionary") {
- AddToImplIncludes("Dictionary.h", $conditional);
- return "exec, $value";
- }
+sub JSValueToNativeDOMConvertNeedsGlobalObject
+{
+ my $type = shift;
- if ($type eq "DOMStringList" ) {
- AddToImplIncludes("JSDOMStringList.h", $conditional);
- return "toDOMStringList(exec, $value)";
- }
+ return 1 if $codeGenerator->IsCallbackInterface($type);
+ return 1 if $codeGenerator->IsCallbackFunction($type);
+ return 0;
+}
+
+sub IsValidContextForJSValueToNative
+{
+ my $context = shift;
- if ($codeGenerator->IsTypedArrayType($type)) {
- return "to$type($value)";
- }
+ return ref($context) eq "IDLAttribute" || ref($context) eq "IDLArgument";
+}
- AddToImplIncludes("HTMLOptionElement.h", $conditional) if $type eq "HTMLOptionElement";
- AddToImplIncludes("Event.h", $conditional) if $type eq "Event";
+# Returns (convertString, mayThrowException).
- my $arrayType = $codeGenerator->GetArrayType($type);
- my $sequenceType = $codeGenerator->GetSequenceType($type);
- my $arrayOrSequenceType = $arrayType || $sequenceType;
+sub JSValueToNative
+{
+ my ($interface, $context, $value, $conditional, $statePointer, $stateReference, $thisObjectReference, $globalObjectReference, $exceptionThrower) = @_;
- if ($arrayOrSequenceType) {
- if ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) {
- AddToImplIncludes("JS${arrayOrSequenceType}.h");
- return "(toRefPtrNativeArray<${arrayOrSequenceType}, JS${arrayOrSequenceType}>(exec, $value, &to${arrayOrSequenceType}))";
- }
- return "toNativeArray<" . GetNativeVectorInnerType($arrayOrSequenceType) . ">(exec, $value)";
+ assert("Invalid context type") if !IsValidContextForJSValueToNative($context);
+
+ my $type = $context->type;
+
+ # FIXME: Remove these 3 variables when all JSValueToNative use references.
+ $statePointer = "state" unless $statePointer;
+ $stateReference = "*state" unless $stateReference;
+ $thisObjectReference = "*castedThis" unless $thisObjectReference;
+
+ AddToImplIncludesForIDLType($type, $conditional);
+
+ if ($type->name eq "DOMString") {
+ return ("AtomicString($value.toString($statePointer)->toExistingAtomicString($statePointer))", 1) if $context->extendedAttributes->{RequiresExistingAtomicString};
+ return ("$value.toString($statePointer)->toAtomicString($statePointer)", 1) if $context->extendedAttributes->{AtomicString};
}
if ($codeGenerator->IsEnumType($type)) {
- return "$value.isEmpty() ? String() : $value.toString(exec)->value(exec)";
+ return ("parseEnumeration<" . GetEnumerationClassName($type, $interface) . ">($stateReference, $value)", 1);
}
- # Default, assume autogenerated type conversion routines
- AddToImplIncludes("JS$type.h", $conditional);
- return "to$type($value)";
+ AddToImplIncludes("JSDOMConvert.h");
+
+ my $IDLType = GetIDLType($interface, $type);
+
+ my @conversionArguments = ();
+ push(@conversionArguments, $stateReference);
+ push(@conversionArguments, $value);
+ push(@conversionArguments, $thisObjectReference) if JSValueToNativeDOMConvertNeedsThisObject($type);
+ push(@conversionArguments, $globalObjectReference) if JSValueToNativeDOMConvertNeedsGlobalObject($type);
+ push(@conversionArguments, GetIntegerConversionConfiguration($context)) if $codeGenerator->IsIntegerType($type);
+ push(@conversionArguments, GetStringConversionConfiguration($context)) if $codeGenerator->IsStringType($type);
+ push(@conversionArguments, $exceptionThrower) if $exceptionThrower;
+
+ return ("convert<$IDLType>(" . join(", ", @conversionArguments) . ")", 1);
}
-sub NativeToJSValue
+sub UnsafeToNative
{
- my $signature = shift;
- my $inFunctionCall = shift;
- my $interfaceName = shift;
- my $value = shift;
- my $thisValue = shift;
+ my ($interface, $context, $value, $conditional, $statePointer, $stateReference, $thisObjectReference) = @_;
- my $conditional = $signature->extendedAttributes->{"Conditional"};
- my $type = $signature->type;
+ assert("Invalid context type") if !IsValidContextForJSValueToNative($context);
- return "jsBoolean($value)" if $type eq "boolean";
+ my $type = $context->type;
- # Need to check Date type before IsPrimitiveType().
- if ($type eq "Date") {
- return "jsDateOrNull(exec, $value)";
- }
+ # FIXME: Remove these 3 variables when all JSValueToNative use references.
+ $statePointer = "state" unless $statePointer;
+ $stateReference = "*state" unless $stateReference;
+ $thisObjectReference = "*castedThis" unless $thisObjectReference;
- if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) {
- $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g;
- return "jsNumber(std::max(0, " . $value . "))";
- }
+ AddToImplIncludesForIDLType($type, $conditional);
- if ($codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp") {
- return "jsNumber($value)";
- }
+ # FIXME: Support more types.
- if ($codeGenerator->IsEnumType($type)) {
- AddToImplIncludes("<runtime/JSString.h>", $conditional);
- return "jsStringWithCache(exec, $value)";
+ if ($type->name eq "DOMString") {
+ return ("AtomicString($value->toExistingAtomicString($statePointer))", 1) if $context->extendedAttributes->{RequiresExistingAtomicString};
+ return ("$value->toAtomicString($statePointer)", 1) if $context->extendedAttributes->{AtomicString};
}
- if ($codeGenerator->IsStringType($type)) {
- AddToImplIncludes("URL.h", $conditional);
- my $conv = $signature->extendedAttributes->{"TreatReturnedNullStringAs"};
- if (defined $conv) {
- return "jsStringOrNull(exec, $value)" if $conv eq "Null";
- return "jsStringOrUndefined(exec, $value)" if $conv eq "Undefined";
+ AddToImplIncludes("DOMJITIDLConvert.h");
- die "Unknown value for TreatReturnedNullStringAs extended attribute";
- }
- AddToImplIncludes("<runtime/JSString.h>", $conditional);
- return "jsStringWithCache(exec, $value)";
+ my $IDLType = GetIDLType($interface, $type);
+
+ my @conversionArguments = ();
+ push(@conversionArguments, "$stateReference");
+ push(@conversionArguments, "$value");
+
+ my @conversionStaticArguments = ();
+ push(@conversionStaticArguments, GetIntegerConversionConfiguration($context)) if $codeGenerator->IsIntegerType($type);
+ push(@conversionStaticArguments, GetStringConversionConfiguration($context)) if $codeGenerator->IsStringType($type);
+
+ if (scalar(@conversionStaticArguments) > 0) {
+ return ("DOMJIT::DirectConverter<$IDLType>::directConvert<" . join(", ", @conversionStaticArguments) . ">(" . join(", ", @conversionArguments) . ")", 1);
}
+ return ("DOMJIT::DirectConverter<$IDLType>::directConvert(" . join(", ", @conversionArguments) . ")", 1);
+}
+
+sub NativeToJSValueDOMConvertNeedsState
+{
+ my ($type, $context) = @_;
+
+ # FIXME: We need a more robust way to specify this requirement so as not
+ # to require specializing each type. Perhaps just requiring all override
+ # types to take both state and the global object would work?
+ if ($context->extendedAttributes->{OverrideIDLType}) {
+ my $overrideTypeName = $context->extendedAttributes->{OverrideIDLType};
+ return 1 if $overrideTypeName eq "IDLIDBKey";
+ return 1 if $overrideTypeName eq "IDLWebGLAny";
+
+ return 0;
+ }
+
+ # FIXME: This should actually check if all the sub-objects of the union need the state.
+ return 1 if $type->isUnion;
+ return 1 if $codeGenerator->IsSequenceOrFrozenArrayType($type);
+ return 1 if $codeGenerator->IsRecordType($type);
+ return 1 if $codeGenerator->IsStringType($type);
+ return 1 if $codeGenerator->IsEnumType($type);
+ return 1 if $codeGenerator->IsDictionaryType($type);
+ return 1 if $codeGenerator->IsInterfaceType($type);
+ return 1 if $codeGenerator->IsTypedArrayType($type);
+ return 1 if $type->name eq "Date";
+ return 1 if $type->name eq "JSON";
+ return 1 if $type->name eq "SerializedScriptValue";
+ return 1 if $type->name eq "XPathNSResolver";
+
+ return 0;
+}
+
+sub NativeToJSValueDOMConvertNeedsGlobalObject
+{
+ my ($type, $context) = @_;
- my $globalObject;
- if ($thisValue) {
- $globalObject = "$thisValue->globalObject()";
- }
+ # FIXME: We need a more robust way to specify this requirement so as not
+ # to require specializing each type. Perhaps just requiring all override
+ # types to take both state and the global object would work?
+ if ($context->extendedAttributes->{OverrideIDLType}) {
+ my $overrideTypeName = $context->extendedAttributes->{OverrideIDLType};
+ return 1 if $overrideTypeName eq "IDLIDBKey";
+ return 1 if $overrideTypeName eq "IDLWebGLAny";
+
+ return 0;
+ }
+
+ # FIXME: This should actually check if all the sub-objects of the union need the global object.
+ return 1 if $type->isUnion;
+ return 1 if $codeGenerator->IsSequenceOrFrozenArrayType($type);
+ return 1 if $codeGenerator->IsRecordType($type);
+ return 1 if $codeGenerator->IsDictionaryType($type);
+ return 1 if $codeGenerator->IsInterfaceType($type);
+ return 1 if $codeGenerator->IsTypedArrayType($type);
+ return 1 if $type->name eq "SerializedScriptValue";
+ return 1 if $type->name eq "XPathNSResolver";
- if ($type eq "CSSStyleDeclaration") {
- AddToImplIncludes("StyleProperties.h", $conditional);
- }
+ return 0;
+}
- if ($type eq "NodeList") {
- AddToImplIncludes("NameNodeList.h", $conditional);
- }
+sub NativeToJSValueUsingReferences
+{
+ my ($context, $interface, $value, $thisValue, $suppressExceptionCheck) = @_;
+ my $stateReference = "state";
+ my $wrapped = "$thisValue.wrapped()";
+ my $globalObjectReference = $thisValue ? "*$thisValue.globalObject()" : "*jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())";
- my $arrayType = $codeGenerator->GetArrayType($type);
- my $sequenceType = $codeGenerator->GetSequenceType($type);
- my $arrayOrSequenceType = $arrayType || $sequenceType;
+ return NativeToJSValue($context, $interface, $value, $stateReference, $wrapped, $globalObjectReference, $suppressExceptionCheck);
+}
- if ($arrayOrSequenceType) {
- if ($arrayType eq "DOMString") {
- AddToImplIncludes("JSDOMStringList.h", $conditional);
- AddToImplIncludes("DOMStringList.h", $conditional);
+# FIXME: We should remove NativeToJSValueUsingPointers and combine NativeToJSValueUsingReferences and NativeToJSValue
+sub NativeToJSValueUsingPointers
+{
+ my ($context, $interface, $value, $thisValue, $suppressExceptionCheck) = @_;
+ my $stateReference = "*state";
+ my $wrapped = "$thisValue->wrapped()";
+ my $globalObjectReference = $thisValue ? "*$thisValue->globalObject()" : "*jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())";
- } elsif ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) {
- AddToImplIncludes("JS${arrayOrSequenceType}.h", $conditional);
- AddToImplIncludes("${arrayOrSequenceType}.h", $conditional);
- }
- AddToImplIncludes("<runtime/JSArray.h>", $conditional);
+ return NativeToJSValue($context, $interface, $value, $stateReference, $wrapped, $globalObjectReference, $suppressExceptionCheck);
+}
- return "jsArray(exec, $thisValue->globalObject(), $value)";
- }
+sub IsValidContextForNativeToJSValue
+{
+ my $context = shift;
+
+ return ref($context) eq "IDLAttribute" || ref($context) eq "IDLOperation" || ref($context) eq "IDLArgument";
+}
- if ($type eq "any") {
- if ($interfaceName eq "Document") {
- AddToImplIncludes("JSCanvasRenderingContext2D.h", $conditional);
- } else {
- return "($value.hasNoValue() ? jsNull() : $value.jsValue())";
- }
- } elsif ($type eq "SerializedScriptValue" or $type eq "any") {
- AddToImplIncludes("SerializedScriptValue.h", $conditional);
- return "$value ? $value->deserialize(exec, castedThis->globalObject(), 0) : jsNull()";
- } elsif ($codeGenerator->IsTypedArrayType($type)) {
- # Do nothing - all headers are already included.
- } else {
- # Default, include header with same name.
- AddToImplIncludes("JS$type.h", $conditional);
- AddToImplIncludes("$type.h", $conditional) if not $codeGenerator->SkipIncludeHeader($type);
- }
-
- return $value if $codeGenerator->IsSVGAnimatedType($type);
-
- if ($signature->extendedAttributes->{"ReturnNewObject"}) {
- return "toJSNewlyCreated(exec, $globalObject, WTF::getPtr($value))";
- }
-
- if ($codeGenerator->IsSVGAnimatedType($interfaceName) or $interfaceName eq "SVGViewSpec") {
- # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked.
- $value = "static_cast<" . GetNativeType($type) . ">($value)";
- } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($type) and not $interfaceName =~ /List$/) {
- my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
- if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($type) and $inFunctionCall eq 0 and not defined $signature->extendedAttributes->{"Immutable"}) {
- my $getter = $value;
- $getter =~ s/impl\.//;
- $getter =~ s/impl->//;
- $getter =~ s/\(\)//;
- my $updateMethod = "&${interfaceName}::update" . $codeGenerator->WK_ucfirst($getter);
-
- my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName);
- if ($selfIsTearOffType) {
- AddToImplIncludes("SVGMatrixTearOff.h", $conditional);
- # FIXME: Blink: Don't create a new one everytime we access the matrix property. This means, e.g, === won't work.
- $value = "SVGMatrixTearOff::create(castedThis->impl(), $value)";
- } else {
- AddToImplIncludes("SVGStaticPropertyTearOff.h", $conditional);
- $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$interfaceName, /;
- $value = "${tearOffType}::create(impl, $value, $updateMethod)";
- }
- } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) {
- $value = "${tearOffType}::create(impl, $value)";
- } elsif (not $tearOffType =~ /SVG(Point|PathSeg)List/) {
- $value = "${tearOffType}::create($value)";
- }
+sub NativeToJSValue
+{
+ my ($context, $interface, $value, $stateReference, $wrapped, $globalObjectReference, $suppressExceptionCheck) = @_;
+
+ assert("Invalid context type") if !IsValidContextForNativeToJSValue($context);
+
+ my $conditional = $context->extendedAttributes->{Conditional};
+ my $type = $context->type;
+ my $mayThrowException = $context->extendedAttributes->{GetterMayThrowException} || $context->extendedAttributes->{MayThrowException} && !$suppressExceptionCheck;
+
+ # We could instead overload a function to work with optional as well as non-optional numbers, but this
+ # is slightly better because it guarantees we will fail to compile if the IDL file doesn't match the C++.
+ if ($context->extendedAttributes->{Reflect} and ($type->name eq "unsigned long" or $type->name eq "unsigned short")) {
+ $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g;
+ $value = "std::max(0, $value)";
}
- if ($globalObject) {
- return "toJS(exec, $globalObject, WTF::getPtr($value))";
- } else {
- return "toJS(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), WTF::getPtr($value))";
+
+ AddToImplIncludesForIDLType($type, $conditional);
+ AddToImplIncludes("JSDOMConvert.h", $conditional);
+
+ if ($context->extendedAttributes->{CheckSecurityForNode}) {
+ AddToImplIncludes("JSDOMBindingSecurity.h", $conditional);
+ $value = "BindingSecurity::checkSecurityForNode($stateReference, $value)";
}
+
+ my $IDLType = GetIDLType($interface, $type, $context);
+
+ my @conversionArguments = ();
+ push(@conversionArguments, $stateReference) if NativeToJSValueDOMConvertNeedsState($type, $context) || $mayThrowException;
+ push(@conversionArguments, $globalObjectReference) if NativeToJSValueDOMConvertNeedsGlobalObject($type, $context);
+ push(@conversionArguments, "throwScope") if $mayThrowException;
+ push(@conversionArguments, $value);
+
+ my $functionName = $context->extendedAttributes->{NewObject} ? "toJSNewlyCreated" : "toJS";
+
+ return "${functionName}<${IDLType}>(" . join(", ", @conversionArguments) . ")";
}
sub ceilingToPowerOf2
@@ -3722,6 +5697,69 @@ sub ceilingToPowerOf2
}
# Internal Helper
+sub GenerateHashTableValueArray
+{
+ my $keys = shift;
+ my $specials = shift;
+ my $value1 = shift;
+ my $value2 = shift;
+ my $conditionals = shift;
+ my $nameEntries = shift;
+
+ my $packedSize = scalar @{$keys};
+ push(@implContent, "\nstatic const HashTableValue $nameEntries\[\] =\n\{\n");
+
+ my $hasSetter = "false";
+
+ my $i = 0;
+ foreach my $key (@{$keys}) {
+ my $conditional;
+ my $firstTargetType;
+ my $secondTargetType = "";
+
+ if ($conditionals) {
+ $conditional = $conditionals->{$key};
+ }
+ if ($conditional) {
+ my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
+ push(@implContent, "#if ${conditionalString}\n");
+ }
+
+ if ("@$specials[$i]" =~ m/DOMJITFunction/) {
+ $firstTargetType = "static_cast<NativeFunction>";
+ $secondTargetType = "static_cast<const JSC::DOMJIT::Signature*>";
+ } elsif ("@$specials[$i]" =~ m/Function/) {
+ $firstTargetType = "static_cast<NativeFunction>";
+ } elsif ("@$specials[$i]" =~ m/Builtin/) {
+ $firstTargetType = "static_cast<BuiltinGenerator>";
+ } elsif ("@$specials[$i]" =~ m/ConstantInteger/) {
+ $firstTargetType = "";
+ } elsif ("@$specials[$i]" =~ m/DOMJITAttribute/) {
+ $firstTargetType = "static_cast<DOMJITGetterSetterGenerator>";
+ } else {
+ $firstTargetType = "static_cast<PropertySlot::GetValueFunc>";
+ $secondTargetType = "static_cast<PutPropertySlot::PutValueFunc>";
+ $hasSetter = "true";
+ }
+ if ("@$specials[$i]" =~ m/ConstantInteger/) {
+ push(@implContent, " { \"$key\", @$specials[$i], NoIntrinsic, { (long long)" . $firstTargetType . "(@$value1[$i]) } },\n");
+ } else {
+ push(@implContent, " { \"$key\", @$specials[$i], NoIntrinsic, { (intptr_t)" . $firstTargetType . "(@$value1[$i]), (intptr_t) " . $secondTargetType . "(@$value2[$i]) } },\n");
+ }
+ if ($conditional) {
+ push(@implContent, "#else\n") ;
+ push(@implContent, " { 0, 0, NoIntrinsic, { 0, 0 } },\n");
+ push(@implContent, "#endif\n") ;
+ }
+ ++$i;
+ }
+
+ push(@implContent, " { 0, 0, NoIntrinsic, { 0, 0 } }\n") if (!$packedSize);
+ push(@implContent, "};\n\n");
+
+ return $hasSetter;
+}
+
sub GenerateHashTable
{
my $object = shift;
@@ -3733,6 +5771,34 @@ sub GenerateHashTable
my $value1 = shift;
my $value2 = shift;
my $conditionals = shift;
+ my $justGenerateValueArray = shift;
+
+ my $nameEntries = "${name}Values";
+ $nameEntries =~ s/:/_/g;
+ my $nameIndex = "${name}Index";
+ $nameIndex =~ s/:/_/g;
+
+ if (($name =~ /Prototype/) or ($name =~ /Constructor/)) {
+ my $type = $name;
+ my $implClass;
+
+ if ($name =~ /Prototype/) {
+ $type =~ s/Prototype.*//;
+ $implClass = $type; $implClass =~ s/Wrapper$//;
+ push(@implContent, "/* Hash table for prototype */\n");
+ } else {
+ $type =~ s/Constructor.*//;
+ $implClass = $type; $implClass =~ s/Constructor$//;
+ push(@implContent, "/* Hash table for constructor */\n");
+ }
+ } else {
+ push(@implContent, "/* Hash table */\n");
+ }
+
+ if ($justGenerateValueArray) {
+ GenerateHashTableValueArray($keys, $specials, $value1, $value2, $conditionals, $nameEntries) if $size;
+ return;
+ }
# Generate size data for compact' size hash table
@@ -3768,60 +5834,22 @@ sub GenerateHashTable
$maxDepth = $depth if ($depth > $maxDepth);
}
- # Start outputing the hashtables
- my $nameEntries = "${name}Values";
- $nameEntries =~ s/:/_/g;
- my $hasSetter = "false";
-
- if (($name =~ /Prototype/) or ($name =~ /Constructor/)) {
- my $type = $name;
- my $implClass;
-
- if ($name =~ /Prototype/) {
- $type =~ s/Prototype.*//;
- $implClass = $type; $implClass =~ s/Wrapper$//;
- push(@implContent, "/* Hash table for prototype */\n");
- } else {
- $type =~ s/Constructor.*//;
- $implClass = $type; $implClass =~ s/Constructor$//;
- push(@implContent, "/* Hash table for constructor */\n");
- }
- } else {
- push(@implContent, "/* Hash table */\n");
+ push(@implContent, "\nstatic const struct CompactHashIndex ${nameIndex}\[$compactSize\] = {\n");
+ for (my $i = 0; $i < $compactSize; $i++) {
+ my $T = -1;
+ if (defined($table[$i])) { $T = $table[$i]; }
+ my $L = -1;
+ if (defined($links[$i])) { $L = $links[$i]; }
+ push(@implContent, " { $T, $L },\n");
}
+ push(@implContent, "};\n\n");
# Dump the hash table
- push(@implContent, "\nstatic const HashTableValue $nameEntries\[\] =\n\{\n");
- $i = 0;
- foreach my $key (@{$keys}) {
- my $conditional;
- my $firstTargetType;
- my $secondTargetType = "";
-
- if ($conditionals) {
- $conditional = $conditionals->{$key};
- }
- if ($conditional) {
- my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
- push(@implContent, "#if ${conditionalString}\n");
- }
-
- if ("@$specials[$i]" =~ m/Function/) {
- $firstTargetType = "static_cast<NativeFunction>";
- } else {
- $firstTargetType = "static_cast<PropertySlot::GetValueFunc>";
- $secondTargetType = "static_cast<PutPropertySlot::PutValueFunc>";
- $hasSetter = "true";
- }
- push(@implContent, " { \"$key\", @$specials[$i], NoIntrinsic, (intptr_t)" . $firstTargetType . "(@$value1[$i]), (intptr_t) " . $secondTargetType . "(@$value2[$i]) },\n");
- push(@implContent, "#endif\n") if $conditional;
- ++$i;
- }
+ my $hasSetter = GenerateHashTableValueArray($keys, $specials, $value1, $value2, $conditionals, $nameEntries);
+ my $packedSize = scalar @{$keys};
- push(@implContent, " { 0, 0, NoIntrinsic, 0, 0 }\n");
- push(@implContent, "};\n\n");
my $compactSizeMask = $numEntries - 1;
- push(@implContent, "static const HashTable $name = { $compactSize, $compactSizeMask, $hasSetter, $nameEntries, 0 };\n");
+ push(@implContent, "static const HashTable $name = { $packedSize, $compactSizeMask, $hasSetter, $nameEntries, $nameIndex };\n");
}
sub WriteData
@@ -3830,11 +5858,10 @@ sub WriteData
my $interface = shift;
my $outputDir = shift;
- my $name = $interface->name;
- my $prefix = FileNamePrefix;
- my $headerFileName = "$outputDir/$prefix$name.h";
- my $implFileName = "$outputDir/$prefix$name.cpp";
- my $depsFileName = "$outputDir/$prefix$name.dep";
+ my $name = $interface->type->name;
+ my $headerFileName = "$outputDir/JS$name.h";
+ my $implFileName = "$outputDir/JS$name.cpp";
+ my $depsFileName = "$outputDir/JS$name.dep";
# Update a .cpp file if the contents are changed.
my $contents = join "", @implContentHeader;
@@ -3842,24 +5869,28 @@ sub WriteData
my @includes = ();
my %implIncludeConditions = ();
foreach my $include (keys %implIncludes) {
+ next if $headerIncludes{$include};
+ next if $headerTrailingIncludes{$include};
+
my $condition = $implIncludes{$include};
+
my $checkType = $include;
$checkType =~ s/\.h//;
- next if $codeGenerator->IsSVGAnimatedType($checkType);
+ next if $codeGenerator->IsSVGAnimatedTypeName($checkType);
$include = "\"$include\"" unless $include =~ /^["<]/; # "
if ($condition eq 1) {
push @includes, $include;
} else {
- push @{$implIncludeConditions{$condition}}, $include;
+ push @{$implIncludeConditions{$codeGenerator->GenerateConditionalStringFromAttributeValue($condition)}}, $include;
}
}
foreach my $include (sort @includes) {
$contents .= "#include $include\n";
}
foreach my $condition (sort keys %implIncludeConditions) {
- $contents .= "\n#if " . $codeGenerator->GenerateConditionalStringFromAttributeValue($condition) . "\n";
+ $contents .= "\n#if " . $condition . "\n";
foreach my $include (sort @{$implIncludeConditions{$condition}}) {
$contents .= "#include $include\n";
}
@@ -3883,7 +5914,7 @@ sub WriteData
}
foreach my $include (sort @includes) {
# "JSClassName.h" is already included right after config.h.
- next if $include eq "\"$prefix$name.h\"";
+ next if $include eq "\"JS$name.h\"";
$contents .= "#include $include\n";
}
@@ -3913,253 +5944,150 @@ sub WriteData
}
}
-sub GenerateConstructorDeclaration
+sub GeneratePrototypeDeclaration
{
- my $outputArray = shift;
- my $className = shift;
- my $interface = shift;
- my $interfaceName = shift;
-
- my $constructorClassName = "${className}Constructor";
+ my ($outputArray, $className, $interface) = @_;
- push(@$outputArray, "class ${constructorClassName} : public DOMConstructorObject {\n");
- push(@$outputArray, "private:\n");
- push(@$outputArray, " ${constructorClassName}(JSC::Structure*, JSDOMGlobalObject*);\n");
- push(@$outputArray, " void finishCreation(JSC::VM&, JSDOMGlobalObject*);\n\n");
+ my $prototypeClassName = "${className}Prototype";
+ my %structureFlags = ();
+ push(@$outputArray, "class ${prototypeClassName} : public JSC::JSNonFinalObject {\n");
push(@$outputArray, "public:\n");
- push(@$outputArray, " typedef DOMConstructorObject Base;\n");
- push(@$outputArray, " static $constructorClassName* create(JSC::VM& vm, JSC::Structure* structure, JSDOMGlobalObject* globalObject)\n");
+ push(@$outputArray, " using Base = JSC::JSNonFinalObject;\n");
+
+ push(@$outputArray, " static ${prototypeClassName}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)\n");
push(@$outputArray, " {\n");
- push(@$outputArray, " $constructorClassName* ptr = new (NotNull, JSC::allocateCell<$constructorClassName>(vm.heap)) $constructorClassName(structure, globalObject);\n");
- push(@$outputArray, " ptr->finishCreation(vm, globalObject);\n");
+ push(@$outputArray, " ${className}Prototype* ptr = new (NotNull, JSC::allocateCell<${className}Prototype>(vm.heap)) ${className}Prototype(vm, globalObject, structure);\n");
+ push(@$outputArray, " ptr->finishCreation(vm);\n");
push(@$outputArray, " return ptr;\n");
push(@$outputArray, " }\n\n");
- push(@$outputArray, " static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
push(@$outputArray, " DECLARE_INFO;\n");
- push(@$outputArray, " static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
+ push(@$outputArray,
+ " static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n" .
+ " {\n" .
+ " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n" .
+ " }\n");
+
+ push(@$outputArray, "\nprivate:\n");
+ push(@$outputArray, " ${prototypeClassName}(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)\n");
+ push(@$outputArray, " : JSC::JSNonFinalObject(vm, structure)\n");
push(@$outputArray, " {\n");
- push(@$outputArray, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n");
push(@$outputArray, " }\n");
- push(@$outputArray, "protected:\n");
- push(@$outputArray, " static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | JSC::ImplementsHasInstance | DOMConstructorObject::StructureFlags;\n");
-
- if (IsConstructable($interface) && !$interface->extendedAttributes->{"NamedConstructor"}) {
- push(@$outputArray, " static JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState*);\n");
-
- if (!HasCustomConstructor($interface)) {
- my @constructors = @{$interface->constructors};
- if (@constructors > 1) {
- foreach my $constructor (@constructors) {
- my $overloadedIndex = "" . $constructor->{overloadedIndex};
- push(@$outputArray, " static JSC::EncodedJSValue JSC_HOST_CALL construct${className}${overloadedIndex}(JSC::ExecState*);\n");
- }
- }
+ if (PrototypeHasStaticPropertyTable($interface)) {
+ if (IsGlobalOrPrimaryGlobalInterface($interface)) {
+ $structureFlags{"JSC::HasStaticPropertyTable"} = 1;
+ } else {
+ push(@$outputArray, "\n");
+ push(@$outputArray, " void finishCreation(JSC::VM&);\n");
}
+ }
- my $conditionalString = $codeGenerator->GenerateConstructorConditionalString($interface);
- push(@$outputArray, "#if $conditionalString\n") if $conditionalString;
- push(@$outputArray, " static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&);\n");
- push(@$outputArray, "#endif // $conditionalString\n") if $conditionalString;
+ if ($interface->extendedAttributes->{JSCustomNamedGetterOnPrototype}) {
+ push(@$outputArray, "\n");
+ push(@$outputArray, " static bool put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
+ push(@$outputArray, " bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&, bool& putResult);\n");
}
- push(@$outputArray, "};\n\n");
- if ($codeGenerator->IsConstructorTemplate($interface, "Event")) {
- push(@$outputArray, "bool fill${interfaceName}Init(${interfaceName}Init&, JSDictionary&);\n\n");
+ # Custom defineOwnProperty function
+ if ($interface->extendedAttributes->{JSCustomDefineOwnPropertyOnPrototype}) {
+ push(@$outputArray, "\n");
+ push(@$outputArray, " static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n");
}
- if ($interface->extendedAttributes->{"NamedConstructor"}) {
- push(@$outputArray, <<END);
-class JS${interfaceName}NamedConstructor : public DOMConstructorWithDocument {
-public:
- typedef DOMConstructorWithDocument Base;
+ $structureFlags{"JSC::IsImmutablePrototypeExoticObject"} = 1 if $interface->extendedAttributes->{IsImmutablePrototypeExoticObjectOnPrototype};
- static JS${interfaceName}NamedConstructor* create(JSC::VM& vm, JSC::Structure* structure, JSDOMGlobalObject* globalObject)
- {
- JS${interfaceName}NamedConstructor* constructor = new (NotNull, JSC::allocateCell<JS${interfaceName}NamedConstructor>(vm.heap)) JS${interfaceName}NamedConstructor(structure, globalObject);
- constructor->finishCreation(vm, globalObject);
- return constructor;
+ # structure flags
+ if (%structureFlags) {
+ push(@$outputArray, "public:\n");
+ push(@$outputArray, " static const unsigned StructureFlags = ");
+ foreach my $structureFlag (sort (keys %structureFlags)) {
+ push(@$outputArray, $structureFlag . " | ");
+ }
+ push(@$outputArray, "Base::StructureFlags;\n");
}
- static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
- {
- return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
- }
+ push(@$outputArray, "};\n\n");
+}
+
+sub GetConstructorTemplateClassName
+{
+ my $interface = shift;
+ return "JSDOMConstructorNotConstructable" if $interface->extendedAttributes->{NamedConstructor};
+ return "JSDOMConstructorNotConstructable" unless IsConstructable($interface);
+ return "JSDOMBuiltinConstructor" if IsJSBuiltinConstructor($interface);
+ return "JSDOMConstructor";
+}
- DECLARE_INFO;
+sub GenerateConstructorDeclaration
+{
+ my ($outputArray, $className, $interface) = @_;
-private:
- JS${interfaceName}NamedConstructor(JSC::Structure*, JSDOMGlobalObject*);
- static JSC::EncodedJSValue JSC_HOST_CALL constructJS${interfaceName}(JSC::ExecState*);
- static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&);
- void finishCreation(JSC::VM&, JSDOMGlobalObject*);
-};
+ my $interfaceName = $interface->type->name;
+ my $constructorClassName = "${className}Constructor";
+ my $templateClassName = GetConstructorTemplateClassName($interface);
-END
- }
+ AddToImplIncludes("${templateClassName}.h");
+ AddToImplIncludes("JSDOMNamedConstructor.h") if $interface->extendedAttributes->{NamedConstructor};
+
+ push(@$outputArray, "using $constructorClassName = $templateClassName<$className>;\n");
+ push(@$outputArray, "using JS${interfaceName}NamedConstructor = JSDOMNamedConstructor<$className>;\n") if $interface->extendedAttributes->{NamedConstructor};
+ push(@$outputArray, "\n");
}
sub GenerateConstructorDefinitions
{
- my $outputArray = shift;
- my $className = shift;
- my $protoClassName = shift;
- my $interfaceName = shift;
- my $visibleInterfaceName = shift;
- my $interface = shift;
- my $generatingNamedConstructor = shift;
+ my ($outputArray, $className, $protoClassName, $visibleInterfaceName, $interface, $generatingNamedConstructor) = @_;
if (IsConstructable($interface)) {
my @constructors = @{$interface->constructors};
if (@constructors > 1) {
foreach my $constructor (@constructors) {
- GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $constructor);
+ GenerateConstructorDefinition($outputArray, $className, $protoClassName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $constructor);
}
- GenerateOverloadedConstructorDefinition($outputArray, $className, $interface);
+ GenerateOverloadedFunctionOrConstructor(@{$interface->constructors}[0], $interface, 1);
} elsif (@constructors == 1) {
- GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $constructors[0]);
+ GenerateConstructorDefinition($outputArray, $className, $protoClassName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $constructors[0]);
} else {
- GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor);
+ GenerateConstructorDefinition($outputArray, $className, $protoClassName, $visibleInterfaceName, $interface, $generatingNamedConstructor);
}
}
- GenerateConstructorHelperMethods($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor);
-}
-
-sub GenerateOverloadedConstructorDefinition
-{
- my $outputArray = shift;
- my $className = shift;
- my $interface = shift;
-
- my $functionName = "${className}Constructor::construct${className}";
- push(@$outputArray, <<END);
-EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)
-{
- size_t argsCount = exec->argumentCount();
-END
-
- my %fetchedArguments = ();
- my $leastNumMandatoryParams = 255;
-
- my @constructors = @{$interface->constructors};
- foreach my $overload (@constructors) {
- my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload);
- $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams);
-
- foreach my $parameterIndex (@neededArguments) {
- next if exists $fetchedArguments{$parameterIndex};
- push(@$outputArray, " JSValue arg$parameterIndex(exec->argument($parameterIndex));\n");
- $fetchedArguments{$parameterIndex} = 1;
- }
-
- push(@$outputArray, " if ($parametersCheck)\n");
- push(@$outputArray, " return ${functionName}$overload->{overloadedIndex}(exec);\n");
- }
-
- if ($leastNumMandatoryParams >= 1) {
- push(@$outputArray, " if (argsCount < $leastNumMandatoryParams)\n");
- push(@$outputArray, " return throwVMError(exec, createNotEnoughArgumentsError(exec));\n");
- }
- push(@$outputArray, <<END);
- return throwVMTypeError(exec);
-}
-
-END
+ GenerateConstructorHelperMethods($outputArray, $className, $protoClassName, $visibleInterfaceName, $interface, $generatingNamedConstructor);
}
sub GenerateConstructorDefinition
{
- my $outputArray = shift;
- my $className = shift;
- my $protoClassName = shift;
- my $interfaceName = shift;
- my $visibleInterfaceName = shift;
- my $interface = shift;
- my $generatingNamedConstructor = shift;
- my $function = shift;
+ my ($outputArray, $className, $protoClassName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $function) = @_;
+ return if IsJSBuiltinConstructor($interface);
+
+ my $interfaceName = $interface->type->name;
my $constructorClassName = $generatingNamedConstructor ? "${className}NamedConstructor" : "${className}Constructor";
if (IsConstructable($interface)) {
- if ($codeGenerator->IsConstructorTemplate($interface, "Event")) {
- $implIncludes{"JSDictionary.h"} = 1;
- $implIncludes{"<runtime/Error.h>"} = 1;
-
- push(@$outputArray, <<END);
-EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}(ExecState* exec)
-{
- ${constructorClassName}* jsConstructor = jsCast<${constructorClassName}*>(exec->callee());
-
- ScriptExecutionContext* executionContext = jsConstructor->scriptExecutionContext();
- if (!executionContext)
- return throwVMError(exec, createReferenceError(exec, "Constructor associated execution context is unavailable"));
-
- AtomicString eventType = exec->argument(0).toString(exec)->value(exec);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- ${interfaceName}Init eventInit;
-
- JSValue initializerValue = exec->argument(1);
- if (!initializerValue.isUndefinedOrNull()) {
- // Given the above test, this will always yield an object.
- JSObject* initializerObject = initializerValue.toObject(exec);
-
- // Create the dictionary wrapper from the initializer object.
- JSDictionary dictionary(exec, initializerObject);
-
- // Attempt to fill in the EventInit.
- if (!fill${interfaceName}Init(eventInit, dictionary))
- return JSValue::encode(jsUndefined());
- }
-
- RefPtr<${interfaceName}> event = ${interfaceName}::create(eventType, eventInit);
- return JSValue::encode(toJS(exec, jsConstructor->globalObject(), event.get()));
-}
-
-bool fill${interfaceName}Init(${interfaceName}Init& eventInit, JSDictionary& dictionary)
-{
-END
-
- if ($interface->parent) {
- my $interfaceBase = $interface->parent;
- push(@implContent, <<END);
- if (!fill${interfaceBase}Init(eventInit, dictionary))
- return false;
-
-END
- }
-
- for (my $index = 0; $index < @{$interface->attributes}; $index++) {
- my $attribute = @{$interface->attributes}[$index];
- if ($attribute->signature->extendedAttributes->{"InitializedByEventConstructor"}) {
- my $attributeName = $attribute->signature->name;
- my $attributeImplName = $attribute->signature->extendedAttributes->{"ImplementedAs"} || $attributeName;
- push(@implContent, <<END);
- if (!dictionary.tryGetProperty("${attributeName}", eventInit.${attributeImplName}))
- return false;
-END
- }
- }
-
- push(@$outputArray, <<END);
- return true;
-}
-
-END
- } elsif (!HasCustomConstructor($interface) && (!$interface->extendedAttributes->{"NamedConstructor"} || $generatingNamedConstructor)) {
- my $overloadedIndexString = "";
- if ($function->{overloadedIndex} && $function->{overloadedIndex} > 0) {
- $overloadedIndexString .= $function->{overloadedIndex};
+ if ($interface->extendedAttributes->{CustomConstructor}) {
+ push(@$outputArray, "template<> JSC::EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct(JSC::ExecState* exec)\n");
+ push(@$outputArray, "{\n");
+ push(@$outputArray, " ASSERT(exec);\n");
+ push(@$outputArray, " return construct${className}(*exec);\n");
+ push(@$outputArray, "}\n\n");
+ } elsif (!HasCustomConstructor($interface) && (!$interface->extendedAttributes->{NamedConstructor} || $generatingNamedConstructor)) {
+ my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
+ if ($isOverloaded) {
+ push(@$outputArray, "static inline EncodedJSValue construct${className}$function->{overloadIndex}(ExecState* state)\n");
+ } else {
+ push(@$outputArray, "template<> EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct(ExecState* state)\n");
}
- push(@$outputArray, "EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}${overloadedIndexString}(ExecState* exec)\n");
push(@$outputArray, "{\n");
- push(@$outputArray, " ${constructorClassName}* castedThis = jsCast<${constructorClassName}*>(exec->callee());\n");
+ push(@$outputArray, " VM& vm = state->vm();\n");
+ push(@$outputArray, " auto throwScope = DECLARE_THROW_SCOPE(vm);\n");
+ push(@$outputArray, " UNUSED_PARAM(throwScope);\n");
+ push(@$outputArray, " auto* castedThis = jsCast<${constructorClassName}*>(state->jsCallee());\n");
+ push(@$outputArray, " ASSERT(castedThis);\n");
my @constructorArgList;
@@ -4167,71 +6095,91 @@ END
GenerateArgumentsCountCheck($outputArray, $function, $interface);
- if ($function->signature->extendedAttributes->{"RaisesException"} || $interface->extendedAttributes->{"ConstructorRaisesException"}) {
- $implIncludes{"ExceptionCode.h"} = 1;
- push(@$outputArray, " ExceptionCode ec = 0;\n");
- }
-
# FIXME: For now, we do not support SVG constructors.
# FIXME: Currently [Constructor(...)] does not yet support optional arguments without [Default=...]
- my $numParameters = @{$function->parameters};
- my ($dummy, $paramIndex) = GenerateParametersCheck($outputArray, $function, $interface, $numParameters, $interfaceName, "constructorCallback", undef, undef, undef);
+ my ($dummy, $paramIndex) = GenerateParametersCheck($outputArray, $function, $interface, "constructorCallback");
- if ($codeGenerator->ExtendedAttributeContains($interface->extendedAttributes->{"ConstructorCallWith"}, "ScriptExecutionContext") ) {
+ push(@constructorArgList, "*state") if $codeGenerator->ExtendedAttributeContains($interface->extendedAttributes->{ConstructorCallWith}, "ScriptState");;
+
+ if ($codeGenerator->ExtendedAttributeContains($interface->extendedAttributes->{ConstructorCallWith}, "ScriptExecutionContext")) {
push(@constructorArgList, "*context");
push(@$outputArray, " ScriptExecutionContext* context = castedThis->scriptExecutionContext();\n");
- push(@$outputArray, " if (!context)\n");
- push(@$outputArray, " return throwVMError(exec, createReferenceError(exec, \"${interfaceName} constructor associated document is unavailable\"));\n");
+ push(@$outputArray, " if (UNLIKELY(!context))\n");
+ push(@$outputArray, " return throwConstructorScriptExecutionContextUnavailableError(*state, throwScope, \"${visibleInterfaceName}\");\n");
}
- if ($generatingNamedConstructor) {
- push(@constructorArgList, "*castedThis->document()");
+
+ if ($codeGenerator->ExtendedAttributeContains($interface->extendedAttributes->{ConstructorCallWith}, "Document")) {
+ $implIncludes{"Document.h"} = 1;
+ push(@constructorArgList, "document");
+ push(@$outputArray, " ScriptExecutionContext* context = castedThis->scriptExecutionContext();\n");
+ push(@$outputArray, " if (UNLIKELY(!context))\n");
+ push(@$outputArray, " return throwConstructorScriptExecutionContextUnavailableError(*state, throwScope, \"${visibleInterfaceName}\");\n");
+ push(@$outputArray, " ASSERT(context->isDocument());\n");
+ push(@$outputArray, " auto& document = downcast<Document>(*context);\n");
}
+ push(@constructorArgList, "*castedThis->document()") if $generatingNamedConstructor;
+
my $index = 0;
- foreach my $parameter (@{$function->parameters}) {
+ foreach my $argument (@{$function->arguments}) {
last if $index eq $paramIndex;
- push(@constructorArgList, $parameter->name);
+
+ push(@constructorArgList, PassArgumentExpression($argument->name, $argument));
+
$index++;
}
- if ($interface->extendedAttributes->{"ConstructorRaisesException"}) {
- push(@constructorArgList, "ec");
- }
my $constructorArg = join(", ", @constructorArgList);
if ($generatingNamedConstructor) {
- push(@$outputArray, " RefPtr<${interfaceName}> object = ${interfaceName}::createForJSConstructor(${constructorArg});\n");
+ push(@$outputArray, " auto object = ${interfaceName}::createForJSConstructor(${constructorArg});\n");
} else {
- push(@$outputArray, " RefPtr<${interfaceName}> object = ${interfaceName}::create(${constructorArg});\n");
+ push(@$outputArray, " auto object = ${interfaceName}::create(${constructorArg});\n");
}
- if ($interface->extendedAttributes->{"ConstructorRaisesException"}) {
- push(@$outputArray, " if (ec) {\n");
- push(@$outputArray, " setDOMException(exec, ec);\n");
- push(@$outputArray, " return JSValue::encode(JSValue());\n");
- push(@$outputArray, " }\n");
- }
+ push(@$outputArray, " RETURN_IF_EXCEPTION(throwScope, encodedJSValue());\n") if $codeGenerator->ExtendedAttributeContains($interface->extendedAttributes->{ConstructorCallWith}, "ScriptState");
+
+ my $IDLType = GetIDLType($interface, $interface->type);
- push(@$outputArray, " return JSValue::encode(asObject(toJS(exec, castedThis->globalObject(), object.get())));\n");
+ my @constructionConversionArguments = ();
+ push(@constructionConversionArguments, "*state");
+ push(@constructionConversionArguments, "*castedThis->globalObject()");
+ push(@constructionConversionArguments, "throwScope") if $interface->extendedAttributes->{ConstructorMayThrowException};
+ push(@constructionConversionArguments, "WTFMove(object)");
+
+ push(@$outputArray, " return JSValue::encode(toJSNewlyCreated<${IDLType}>(" . join(", ", @constructionConversionArguments) . "));\n");
push(@$outputArray, "}\n\n");
}
}
}
-sub GenerateConstructorHelperMethods
+sub ConstructorHasProperties
{
- my $outputArray = shift;
- my $className = shift;
- my $protoClassName = shift;
- my $interfaceName = shift;
- my $visibleInterfaceName = shift;
my $interface = shift;
- my $generatingNamedConstructor = shift;
+
+ foreach my $constant (@{$interface->constants}) {
+ return 1;
+ }
+
+ foreach my $attribute (@{$interface->attributes}) {
+ next unless ($attribute->isStatic);
+ return 1;
+ }
+
+ foreach my $function (@{$interface->functions}) {
+ next unless ($function->isStatic);
+ return 1;
+ }
+
+ return 0;
+}
+
+sub GenerateConstructorHelperMethods
+{
+ my ($outputArray, $className, $protoClassName, $visibleInterfaceName, $interface, $generatingNamedConstructor) = @_;
my $constructorClassName = $generatingNamedConstructor ? "${className}NamedConstructor" : "${className}Constructor";
my $leastConstructorLength = 0;
- if ($codeGenerator->IsConstructorTemplate($interface, "Event")) {
- $leastConstructorLength = 1;
- } elsif ($interface->extendedAttributes->{"Constructor"} || $interface->extendedAttributes->{"CustomConstructor"}) {
+ if ($interface->extendedAttributes->{Constructor} || $interface->extendedAttributes->{CustomConstructor}) {
my @constructors = @{$interface->constructors};
my @customConstructors = @{$interface->customConstructors};
$leastConstructorLength = 255;
@@ -4243,108 +6191,192 @@ sub GenerateConstructorHelperMethods
$leastConstructorLength = 0;
}
- if ($generatingNamedConstructor) {
- push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, 0, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
- push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n");
- push(@$outputArray, " : DOMConstructorWithDocument(structure, globalObject)\n");
- push(@$outputArray, "{\n");
- push(@$outputArray, "}\n\n");
+ # If the interface has a parent interface which does not have [NoInterfaceObject], then use its interface object as prototype,
+ # otherwise use FunctionPrototype: http://heycam.github.io/webidl/#interface-object
+ push(@$outputArray, "template<> JSValue ${constructorClassName}::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)\n");
+ push(@$outputArray, "{\n");
+ # FIXME: IDL does not allow an interface without [NoInterfaceObject] to inherit one that is marked as [NoInterfaceObject]
+ # so we should be able to use our parent's interface object no matter what. However, some of our IDL files (e.g. CanvasRenderingContext2D)
+ # are not valid so we need this check for now.
+ if ($interface->parentType && !$codeGenerator->GetInterfaceExtendedAttributesFromName($interface->parentType->name)->{NoInterfaceObject}) {
+ my $parentClassName = "JS" . $interface->parentType->name;
+ push(@$outputArray, " return ${parentClassName}::getConstructor(vm, &globalObject);\n");
} else {
- if ($interface->extendedAttributes->{"JSNoStaticTables"}) {
- push(@$outputArray, "static const HashTable& get${constructorClassName}Table(VM& vm)\n");
- push(@$outputArray, "{\n");
- push(@$outputArray, " return getHashTableForGlobalData(vm, ${constructorClassName}Table);\n");
- push(@$outputArray, "}\n\n");
- push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, 0, get${constructorClassName}Table, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
- } else {
- push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, &${constructorClassName}Table, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
- }
-
- push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n");
- push(@$outputArray, " : DOMConstructorObject(structure, globalObject)\n");
- push(@$outputArray, "{\n}\n\n");
+ AddToImplIncludes("<runtime/FunctionPrototype.h>");
+ push(@$outputArray, " UNUSED_PARAM(vm);\n");
+ push(@$outputArray, " return globalObject.functionPrototype();\n");
}
+ push(@$outputArray, "}\n\n");
- push(@$outputArray, "void ${constructorClassName}::finishCreation(VM& vm, JSDOMGlobalObject* globalObject)\n");
+
+ push(@$outputArray, "template<> void ${constructorClassName}::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)\n");
push(@$outputArray, "{\n");
- if (IsDOMGlobalObject($interface)) {
- push(@$outputArray, " Base::finishCreation(vm);\n");
- push(@$outputArray, " ASSERT(inherits(info()));\n");
- push(@$outputArray, " putDirect(vm, vm.propertyNames->prototype, globalObject->prototype(), DontDelete | ReadOnly);\n");
- } elsif ($generatingNamedConstructor) {
- push(@$outputArray, " Base::finishCreation(globalObject);\n");
- push(@$outputArray, " ASSERT(inherits(info()));\n");
- push(@$outputArray, " putDirect(vm, vm.propertyNames->prototype, ${className}Prototype::self(vm, globalObject), None);\n");
+
+ # There must exist an interface prototype object for every non-callback interface defined, regardless
+ # of whether the interface was declared with the [NoInterfaceObject] extended attribute.
+ # https://heycam.github.io/webidl/#interface-prototype-object
+ if (ShouldUseGlobalObjectPrototype($interface)) {
+ push(@$outputArray, " putDirect(vm, vm.propertyNames->prototype, globalObject.getPrototypeDirect(), DontDelete | ReadOnly | DontEnum);\n");
+ } elsif ($interface->isCallback) {
+ push(@$outputArray, " UNUSED_PARAM(globalObject);\n");
} else {
- push(@$outputArray, " Base::finishCreation(vm);\n");
- push(@$outputArray, " ASSERT(inherits(info()));\n");
- push(@$outputArray, " putDirect(vm, vm.propertyNames->prototype, ${protoClassName}::self(vm, globalObject), DontDelete | ReadOnly);\n");
+ push(@$outputArray, " putDirect(vm, vm.propertyNames->prototype, ${className}::prototype(vm, &globalObject), DontDelete | ReadOnly | DontEnum);\n");
}
- push(@$outputArray, " putDirect(vm, vm.propertyNames->length, jsNumber(${leastConstructorLength}), ReadOnly | DontDelete | DontEnum);\n") if defined $leastConstructorLength;
- push(@$outputArray, "}\n\n");
- if (!$generatingNamedConstructor) {
- my $hasStaticFunctions = 0;
- foreach my $function (@{$interface->functions}) {
- if ($function->isStatic) {
- $hasStaticFunctions = 1;
- last;
- }
- }
+ push(@$outputArray, " putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String(ASCIILiteral(\"$visibleInterfaceName\"))), ReadOnly | DontEnum);\n");
+ push(@$outputArray, " putDirect(vm, vm.propertyNames->length, jsNumber(${leastConstructorLength}), ReadOnly | DontEnum);\n") if defined $leastConstructorLength;
+ push(@$outputArray, " reifyStaticProperties(vm, ${className}ConstructorTableValues, *this);\n") if ConstructorHasProperties($interface);
- my $kind = $hasStaticFunctions ? "Property" : "Value";
+ push(@$outputArray, "}\n\n");
- push(@$outputArray, "bool ${constructorClassName}::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
+ if (IsJSBuiltinConstructor($interface)) {
+ push(@$outputArray, "template<> FunctionExecutable* ${constructorClassName}::initializeExecutable(VM& vm)\n");
push(@$outputArray, "{\n");
- push(@$outputArray, " return getStatic${kind}Slot<${constructorClassName}, JSDOMWrapper>(exec, " . constructorHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $constructorClassName) . ", jsCast<${constructorClassName}*>(object), propertyName, slot);\n");
- push(@$outputArray, "}\n\n");
- }
-
- if (IsConstructable($interface)) {
- if (!$interface->extendedAttributes->{"NamedConstructor"} || $generatingNamedConstructor) {
- my $conditionalString = $codeGenerator->GenerateConstructorConditionalString($interface);
- push(@$outputArray, "#if $conditionalString\n") if $conditionalString;
- push(@$outputArray, "ConstructType ${constructorClassName}::getConstructData(JSCell*, ConstructData& constructData)\n");
- push(@$outputArray, "{\n");
- push(@$outputArray, " constructData.native.function = construct${className};\n");
- push(@$outputArray, " return ConstructTypeHost;\n");
- push(@$outputArray, "}\n");
- push(@$outputArray, "#endif // $conditionalString\n") if $conditionalString;
- push(@$outputArray, "\n");
- }
+ push(@$outputArray, " return " . GetJSBuiltinFunctionNameFromString($interface->type->name, "initialize" . $interface->type->name) . "(vm);\n");
+ push(@$outputArray, "}\n");
+ push(@$outputArray, "\n");
}
+ push(@$outputArray, "template<> const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}\", &Base::s_info, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
}
sub HasCustomConstructor
{
my $interface = shift;
-
- return $interface->extendedAttributes->{"CustomConstructor"};
+ return $interface->extendedAttributes->{CustomConstructor};
}
sub HasCustomGetter
{
- my $attrExt = shift;
- return $attrExt->{"Custom"} || $attrExt->{"CustomGetter"} ;
+ my $extendedAttributes = shift;
+ return $extendedAttributes->{Custom} || $extendedAttributes->{CustomGetter} ;
}
sub HasCustomSetter
{
- my $attrExt = shift;
- return $attrExt->{"Custom"} || $attrExt->{"CustomSetter"};
+ my $extendedAttributes = shift;
+ return $extendedAttributes->{Custom} || $extendedAttributes->{CustomSetter};
}
sub HasCustomMethod
{
- my $attrExt = shift;
- return $attrExt->{"Custom"};
+ my $extendedAttributes = shift;
+ return $extendedAttributes->{Custom};
+}
+
+sub NeedsConstructorProperty
+{
+ my $interface = shift;
+ return !$interface->extendedAttributes->{NoInterfaceObject} || $interface->extendedAttributes->{CustomConstructor};
+}
+
+sub IsReturningPromise
+{
+ my $function = shift;
+ return $function->type && $function->type->name eq "Promise";
}
sub IsConstructable
{
my $interface = shift;
+ return HasCustomConstructor($interface)
+ || $interface->extendedAttributes->{Constructor}
+ || $interface->extendedAttributes->{NamedConstructor}
+ || $interface->extendedAttributes->{JSBuiltinConstructor};
+}
+
+sub HeaderNeedsPrototypeDeclaration
+{
+ my $interface = shift;
+ return IsDOMGlobalObject($interface) || $interface->extendedAttributes->{JSCustomNamedGetterOnPrototype} || $interface->extendedAttributes->{JSCustomDefineOwnPropertyOnPrototype};
+}
+
+sub IsUnforgeable
+{
+ my $interface = shift;
+ my $property = shift;
+ return $property->extendedAttributes->{Unforgeable} || $interface->extendedAttributes->{Unforgeable};
+}
+
+sub ComputeFunctionSpecial
+{
+ my $interface = shift;
+ my $function = shift;
+
+ my @specials = ();
+ push(@specials, ("DontDelete", "ReadOnly")) if IsUnforgeable($interface, $function);
+ push(@specials, "DontEnum") if $function->extendedAttributes->{NotEnumerable};
+ if (IsJSBuiltin($interface, $function)) {
+ push(@specials, "JSC::Builtin");
+ }
+ else {
+ push(@specials, "JSC::Function");
+ }
+ if ($function->extendedAttributes->{"DOMJIT"}) {
+ push(@specials, "DOMJITFunction") if $function->extendedAttributes->{DOMJIT};
+ }
+ return (@specials > 0) ? join(" | ", @specials) : "0";
+}
+
+sub IsJSBuiltin
+{
+ my ($interface, $object) = @_;
- return HasCustomConstructor($interface) || $interface->extendedAttributes->{"Constructor"} || $interface->extendedAttributes->{"NamedConstructor"} || $interface->extendedAttributes->{"ConstructorTemplate"};
+ return 0 if $object->extendedAttributes->{Custom};
+ return 0 if $object->extendedAttributes->{CustomGetter};
+ return 0 if $object->extendedAttributes->{CustomSetter};
+
+ return 1 if $object->extendedAttributes->{JSBuiltin};
+ return 1 if $interface->extendedAttributes->{JSBuiltin};
+
+ return 0;
+}
+
+sub IsJSBuiltinConstructor
+{
+ my ($interface) = @_;
+
+ return 0 if $interface->extendedAttributes->{CustomConstructor};
+ return 1 if $interface->extendedAttributes->{JSBuiltin};
+ return 1 if $interface->extendedAttributes->{JSBuiltinConstructor};
+ return 0;
+}
+
+sub GetJSBuiltinFunctionName
+{
+ my ($className, $function) = @_;
+ my $scopeName = $function->extendedAttributes->{ImplementedBy};
+ $scopeName = substr $className, 2 unless $scopeName;
+ return GetJSBuiltinFunctionNameFromString($scopeName, $function->name);
+}
+
+sub GetJSBuiltinFunctionNameFromString
+{
+ my ($scopeName, $functionName) = @_;
+ return $codeGenerator->WK_lcfirst($scopeName) . $codeGenerator->WK_ucfirst($functionName) . "CodeGenerator";
+}
+
+sub GetJSBuiltinScopeName
+{
+ my ($interface, $object) = @_;
+ return $object->extendedAttributes->{ImplementedBy} || $interface->type->name;
+}
+
+sub AddJSBuiltinIncludesIfNeeded()
+{
+ my $interface = shift;
+
+ if ($interface->extendedAttributes->{JSBuiltin} || $interface->extendedAttributes->{JSBuiltinConstructor}) {
+ AddToImplIncludes($interface->type->name . "Builtins.h");
+ return;
+ }
+
+ foreach my $function (@{$interface->functions}) {
+ AddToImplIncludes(GetJSBuiltinScopeName($interface, $function) . "Builtins.h", $function->extendedAttributes->{Conditional}) if IsJSBuiltin($interface, $function);
+ }
+
+ foreach my $attribute (@{$interface->attributes}) {
+ AddToImplIncludes(GetJSBuiltinScopeName($interface, $attribute) . "Builtins.h", $attribute->extendedAttributes->{Conditional}) if IsJSBuiltin($interface, $attribute);
+ }
}
1;
diff --git a/Source/WebCore/bindings/scripts/IDLAttributes.txt b/Source/WebCore/bindings/scripts/IDLAttributes.txt
index 85ead715d..e872d88d9 100644
--- a/Source/WebCore/bindings/scripts/IDLAttributes.txt
+++ b/Source/WebCore/bindings/scripts/IDLAttributes.txt
@@ -19,54 +19,66 @@
#
ActiveDOMObject
-CPPPureInterface
+AppleCopyright
+AtomicString
+CEReactions
CachedAttribute
CallbackNeedsOperatorEqual
-CallWith=ScriptExecutionContext|ScriptState|ScriptArguments|CallStack
+CallWith=Document|ScriptExecutionContext|ScriptState|ScriptArguments|CallStack|GlobalObject|ActiveWindow|FirstWindow|CallerDocument|CallerWindow
CheckSecurity
CheckSecurityForNode
Clamp
Conditional=*
+ConstantsScope=*
Constructor
-ConstructorCallWith=ScriptExecutionContext
-ConstructorConditional=*
-ConstructorRaisesException
-ConstructorTemplate=Event|TypedArray
+ConstructorCallWith=Document|ScriptExecutionContext|ScriptState
+ConstructorMayThrowException
Custom
CustomCall
CustomConstructor
CustomDeleteProperty
CustomEnumerateProperty
CustomGetOwnPropertySlot
+CustomGetPrototype
CustomGetter
CustomIndexedSetter
CustomIsReachable
CustomNamedGetter
CustomNamedSetter
+CustomPreventExtensions
+CustomProxyToJSObject
CustomPutFunction
-CustomReturn
+CustomSetPrototype
CustomSetter
CustomToJSObject
-Default=NullString|Undefined
-Deletable
+CustomToStringName
+DOMJIT=|ReadDOM|Getter
DoNotCheckConstants
DoNotCheckSecurity
DoNotCheckSecurityOnGetter
DoNotCheckSecurityOnSetter
+DocumentEventHandler
EnabledAtRuntime=*
EnabledBySetting=*
+EnabledForWorld=*
EnforceRange
-EventTarget
-GenerateIsReachable=|Impl|ImplWebGLRenderingContext|ImplDocument|ImplElementRoot|ImplFrame|ImplOwnerNodeRoot
-GetterRaisesException
-GlobalContext=DOMWindow|WorkerGlobalScope|SharedWorkerGlobalScope|DedicatedWorkerGlobalScope
+ExportMacro=WEBCORE_EXPORT|WEBCORE_TESTSUPPORT_EXPORT
+ExportToWrappedFunction
+Exposed=*
+ForwardDeclareInHeader
+GenerateIsReachable=|Impl|ImplWebGLRenderingContext|ImplDocument|ImplElementRoot|ImplFrame|ImplOwnerNodeRoot|ImplScriptExecutionContext
+GetterMayThrowException
+Global=*
Immutable
-ImplementationLacksVTable
-ImplementationNamespace=*
ImplementedAs=*
-InitializedByEventConstructor
+ImplementationLacksVTable
+ImplicitThis
InterfaceName=*
-IsIndex
+IsImmutablePrototypeExoticObject
+IsImmutablePrototypeExoticObjectOnPrototype
+IsWeakCallback
+JSBuiltin
+JSBuiltinConstructor
JSCustomDefineOwnProperty
JSCustomDefineOwnPropertyOnPrototype
JSCustomFinalize
@@ -79,34 +91,33 @@ JSCustomToNativeObject
JSGenerateToJSObject
JSGenerateToNativeObject
JSLegacyParent=*
-JSNoStaticTables
-JSWindowEventListener
+LegacyUnenumerableNamedProperties
+LenientThis
MasqueradesAsUndefined
+MayThrowException
NamedConstructor=*
NewImpurePropertyFiresWatchpoints
+NewObject
NoInterfaceObject
NotEnumerable
-NotDeletable
-ObjCCustomImplementation
-ObjCLegacyUnnamedParameters
-ObjCPolymorphic
-ObjCProtocol
-OperationsNotDeletable
+OverrideBuiltins
+OverrideIDLType=*
PassContext
-RaisesException
+PrimaryGlobal
+PrivateIdentifier
+PublicIdentifier
+PutForwards=*
Reflect=*
Replaceable
-ReplaceableConstructor
-ReturnNewObject
-SetterRaisesException
+ReportExtraMemoryCost
+ReportExternalMemoryCost
+RequiresExistingAtomicString
+SetterCallWith=ScriptExecutionContext|ScriptState|ScriptArguments|CallStack|GlobalObject|ActiveWindow|FirstWindow
+SetterMayThrowException
SkipVTableValidation
-StrictTypeChecking
SuppressToJSObject
-TreatNullAs=NullString
-TreatReturnedNullStringAs=Null|Undefined
-TreatUndefinedAs=NullString
-TypedArray=*
+TreatNullAs=EmptyString
URL
-
-# PLATFORM(IOS)
-AppleCopyright
+Unforgeable
+Unscopable
+WindowEventHandler
diff --git a/Source/WebCore/bindings/scripts/IDLParser.pm b/Source/WebCore/bindings/scripts/IDLParser.pm
index 319f62bae..2107b94a5 100644
--- a/Source/WebCore/bindings/scripts/IDLParser.pm
+++ b/Source/WebCore/bindings/scripts/IDLParser.pm
@@ -23,6 +23,9 @@ package IDLParser;
use strict;
+use Carp qw<longmess>;
+use Data::Dumper;
+
use preprocessor;
use Class::Struct;
@@ -34,68 +37,132 @@ use constant OtherToken => 4;
use constant EmptyToken => 5;
# Used to represent a parsed IDL document
-struct( idlDocument => {
- interfaces => '@', # All parsed interfaces
- enumerations => '@', # All parsed enumerations
- fileName => '$', # file name
+struct( IDLDocument => {
+ interfaces => '@', # List of 'IDLInterface'
+ enumerations => '@', # List of 'IDLEnum'
+ dictionaries => '@', # List of 'IDLDictionary'
+ callbackFunctions => '@', # List of 'IDLCallbackFunction'
+ fileName => '$',
+});
+
+# https://heycam.github.io/webidl/#idl-types
+struct( IDLType => {
+ name => '$', # Type identifier
+ isNullable => '$', # Is the type Nullable (T?)
+ isUnion => '$', # Is the type a union (T or U)
+ subtypes => '@', # Array of subtypes, only valid if isUnion or sequence
});
# Used to represent 'interface' blocks
-struct( domInterface => {
- name => '$', # Class identifier
- parent => '$', # Parent class identifier
- parents => '@', # Parent class identifiers (Kept for compatibility with ObjC bindings)
- constants => '@', # List of 'domConstant'
- functions => '@', # List of 'domFunction'
- anonymousFunctions => '@', # List of 'domFunction'
- attributes => '@', # List of 'domAttribute'
- extendedAttributes => '$', # Extended attributes
- constructors => '@', # Constructors, list of 'domFunction'
- customConstructors => '@', # Custom constructors, list of 'domFunction'
+struct( IDLInterface => {
+ type => 'IDLType',
+ parentType => 'IDLType',
+ constants => '@', # List of 'IDLConstant'
+ functions => '@', # List of 'IDLOperation'
+ anonymousFunctions => '@', # List of 'IDLOperation'
+ attributes => '@', # List of 'IDLAttribute'
+ constructors => '@', # Constructors, list of 'IDLOperation'
+ customConstructors => '@', # Custom constructors, list of 'IDLOperation'
isException => '$', # Used for exception interfaces
isCallback => '$', # Used for callback interfaces
isPartial => '$', # Used for partial interfaces
+ iterable => '$', # Used for iterable interfaces
+ serializable => '$', # Used for serializable interfaces
+ extendedAttributes => '$',
});
-# Used to represent domInterface contents (name of method, signature)
-struct( domFunction => {
+# Used to represent an argument to a IDLOperation.
+struct( IDLArgument => {
+ name => '$',
+ type => 'IDLType',
+ isVariadic => '$',
+ isOptional => '$',
+ default => '$',
+ extendedAttributes => '$',
+});
+
+# https://heycam.github.io/webidl/#idl-operations
+struct( IDLOperation => {
+ name => '$',
+ type => 'IDLType', # Return type
+ arguments => '@', # List of 'IDLArgument'
isStatic => '$',
- signature => '$', # Return type/Object name/extended attributes
- parameters => '@', # List of 'domSignature'
+ specials => '@',
+ extendedAttributes => '$',
});
-# Used to represent domInterface contents (name of attribute, signature)
-struct( domAttribute => {
- type => '$', # Attribute type (including namespace)
+
+# https://heycam.github.io/webidl/#idl-attributes
+struct( IDLAttribute => {
+ name => '$',
+ type => 'IDLType',
isStatic => '$',
+ isStringifier => '$',
isReadOnly => '$',
- signature => '$', # Attribute signature
+ extendedAttributes => '$',
+});
+
+# https://heycam.github.io/webidl/#idl-iterable
+struct( IDLIterable => {
+ isKeyValue => '$',
+ keyType => 'IDLType',
+ valueType => 'IDLType',
+ functions => '@', # Iterable functions (entries, keys, values, [Symbol.Iterator], forEach)
+ extendedAttributes => '$',
+});
+
+# https://heycam.github.io/webidl/#idl-serializers
+struct( IDLSerializable => {
+ attributes => '@', # List of attributes to serialize
+ hasAttribute => '$', # serializer = { attribute }
+ hasInherit => '$', # serializer = { inherit }
+ hasGetter => '$', # serializer = { getter }
+ functions => '@', # toJSON function
+});
+
+# https://heycam.github.io/webidl/#idl-constants
+struct( IDLConstant => {
+ name => '$',
+ type => 'IDLType',
+ value => '$',
+ extendedAttributes => '$',
+});
+
+# https://heycam.github.io/webidl/#idl-enums
+struct( IDLEnum => {
+ name => '$',
+ type => 'IDLType',
+ values => '@',
+ extendedAttributes => '$',
+});
+
+# https://heycam.github.io/webidl/#dfn-dictionary-member
+struct( IDLDictionaryMember => {
+ name => '$',
+ type => 'IDLType',
+ isRequired => '$',
+ default => '$',
+ extendedAttributes => '$',
});
-# Used to represent a map of 'variable name' <-> 'variable type'
-struct( domSignature => {
- direction => '$', # Variable direction (in or out)
- name => '$', # Variable name
- type => '$', # Variable type
- specials => '@', # Specials
- extendedAttributes => '$', # Extended attributes
- isNullable => '$', # Is variable type Nullable (T?)
- isVariadic => '$', # Is variable variadic (long... numbers)
- isOptional => '$', # Is variable optional (optional T)
+# https://heycam.github.io/webidl/#idl-dictionaries
+struct( IDLDictionary => {
+ type => 'IDLType',
+ parentType => 'IDLType',
+ members => '@', # List of 'IDLDictionaryMember'
+ extendedAttributes => '$',
});
-# Used to represent string constants
-struct( domConstant => {
- name => '$', # DOM Constant identifier
- type => '$', # Type of data
- value => '$', # Constant value
- extendedAttributes => '$', # Extended attributes
+# https://heycam.github.io/webidl/#idl-callback-functions
+struct( IDLCallbackFunction => {
+ type => '$',
+ operation => 'IDLOperation',
+ extendedAttributes => '$',
});
-# Used to represent 'enum' definitions
-struct( domEnum => {
- name => '$', # Enumeration identifier
- values => '@', # Enumeration values (list of unique strings)
+# https://heycam.github.io/webidl/#idl-typedefs
+struct( IDLTypedef => {
+ type => 'IDLType',
});
struct( Token => {
@@ -103,11 +170,6 @@ struct( Token => {
value => '$' # value of token
});
-struct( Typedef => {
- extendedAttributes => '$', # Extended attributes
- type => '$', # Type of data
-});
-
# Maps 'typedef name' -> Typedef
my %typedefs = ();
@@ -129,17 +191,28 @@ sub new {
return bless $self, $class;
}
+sub assert
+{
+ my $message = shift;
+
+ my $mess = longmess();
+ print Dumper($mess);
+
+ die $message;
+}
+
sub assertTokenValue
{
my $self = shift;
my $token = shift;
my $value = shift;
my $line = shift;
- my $msg = "Next token should be " . $value . ", but " . $token->value() . " at " . $self->{Line};
+ my $msg = "Next token should be " . $value . ", but " . $token->value() . " on line " . $self->{Line};
if (defined ($line)) {
$msg .= " IDLParser.pm:" . $line;
}
- die $msg unless $token->value() eq $value;
+
+ assert $msg unless $token->value() eq $value;
}
sub assertTokenType
@@ -147,7 +220,8 @@ sub assertTokenType
my $self = shift;
my $token = shift;
my $type = shift;
- die "Next token's type should be " . $type . ", but " . $token->type() . " at " . $self->{Line} unless $token->type() eq $type;
+
+ assert "Next token's type should be " . $type . ", but " . $token->type() . " on line " . $self->{Line} unless $token->type() eq $type;
}
sub assertUnexpectedToken
@@ -155,11 +229,12 @@ sub assertUnexpectedToken
my $self = shift;
my $token = shift;
my $line = shift;
- my $msg = "Unexpected token " . $token . " at " . $self->{Line};
+ my $msg = "Unexpected token " . $token . " on line " . $self->{Line};
if (defined ($line)) {
$msg .= " IDLParser.pm:" . $line;
}
- die $msg;
+
+ assert $msg;
}
sub assertNoExtendedAttributesInTypedef
@@ -168,11 +243,12 @@ sub assertNoExtendedAttributesInTypedef
my $name = shift;
my $line = shift;
my $typedef = $typedefs{$name};
- my $msg = "Unexpected extendedAttributeList in typedef \"$name\" at " . $self->{Line};
+ my $msg = "Unexpected extendedAttributeList in typedef \"$name\" on line " . $self->{Line};
if (defined ($line)) {
$msg .= " IDLParser.pm:" . $line;
}
- die $msg if %{$typedef->extendedAttributes};
+
+ assert $msg if %{$typedef->extendedAttributes};
}
sub Parse
@@ -196,15 +272,19 @@ sub Parse
my $next = $self->nextToken();
$self->assertTokenType($next, EmptyToken);
};
- die $@ . " in $fileName" if $@;
+ assert $@ . " in $fileName" if $@;
- my $document = idlDocument->new();
+ my $document = IDLDocument->new();
$document->fileName($fileName);
foreach my $definition (@definitions) {
- if (ref($definition) eq "domInterface") {
+ if (ref($definition) eq "IDLInterface") {
push(@{$document->interfaces}, $definition);
- } elsif (ref($definition) eq "domEnum") {
+ } elsif (ref($definition) eq "IDLEnum") {
push(@{$document->enumerations}, $definition);
+ } elsif (ref($definition) eq "IDLDictionary") {
+ push(@{$document->dictionaries}, $definition);
+ } elsif (ref($definition) eq "IDLCallbackFunction") {
+ push(@{$document->callbackFunctions}, $definition);
} else {
die "Unrecognized IDL definition kind: \"" . ref($definition) . "\"";
}
@@ -231,7 +311,7 @@ my $floatTokenPattern = '^(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|
my $integerTokenPattern = '^(-?[1-9][0-9]*|-?0[Xx][0-9A-Fa-f]+|-?0[0-7]*)';
my $stringTokenPattern = '^(\"[^\"]*\")';
my $identifierTokenPattern = '^([A-Z_a-z][0-9A-Z_a-z]*)';
-my $otherTokenPattern = '^(::|\.\.\.|[^\t\n\r 0-9A-Z_a-z])';
+my $otherTokenPattern = '^(\.\.\.|[^\t\n\r 0-9A-Z_a-z])';
sub getTokenInternal
{
@@ -296,51 +376,75 @@ sub unquoteString
die "Failed to parse string (" . $quotedString . ") at " . $self->{Line};
}
-sub typeHasNullableSuffix
+sub identifierRemoveNullablePrefix
{
my $type = shift;
- return $type =~ /\?$/;
+ $type =~ s/^_//;
+ return $type;
}
-sub typeRemoveNullableSuffix
+sub typeDescription
{
my $type = shift;
- $type =~ s/\?//g;
+
+ if (scalar @{$type->subtypes}) {
+ return $type->name . '<' . join(', ', map { typeDescription($_) } @{$type->subtypes}) . '>' . ($type->isNullable ? "?" : "");
+ }
+
+ return $type->name . ($type->isNullable ? "?" : "");
+}
+
+sub makeSimpleType
+{
+ my $typeName = shift;
+
+ my $type = IDLType->new();
+ $type->name($typeName);
+
return $type;
}
-sub identifierRemoveNullablePrefix
+sub cloneType
{
+ my $self = shift;
my $type = shift;
- $type =~ s/^_//;
- return $type;
+
+ my $clonedType = IDLType->new();
+ $clonedType->name($type->name);
+ $clonedType->isNullable($type->isNullable);
+ $clonedType->isUnion($type->isUnion);
+ foreach my $subtype (@{$type->subtypes}) {
+ push(@{$clonedType->subtypes}, $self->cloneType($subtype));
+ }
+
+ return $clonedType;
}
my $nextAttribute_1 = '^(attribute|inherit|readonly)$';
my $nextPrimitiveType_1 = '^(int|long|short|unsigned)$';
my $nextPrimitiveType_2 = '^(double|float|unrestricted)$';
-my $nextArgumentList_1 = '^(\(|::|ByteString|DOMString|Date|\[|any|boolean|byte|double|float|in|int|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
-my $nextNonAnyType_1 = '^(boolean|byte|double|float|int|long|octet|short|unrestricted|unsigned)$';
-my $nextInterfaceMember_1 = '^(\(|::|ByteString|DOMString|Date|any|attribute|boolean|byte|creator|deleter|double|float|getter|inherit|int|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
-my $nextOptionalIteratorInterfaceOrObject_1 = '^(;|=)$';
-my $nextAttributeOrOperationOrIterator_1 = '^(static|stringifier)$';
-my $nextAttributeOrOperationOrIterator_2 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|creator|deleter|double|float|getter|int|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
+my $nextArgumentList_1 = '^(\(|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|double|float|in|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
+my $nextNonAnyType_1 = '^(boolean|byte|double|float|long|octet|short|unrestricted|unsigned)$';
+my $nextStringType_1 = '^(ByteString|DOMString|USVString)$';
+my $nextInterfaceMember_1 = '^(\(|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|creator|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
+my $nextAttributeOrOperation_1 = '^(static|stringifier)$';
+my $nextAttributeOrOperation_2 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|creator|deleter|double|float|getter|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
my $nextUnrestrictedFloatType_1 = '^(double|float)$';
-my $nextExtendedAttributeRest3_1 = '^(\,|::|\])$';
-my $nextExceptionField_1 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
-my $nextType_1 = '^(::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
+my $nextExtendedAttributeRest3_1 = '^(\,|\])$';
+my $nextExceptionField_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
+my $nextType_1 = '^(ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
my $nextSpecials_1 = '^(creator|deleter|getter|legacycaller|setter)$';
-my $nextDefinitions_1 = '^(::|callback|dictionary|enum|exception|interface|partial|typedef)$';
-my $nextExceptionMembers_1 = '^(\(|::|ByteString|DOMString|Date|\[|any|boolean|byte|const|double|float|int|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
+my $nextDefinitions_1 = '^(callback|dictionary|enum|exception|interface|partial|typedef)$';
+my $nextExceptionMembers_1 = '^(\(|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|const|double|float|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
my $nextAttributeRest_1 = '^(attribute|readonly)$';
-my $nextInterfaceMembers_1 = '^(\(|::|ByteString|DOMString|Date|any|attribute|boolean|byte|const|creator|deleter|double|float|getter|inherit|int|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
-my $nextSingleType_1 = '^(::|ByteString|DOMString|Date|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
+my $nextInterfaceMembers_1 = '^(\(|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|const|creator|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
+my $nextSingleType_1 = '^(ByteString|DOMString|USVString|Date|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
my $nextArgumentName_1 = '^(attribute|callback|const|creator|deleter|dictionary|enum|exception|getter|implements|inherit|interface|legacycaller|partial|serializer|setter|static|stringifier|typedef|unrestricted)$';
my $nextConstValue_1 = '^(false|true)$';
my $nextConstValue_2 = '^(-|Infinity|NaN)$';
my $nextDefinition_1 = '^(callback|interface)$';
-my $nextAttributeOrOperationRest_1 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned|void)$';
-my $nextUnsignedIntegerType_1 = '^(int|long|short)$';
+my $nextAttributeOrOperationRest_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned|void)$';
+my $nextUnsignedIntegerType_1 = '^(long|short)$';
my $nextDefaultValue_1 = '^(-|Infinity|NaN|false|null|true)$';
@@ -374,59 +478,71 @@ sub applyTypedefs
if (!%typedefs) {
return;
}
+
+ # FIXME: Add support for applying typedefs to IDLIterable.
foreach my $definition (@$definitions) {
- if (ref($definition) eq "domInterface") {
+ if (ref($definition) eq "IDLInterface") {
foreach my $constant (@{$definition->constants}) {
- if (exists $typedefs{$constant->type}) {
- my $typedef = $typedefs{$constant->type};
- $self->assertNoExtendedAttributesInTypedef($constant->type, __LINE__);
- $constant->type($typedef->type);
- }
+ $constant->type($self->typeByApplyingTypedefs($constant->type));
}
foreach my $attribute (@{$definition->attributes}) {
- $self->applyTypedefsForSignature($attribute->signature);
+ $attribute->type($self->typeByApplyingTypedefs($attribute->type));
}
- foreach my $function (@{$definition->functions}, @{$definition->anonymousFunctions}, @{$definition->constructors}, @{$definition->customConstructors}) {
- $self->applyTypedefsForSignature($function->signature);
- foreach my $signature (@{$function->parameters}) {
- $self->applyTypedefsForSignature($signature);
- }
+ foreach my $operation (@{$definition->functions}, @{$definition->anonymousFunctions}, @{$definition->constructors}, @{$definition->customConstructors}) {
+ $self->applyTypedefsToOperation($operation);
}
+ } elsif (ref($definition) eq "IDLDictionary") {
+ foreach my $member (@{$definition->members}) {
+ $member->type($self->typeByApplyingTypedefs($member->type));
+ }
+ } elsif (ref($definition) eq "IDLCallbackFunction") {
+ $self->applyTypedefsToOperation($definition->operation);
}
}
}
-sub applyTypedefsForSignature
+sub applyTypedefsToOperation
{
my $self = shift;
- my $signature = shift;
+ my $operation = shift;
- if (!defined ($signature->type)) {
- return;
+ if ($operation->type) {
+ $operation->type($self->typeByApplyingTypedefs($operation->type));
}
- my $type = $signature->type;
- $type =~ s/[\?\[\]]+$//g;
- my $typeSuffix = $signature->type;
- $typeSuffix =~ s/^[^\?\[\]]+//g;
- if (exists $typedefs{$type}) {
- my $typedef = $typedefs{$type};
- $signature->type($typedef->type . $typeSuffix);
- copyExtendedAttributes($signature->extendedAttributes, $typedef->extendedAttributes);
+ foreach my $argument (@{$operation->arguments}) {
+ $argument->type($self->typeByApplyingTypedefs($argument->type));
}
+}
- # Handle union types, sequences and etc.
- foreach my $name (%typedefs) {
- if (!exists $typedefs{$name}) {
- next;
+sub typeByApplyingTypedefs
+{
+ my $self = shift;
+ my $type = shift;
+
+ assert("Missing type") if !$type;
+
+ my $numberOfSubtypes = scalar @{$type->subtypes};
+ if ($numberOfSubtypes) {
+ for my $i (0..$numberOfSubtypes - 1) {
+ my $subtype = @{$type->subtypes}[$i];
+ my $replacementSubtype = $self->typeByApplyingTypedefs($subtype);
+ @{$type->subtypes}[$i] = $replacementSubtype
}
- my $typedef = $typedefs{$name};
- my $regex = '\\b' . $name . '\\b';
- my $replacement = $typedef->type;
- my $type = $signature->type;
- $type =~ s/($regex)/$replacement/g;
- $signature->type($type);
+
+ return $type;
}
+
+ if (exists $typedefs{$type->name}) {
+ my $typedef = $typedefs{$type->name};
+
+ my $clonedType = $self->cloneType($typedef->type);
+ $clonedType->isNullable($clonedType->isNullable || $type->isNullable);
+
+ return $self->typeByApplyingTypedefs($clonedType);
+ }
+
+ return $type;
}
sub parseDefinition
@@ -453,7 +569,7 @@ sub parseDefinition
if ($next->value() eq "typedef") {
return $self->parseTypedef($extendedAttributeList);
}
- if ($next->type() == IdentifierToken || $next->value() eq "::") {
+ if ($next->type() == IdentifierToken) {
return $self->parseImplementsStatement($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
@@ -499,14 +615,20 @@ sub parseInterface
my $next = $self->nextToken();
if ($next->value() eq "interface") {
- my $interface = domInterface->new();
+ my $interface = IDLInterface->new();
$self->assertTokenValue($self->getToken(), "interface", __LINE__);
my $interfaceNameToken = $self->getToken();
$self->assertTokenType($interfaceNameToken, IdentifierToken);
- $interface->name(identifierRemoveNullablePrefix($interfaceNameToken->value()));
- my $parents = $self->parseInheritance();
- $interface->parents($parents);
- $interface->parent($parents->[0]);
+
+ my $name = identifierRemoveNullablePrefix($interfaceNameToken->value());
+ $interface->type(makeSimpleType($name));
+
+ $next = $self->nextToken();
+ if ($next->value() eq ":") {
+ my $parent = $self->parseInheritance();
+ $interface->parentType(makeSimpleType($parent));
+ }
+
$self->assertTokenValue($self->getToken(), "{", __LINE__);
my $interfaceMembers = $self->parseInterfaceMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
@@ -610,14 +732,27 @@ sub parseDictionary
my $next = $self->nextToken();
if ($next->value() eq "dictionary") {
+ my $dictionary = IDLDictionary->new();
+ $dictionary->extendedAttributes($extendedAttributeList);
$self->assertTokenValue($self->getToken(), "dictionary", __LINE__);
- $self->assertTokenType($self->getToken(), IdentifierToken);
- $self->parseInheritance();
+
+ my $nameToken = $self->getToken();
+ $self->assertTokenType($nameToken, IdentifierToken);
+
+ my $name = $nameToken->value();
+ $dictionary->type(makeSimpleType($name));
+
+ $next = $self->nextToken();
+ if ($next->value() eq ":") {
+ my $parent = $self->parseInheritance();
+ $dictionary->parentType(makeSimpleType($parent));
+ }
+
$self->assertTokenValue($self->getToken(), "{", __LINE__);
- $self->parseDictionaryMembers();
+ $dictionary->members($self->parseDictionaryMembers());
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
- return;
+ return $dictionary;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -626,15 +761,19 @@ sub parseDictionaryMembers
{
my $self = shift;
+ my @members = ();
+
while (1) {
my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
- $self->parseDictionaryMember($extendedAttributeList);
+ push(@members, $self->parseDictionaryMember($extendedAttributeList));
} else {
last;
}
}
+
+ return \@members;
}
sub parseDictionaryMember
@@ -644,11 +783,24 @@ sub parseDictionaryMember
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
- $self->parseType();
- $self->assertTokenType($self->getToken(), IdentifierToken);
- $self->parseDefault();
+ my $member = IDLDictionaryMember->new();
+ if ($next->value eq "required") {
+ $self->assertTokenValue($self->getToken(), "required", __LINE__);
+ $member->isRequired(1);
+ } else {
+ $member->isRequired(0);
+ }
+ $member->extendedAttributes($extendedAttributeList);
+
+ my $type = $self->parseType();
+ $member->type($type);
+
+ my $nameToken = $self->getToken();
+ $self->assertTokenType($nameToken, IdentifierToken);
+ $member->name($nameToken->value);
+ $member->default($self->parseDefault());
$self->assertTokenValue($self->getToken(), ";", __LINE__);
- return;
+ return $member;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -677,6 +829,7 @@ sub parseDefault
$self->assertTokenValue($self->getToken(), "=", __LINE__);
return $self->parseDefaultValue();
}
+ return undef;
}
sub parseDefaultValue
@@ -689,6 +842,11 @@ sub parseDefaultValue
if ($next->type() == StringToken) {
return $self->getToken()->value();
}
+ if ($next->value() eq "[") {
+ $self->assertTokenValue($self->getToken(), "[", __LINE__);
+ $self->assertTokenValue($self->getToken(), "]", __LINE__);
+ return "[]";
+ }
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -699,15 +857,21 @@ sub parseException
my $next = $self->nextToken();
if ($next->value() eq "exception") {
- my $interface = domInterface->new();
+ my $interface = IDLInterface->new();
$self->assertTokenValue($self->getToken(), "exception", __LINE__);
my $exceptionNameToken = $self->getToken();
$self->assertTokenType($exceptionNameToken, IdentifierToken);
- $interface->name(identifierRemoveNullablePrefix($exceptionNameToken->value()));
+
+ my $name = identifierRemoveNullablePrefix($exceptionNameToken->value());
+ $interface->type(makeSimpleType($name));
$interface->isException(1);
- my $parents = $self->parseInheritance();
- $interface->parents($parents);
- $interface->parent($parents->[0]);
+
+ $next = $self->nextToken();
+ if ($next->value() eq ":") {
+ my $parent = $self->parseInheritance();
+ $interface->parentType(makeSimpleType($parent));
+ }
+
$self->assertTokenValue($self->getToken(), "{", __LINE__);
my $exceptionMembers = $self->parseExceptionMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
@@ -743,35 +907,34 @@ sub parseExceptionMembers
sub parseInheritance
{
my $self = shift;
- my @parent = ();
my $next = $self->nextToken();
if ($next->value() eq ":") {
$self->assertTokenValue($self->getToken(), ":", __LINE__);
- my $scopedName = $self->parseScopedName();
- push(@parent, $scopedName);
- # Multiple inheritance (needed for ObjC bindings).
- push(@parent, @{$self->parseIdentifiers()});
+ return $self->parseName();
}
- return \@parent;
+ $self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseEnum
{
my $self = shift;
- my $extendedAttributeList = shift; # ignored: Extended attributes are not applicable to enumerations
+ my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "enum") {
- my $enum = domEnum->new();
+ my $enum = IDLEnum->new();
$self->assertTokenValue($self->getToken(), "enum", __LINE__);
my $enumNameToken = $self->getToken();
$self->assertTokenType($enumNameToken, IdentifierToken);
- $enum->name(identifierRemoveNullablePrefix($enumNameToken->value()));
+ my $name = identifierRemoveNullablePrefix($enumNameToken->value());
+ $enum->name($name);
+ $enum->type(makeSimpleType($name));
$self->assertTokenValue($self->getToken(), "{", __LINE__);
push(@{$enum->values}, @{$self->parseEnumValueList()});
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
+ $enum->extendedAttributes($extendedAttributeList);
return $enum;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
@@ -818,14 +981,30 @@ sub parseCallbackRest
my $next = $self->nextToken();
if ($next->type() == IdentifierToken) {
- $self->assertTokenType($self->getToken(), IdentifierToken);
+ my $callback = IDLCallbackFunction->new();
+
+ my $nameToken = $self->getToken();
+ $self->assertTokenType($nameToken, IdentifierToken);
+
+ $callback->type(makeSimpleType($nameToken->value()));
+
$self->assertTokenValue($self->getToken(), "=", __LINE__);
- $self->parseReturnType();
+
+ my $operation = IDLOperation->new();
+ $operation->type($self->parseReturnType());
+ $operation->extendedAttributes($extendedAttributeList);
+
$self->assertTokenValue($self->getToken(), "(", __LINE__);
- $self->parseArgumentList();
+
+ push(@{$operation->arguments}, @{$self->parseArgumentList()});
+
$self->assertTokenValue($self->getToken(), ")", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
- return;
+
+ $callback->operation($operation);
+ $callback->extendedAttributes($extendedAttributeList);
+
+ return $callback;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -839,14 +1018,16 @@ sub parseTypedef
my $next = $self->nextToken();
if ($next->value() eq "typedef") {
$self->assertTokenValue($self->getToken(), "typedef", __LINE__);
- my $typedef = Typedef->new();
- $typedef->extendedAttributes($self->parseExtendedAttributeListAllowEmpty());
- $typedef->type($self->parseType());
+ my $typedef = IDLTypedef->new();
+
+ my $type = $self->parseType();
+ $typedef->type($type);
+
my $nameToken = $self->getToken();
$self->assertTokenType($nameToken, IdentifierToken);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
my $name = $nameToken->value();
- die "typedef redefinition for " . $name . " at " . $self->{Line} if (exists $typedefs{$name} && $typedef->type ne $typedefs{$name}->type);
+ die "typedef redefinition for " . $name . " at " . $self->{Line} if (exists $typedefs{$name} && $typedef->type->name ne $typedefs{$name}->type->name);
$typedefs{$name} = $typedef;
return;
}
@@ -860,9 +1041,9 @@ sub parseImplementsStatement
my $next = $self->nextToken();
if ($next->type() == IdentifierToken) {
- $self->parseScopedName();
+ $self->parseName();
$self->assertTokenValue($self->getToken(), "implements", __LINE__);
- $self->parseScopedName();
+ $self->parseName();
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
@@ -876,9 +1057,10 @@ sub parseConst
my $next = $self->nextToken();
if ($next->value() eq "const") {
- my $newDataNode = domConstant->new();
+ my $newDataNode = IDLConstant->new();
$self->assertTokenValue($self->getToken(), "const", __LINE__);
- $newDataNode->type($self->parseConstType());
+ my $type = $self->parseConstType();
+ $newDataNode->type($type);
my $constNameToken = $self->getToken();
$self->assertTokenType($constNameToken, IdentifierToken);
$newDataNode->name(identifierRemoveNullablePrefix($constNameToken->value()));
@@ -905,10 +1087,6 @@ sub parseConstValue
if ($next->type() == FloatToken || $next->value() =~ /$nextConstValue_2/) {
return $self->parseFloatLiteral();
}
- # backward compatibility
- if ($next->type() == StringToken) {
- return $self->getToken()->value();
- }
if ($next->type() == IntegerToken) {
return $self->getToken()->value();
}
@@ -962,18 +1140,19 @@ sub parseAttributeOrOperationOrIterator
if ($next->value() eq "serializer") {
return $self->parseSerializer($extendedAttributeList);
}
- if ($next->value() =~ /$nextAttributeOrOperationOrIterator_1/) {
+ if ($next->value() =~ /$nextAttributeOrOperation_1/) {
my $qualifier = $self->parseQualifier();
my $newDataNode = $self->parseAttributeOrOperationRest($extendedAttributeList);
- if (defined($newDataNode) && $qualifier eq "static") {
- $newDataNode->isStatic(1);
+ if (defined($newDataNode)) {
+ $newDataNode->isStatic(1) if $qualifier eq "static";
+ $newDataNode->isStringifier(1) if $qualifier eq "stringifier";
}
return $newDataNode;
}
if ($next->value() =~ /$nextAttribute_1/) {
return $self->parseAttribute($extendedAttributeList);
}
- if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationOrIterator_2/) {
+ if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperation_2/) {
return $self->parseOperationOrIterator($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
@@ -987,7 +1166,22 @@ sub parseSerializer
my $next = $self->nextToken();
if ($next->value() eq "serializer") {
$self->assertTokenValue($self->getToken(), "serializer", __LINE__);
- return $self->parseSerializerRest($extendedAttributeList);
+ my $next = $self->nextToken();
+ my $newDataNode;
+ if ($next->value() ne ";") {
+ $newDataNode = $self->parseSerializerRest($extendedAttributeList);
+ my $next = $self->nextToken();
+ } else {
+ $newDataNode = IDLSerializable->new();
+ }
+
+ my $toJSONFunction = IDLOperation->new();
+ $toJSONFunction->name("toJSON");
+ $toJSONFunction->extendedAttributes($extendedAttributeList);
+ push(@{$newDataNode->functions}, $toJSONFunction);
+
+ $self->assertTokenValue($self->getToken(), ";", __LINE__);
+ return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -1000,7 +1194,9 @@ sub parseSerializerRest
my $next = $self->nextToken();
if ($next->value() eq "=") {
$self->assertTokenValue($self->getToken(), "=", __LINE__);
- return $self->parseSerializationPattern($extendedAttributeList);
+
+ return $self->parseSerializationPattern();
+
}
if ($next->type() == IdentifierToken || $next->value() eq "(") {
return $self->parseOperationRest($extendedAttributeList);
@@ -1010,59 +1206,74 @@ sub parseSerializerRest
sub parseSerializationPattern
{
my $self = shift;
- my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "{") {
$self->assertTokenValue($self->getToken(), "{", __LINE__);
- $self->parseSerializationPatternMap();
+ my $newDataNode = IDLSerializable->new();
+ $self->parseSerializationAttributes($newDataNode);
$self->assertTokenValue($self->getToken(), "}", __LINE__);
- return;
+ return $newDataNode;
}
if ($next->value() eq "[") {
- $self->assertTokenValue($self->getToken(), "[", __LINE__);
- $self->parseSerializationPatternList();
- $self->assertTokenValue($self->getToken(), "]", __LINE__);
- return;
+ die "Serialization of lists pattern is not currently supported.";
}
if ($next->type() == IdentifierToken) {
- $self->assertTokenType($self->getToken(), IdentifierToken);
- return;
+ my @attributes = ();
+ my $token = $self->getToken();
+ $self->assertTokenType($token, IdentifierToken);
+ push(@attributes, $token->value());
+
+ my $newDataNode = IDLSerializable->new();
+ $newDataNode->attributes(\@attributes);
+
+ return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
-sub parseSerializationPatternMap
+sub parseSerializationAttributes
{
my $self = shift;
- my $next = $self->nextToken();
- if ($next->value() eq "getter") {
- $self->assertTokenValue($self->getToken(), "getter", __LINE__);
- return;
- }
- if ($next->value() eq "inherit") {
- $self->assertTokenValue($self->getToken(), "inherit", __LINE__);
- $self->parseIdentifiers();
- return;
- }
- if ($next->type() == IdentifierToken) {
- $self->assertTokenType($self->getToken(), IdentifierToken);
- $self->parseIdentifiers();
+ my $serializable = shift;
+
+ my @attributes = ();
+ my @identifiers = $self->parseIdentifierList();
+
+ for my $identifier (@identifiers) {
+ if ($identifier eq "getter") {
+ $serializable->hasGetter(1);
+ die "Serializer getter keyword is not currently supported.";
+ }
+
+ if ($identifier eq "inherit") {
+ $serializable->hasInherit(1);
+ next;
+ }
+
+ if ($identifier eq "attribute") {
+ $serializable->hasAttribute(1);
+ # Attributes will be filled in via applyMemberList()
+ next;
+ }
+
+ push(@attributes, $identifier);
}
+
+ $serializable->attributes(\@attributes);
}
-sub parseSerializationPatternList
+sub parseIdentifierList
{
my $self = shift;
my $next = $self->nextToken();
- if ($next->value() eq "getter") {
- $self->assertTokenValue($self->getToken(), "getter", __LINE__);
- return;
- }
- if ($next->type() == IdentifierToken) {
- $self->assertTokenType($self->getToken(), IdentifierToken);
- $self->parseIdentifiers();
+
+ my @identifiers = ();
+ if ($next->type == IdentifierToken) {
+ push(@identifiers, $self->getToken()->value());
+ push(@identifiers, @{$self->parseIdentifiers()});
}
+ return @identifiers;
}
sub parseIdentifiers
@@ -1115,11 +1326,11 @@ sub parseAttributeOrOperationRest
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) {
my $returnType = $self->parseReturnType();
- my $interface = $self->parseOperationRest($extendedAttributeList);
- if (defined ($interface)) {
- $interface->signature->type($returnType);
+ my $operation = $self->parseOperationRest($extendedAttributeList);
+ if (defined ($operation)) {
+ $operation->type($returnType);
}
- return $interface;
+ return $operation;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -1144,33 +1355,25 @@ sub parseAttributeRest
my $next = $self->nextToken();
if ($next->value() =~ /$nextAttributeRest_1/) {
- my $newDataNode = domAttribute->new();
- if ($self->parseReadOnly()) {
- $newDataNode->type("attribute");
- $newDataNode->isReadOnly(1);
- } else {
- $newDataNode->type("attribute");
- }
+ my $newDataNode = IDLAttribute->new();
+ $newDataNode->isReadOnly($self->parseReadOnly());
+
$self->assertTokenValue($self->getToken(), "attribute", __LINE__);
- $newDataNode->signature(domSignature->new());
+
my $type = $self->parseType();
- if (typeHasNullableSuffix($type)) {
- $newDataNode->signature->isNullable(1);
- } else {
- $newDataNode->signature->isNullable(0);
- }
- # Remove all "?" in the type declaration, e.g. "double?" -> "double".
- $newDataNode->signature->type(typeRemoveNullableSuffix($type));
+ $newDataNode->type($type);
+
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
- $newDataNode->signature->name(identifierRemoveNullablePrefix($token->value()));
+ $newDataNode->name(identifierRemoveNullablePrefix($token->value()));
$self->assertTokenValue($self->getToken(), ";", __LINE__);
+
# CustomConstructor may also be used on attributes.
if (defined $extendedAttributeList->{"CustomConstructors"}) {
delete $extendedAttributeList->{"CustomConstructors"};
$extendedAttributeList->{"CustomConstructor"} = "VALUE_IS_MISSING";
}
- $newDataNode->signature->extendedAttributes($extendedAttributeList);
+ $newDataNode->extendedAttributes($extendedAttributeList);
return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
@@ -1207,13 +1410,17 @@ sub parseOperationOrIterator
if ($next->value() =~ /$nextSpecials_1/) {
return $self->parseSpecialOperation($extendedAttributeList);
}
+ if ($next->value() eq "iterable") {
+ return $self->parseIterableRest($extendedAttributeList);
+ }
if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) {
my $returnType = $self->parseReturnType();
- my $interface = $self->parseOperationOrIteratorRest($extendedAttributeList);
- if (defined ($interface)) {
- $interface->signature->type($returnType);
+ my $next = $self->nextToken();
+ if ($next->type() == IdentifierToken || $next->value() eq "(") {
+ my $operation = $self->parseOperationRest($extendedAttributeList);
+ $operation->type($returnType);
+ return $operation;
}
- return $interface;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -1228,12 +1435,12 @@ sub parseSpecialOperation
my @specials = ();
push(@specials, @{$self->parseSpecials()});
my $returnType = $self->parseReturnType();
- my $interface = $self->parseOperationRest($extendedAttributeList);
- if (defined ($interface)) {
- $interface->signature->type($returnType);
- $interface->signature->specials(\@specials);
+ my $operation = $self->parseOperationRest($extendedAttributeList);
+ if (defined ($operation)) {
+ $operation->type($returnType);
+ $operation->specials(\@specials);
}
- return $interface;
+ return $operation;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -1281,62 +1488,75 @@ sub parseSpecial
$self->assertUnexpectedToken($next->value(), __LINE__);
}
-sub parseOperationOrIteratorRest
+sub parseIterableRest
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
- if ($next->value() eq "iterator") {
- return $self->parseIteratorRest($extendedAttributeList);
- }
- if ($next->type() == IdentifierToken || $next->value() eq "(") {
- return $self->parseOperationRest($extendedAttributeList);
- }
- $self->assertUnexpectedToken($next->value(), __LINE__);
-}
-
-sub parseIteratorRest
-{
- my $self = shift;
- my $extendedAttributeList = shift;
-
- my $next = $self->nextToken();
- if ($next->value() eq "iterator") {
- $self->assertTokenValue($self->getToken(), "iterator", __LINE__);
- $self->parseOptionalIteratorInterfaceOrObject($extendedAttributeList);
+ if ($next->value() eq "iterable") {
+ $self->assertTokenValue($self->getToken(), "iterable", __LINE__);
+ my $iterableNode = $self->parseOptionalIterableInterface($extendedAttributeList);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
- return;
+ return $iterableNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
-sub parseOptionalIteratorInterfaceOrObject
+sub parseOptionalIterableInterface
{
my $self = shift;
my $extendedAttributeList = shift;
- my $next = $self->nextToken();
- if ($next->value() =~ /$nextOptionalIteratorInterfaceOrObject_1/) {
- return $self->parseOptionalIteratorInterface($extendedAttributeList);
- }
- if ($next->value() eq "object") {
- $self->assertTokenValue($self->getToken(), "object", __LINE__);
- return;
- }
- $self->assertUnexpectedToken($next->value(), __LINE__);
-}
-
-sub parseOptionalIteratorInterface
-{
- my $self = shift;
- my $extendedAttributeList = shift;
+ my $symbolIteratorFunction = IDLOperation->new();
+ $symbolIteratorFunction->name("[Symbol.Iterator]");
+ $symbolIteratorFunction->extendedAttributes($extendedAttributeList);
+
+ my $entriesFunction = IDLOperation->new();
+ $entriesFunction->name("entries");
+ $entriesFunction->extendedAttributes($extendedAttributeList);
+
+ my $keysFunction = IDLOperation->new();
+ $keysFunction->name("keys");
+ $keysFunction->extendedAttributes($extendedAttributeList);
+
+ my $valuesFunction = IDLOperation->new();
+ $valuesFunction->name("values");
+ $valuesFunction->extendedAttributes($extendedAttributeList);
+
+ my $forEachFunction = IDLOperation->new();
+ $forEachFunction->name("forEach");
+ $forEachFunction->extendedAttributes($extendedAttributeList);
+ my $forEachArgument = IDLArgument->new();
+ $forEachArgument->name("callback");
+ $forEachArgument->type(makeSimpleType("any"));
+ push(@{$forEachFunction->arguments}, ($forEachArgument));
+
+ my $newDataNode = IDLIterable->new();
+ $newDataNode->extendedAttributes($extendedAttributeList);
+ push(@{$newDataNode->functions}, $symbolIteratorFunction);
+ push(@{$newDataNode->functions}, $entriesFunction);
+ push(@{$newDataNode->functions}, $keysFunction);
+ push(@{$newDataNode->functions}, $valuesFunction);
+ push(@{$newDataNode->functions}, $forEachFunction);
+
+ $self->assertTokenValue($self->getToken(), "<", __LINE__);
+ my $type1 = $self->parseType();
+
+ if ($self->nextToken()->value() eq ",") {
+ $self->assertTokenValue($self->getToken(), ",", __LINE__);
- my $next = $self->nextToken();
- if ($next->value() eq "=") {
- $self->assertTokenValue($self->getToken(), "=", __LINE__);
- $self->assertTokenType($self->getToken(), IdentifierToken);
+ my $type2 = $self->parseType();
+ $newDataNode->isKeyValue(1);
+ $newDataNode->keyType($type1);
+ $newDataNode->valueType($type2);
+ } else {
+ $newDataNode->isKeyValue(0);
+ $newDataNode->valueType($type1);
}
+ $self->assertTokenValue($self->getToken(), ">", __LINE__);
+
+ return $newDataNode;
}
sub parseOperationRest
@@ -1346,15 +1566,19 @@ sub parseOperationRest
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() eq "(") {
- my $newDataNode = domFunction->new();
- $newDataNode->signature(domSignature->new());
+ my $newDataNode = IDLOperation->new();
+
my $name = $self->parseOptionalIdentifier();
- $newDataNode->signature->name(identifierRemoveNullablePrefix($name));
+ $newDataNode->name(identifierRemoveNullablePrefix($name));
+
$self->assertTokenValue($self->getToken(), "(", $name, __LINE__);
- push(@{$newDataNode->parameters}, @{$self->parseArgumentList()});
+
+ push(@{$newDataNode->arguments}, @{$self->parseArgumentList()});
+
$self->assertTokenValue($self->getToken(), ")", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
- $newDataNode->signature->extendedAttributes($extendedAttributeList);
+
+ $newDataNode->extendedAttributes($extendedAttributeList);
return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
@@ -1406,10 +1630,8 @@ sub parseArgument
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextArgumentList_1/) {
- my $in = $self->parseIn();
my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
my $argument = $self->parseOptionalOrRequiredArgument($extendedAttributeList);
- $argument->direction($self->parseIn());
return $argument;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
@@ -1420,36 +1642,23 @@ sub parseOptionalOrRequiredArgument
my $self = shift;
my $extendedAttributeList = shift;
- my $paramDataNode = domSignature->new();
+ my $paramDataNode = IDLArgument->new();
$paramDataNode->extendedAttributes($extendedAttributeList);
my $next = $self->nextToken();
if ($next->value() eq "optional") {
$self->assertTokenValue($self->getToken(), "optional", __LINE__);
+
my $type = $self->parseType();
- # domDataNode can only consider last "?".
- if (typeHasNullableSuffix($type)) {
- $paramDataNode->isNullable(1);
- } else {
- $paramDataNode->isNullable(0);
- }
- # Remove all "?" if exists, e.g. "object?[]?" -> "object[]".
- $paramDataNode->type(identifierRemoveNullablePrefix(typeRemoveNullableSuffix($type)));
+ $paramDataNode->type($type);
$paramDataNode->isOptional(1);
$paramDataNode->name($self->parseArgumentName());
- $self->parseDefault();
+ $paramDataNode->default($self->parseDefault());
return $paramDataNode;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
my $type = $self->parseType();
- # domDataNode can only consider last "?".
- if (typeHasNullableSuffix($type)) {
- $paramDataNode->isNullable(1);
- } else {
- $paramDataNode->isNullable(0);
- }
- # Remove all "?" if exists, e.g. "object?[]?" -> "object[]".
- $paramDataNode->type(typeRemoveNullableSuffix($type));
+ $paramDataNode->type($type);
$paramDataNode->isOptional(0);
$paramDataNode->isVariadic($self->parseEllipsis());
$paramDataNode->name($self->parseArgumentName());
@@ -1504,16 +1713,17 @@ sub parseExceptionField
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
- my $newDataNode = domAttribute->new();
- $newDataNode->type("attribute");
+ my $newDataNode = IDLAttribute->new();
$newDataNode->isReadOnly(1);
- $newDataNode->signature(domSignature->new());
- $newDataNode->signature->type($self->parseType());
+
+ my $type = $self->parseType();
+ $newDataNode->type($type);
+
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
- $newDataNode->signature->name(identifierRemoveNullablePrefix($token->value()));
+ $newDataNode->name(identifierRemoveNullablePrefix($token->value()));
$self->assertTokenValue($self->getToken(), ";", __LINE__);
- $newDataNode->signature->extendedAttributes($extendedAttributeList);
+ $newDataNode->extendedAttributes($extendedAttributeList);
return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
@@ -1594,9 +1804,9 @@ sub parseExtendedAttribute
{
my $self = shift;
my $next = $self->nextToken();
- if ($next->type() == IdentifierToken || $next->value() eq "::") {
- my $scopedName = $self->parseScopedName();
- return $self->parseExtendedAttributeRest($scopedName);
+ if ($next->type() == IdentifierToken) {
+ my $name = $self->parseName();
+ return $self->parseExtendedAttributeRest($name);
}
# backward compatibility. Spec doesn' allow "[]". But WebKit requires.
if ($next->value() eq ']') {
@@ -1609,9 +1819,9 @@ sub parseExtendedAttribute2
{
my $self = shift;
my $next = $self->nextToken();
- if ($next->type() == IdentifierToken || $next->value() eq "::") {
- my $scopedName = $self->parseScopedName();
- return $self->parseExtendedAttributeRest($scopedName);
+ if ($next->type() == IdentifierToken) {
+ my $name = $self->parseName();
+ return $self->parseExtendedAttributeRest($name);
}
return {};
}
@@ -1647,9 +1857,15 @@ sub parseExtendedAttributeRest2
{
my $self = shift;
my $next = $self->nextToken();
- if ($next->type() == IdentifierToken || $next->value() eq "::") {
- my $scopedName = $self->parseScopedName();
- return $self->parseExtendedAttributeRest3($scopedName);
+ if ($next->value() eq "(") {
+ $self->assertTokenValue($self->getToken(), "(", __LINE__);
+ my @arguments = $self->parseIdentifierList();
+ $self->assertTokenValue($self->getToken(), ")", __LINE__);
+ return @arguments;
+ }
+ if ($next->type() == IdentifierToken) {
+ my $name = $self->parseName();
+ return $self->parseExtendedAttributeRest3($name);
}
if ($next->type() == IntegerToken) {
my $token = $self->getToken();
@@ -1666,12 +1882,12 @@ sub parseExtendedAttributeRest3
my $next = $self->nextToken();
if ($next->value() eq "&") {
$self->assertTokenValue($self->getToken(), "&", __LINE__);
- my $rightValue = $self->parseScopedName();
+ my $rightValue = $self->parseName();
return $name . "&" . $rightValue;
}
if ($next->value() eq "|") {
$self->assertTokenValue($self->getToken(), "|", __LINE__);
- my $rightValue = $self->parseScopedName();
+ my $rightValue = $self->parseName();
return $name . "|" . $rightValue;
}
if ($next->value() eq "(") {
@@ -1682,30 +1898,12 @@ sub parseExtendedAttributeRest3
return $attr;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExtendedAttributeRest3_1/) {
- my @names = ();
- push(@names, $name);
- push(@names, @{$self->parseScopedNameListNoComma()});
- return join(' ', @names);
+ $self->parseNameNoComma();
+ return $name;
}
$self->assertUnexpectedToken($next->value());
}
-sub parseScopedNameListNoComma
-{
- my $self = shift;
- my @names = ();
-
- while (1) {
- my $next = $self->nextToken();
- if ($next->type() == IdentifierToken || $next->value() eq "::") {
- push(@names, $self->parseScopedName());
- } else {
- last;
- }
- }
- return \@names;
-}
-
sub parseArgumentNameKeyword
{
my $self = shift;
@@ -1778,9 +1976,9 @@ sub parseType
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "(") {
- $self->parseUnionType();
- $self->parseTypeSuffix();
- return;
+ my $unionType = $self->parseUnionType();
+ $unionType->isNullable($self->parseNull());
+ return $unionType;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextType_1/) {
return $self->parseSingleType();
@@ -1794,10 +1992,15 @@ sub parseSingleType
my $next = $self->nextToken();
if ($next->value() eq "any") {
$self->assertTokenValue($self->getToken(), "any", __LINE__);
- return "any" . $self->parseTypeSuffixStartingWithArray();
+
+ my $anyType = IDLType->new();
+ $anyType->name("any");
+ return $anyType;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
- return $self->parseNonAnyType();
+ my $nonAnyType = $self->parseNonAnyType();
+ $nonAnyType->isNullable($self->parseNull());
+ return $nonAnyType;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -1806,14 +2009,20 @@ sub parseUnionType
{
my $self = shift;
my $next = $self->nextToken();
+
+ my $unionType = IDLType->new();
+ $unionType->name("UNION");
+ $unionType->isUnion(1);
+
if ($next->value() eq "(") {
$self->assertTokenValue($self->getToken(), "(", __LINE__);
- $self->parseUnionMemberType();
- $self->assertTokenValue($self->getToken(), "or", __LINE__);
- $self->parseUnionMemberType();
- $self->parseUnionMemberTypes();
+
+ push(@{$unionType->subtypes}, $self->parseUnionMemberType());
+ push(@{$unionType->subtypes}, $self->parseUnionMemberTypes());
+
$self->assertTokenValue($self->getToken(), ")", __LINE__);
- return;
+
+ return $unionType;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -1823,20 +2032,14 @@ sub parseUnionMemberType
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "(") {
- $self->parseUnionType();
- $self->parseTypeSuffix();
- return;
- }
- if ($next->value() eq "any") {
- $self->assertTokenValue($self->getToken(), "any", __LINE__);
- $self->assertTokenValue($self->getToken(), "[", __LINE__);
- $self->assertTokenValue($self->getToken(), "]", __LINE__);
- $self->parseTypeSuffix();
- return;
+ my $unionType = $self->parseUnionType();
+ $unionType->isNullable($self->parseNull());
+ return $unionType;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
- $self->parseNonAnyType();
- return;
+ my $nonAnyType = $self->parseNonAnyType();
+ $nonAnyType->isNullable($self->parseNull());
+ return $nonAnyType;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -1845,46 +2048,126 @@ sub parseUnionMemberTypes
{
my $self = shift;
my $next = $self->nextToken();
+
+ my @subtypes = ();
+
if ($next->value() eq "or") {
$self->assertTokenValue($self->getToken(), "or", __LINE__);
- $self->parseUnionMemberType();
- $self->parseUnionMemberTypes();
+ push(@subtypes, $self->parseUnionMemberType());
+ push(@subtypes, $self->parseUnionMemberTypes());
}
+
+ return @subtypes;
}
sub parseNonAnyType
{
my $self = shift;
my $next = $self->nextToken();
+
+ my $type = IDLType->new();
+
if ($next->value() =~ /$nextNonAnyType_1/) {
- return $self->parsePrimitiveType() . $self->parseTypeSuffix();
+ $type->name($self->parsePrimitiveType());
+ return $type;
}
- if ($next->value() eq "ByteString") {
- $self->assertTokenValue($self->getToken(), "ByteString", __LINE__);
- return "ByteString" . $self->parseTypeSuffix();
+ if ($next->value() =~ /$nextStringType_1/) {
+ $type->name($self->parseStringType());
+ return $type;
}
- if ($next->value() eq "DOMString") {
- $self->assertTokenValue($self->getToken(), "DOMString", __LINE__);
- return "DOMString" . $self->parseTypeSuffix();
+ if ($next->value() eq "object") {
+ $self->assertTokenValue($self->getToken(), "object", __LINE__);
+
+ $type->name("object");
+ return $type;
+ }
+ if ($next->value() eq "RegExp") {
+ $self->assertTokenValue($self->getToken(), "RegExp", __LINE__);
+
+ $type->name("RegExp");
+ return $type;
+ }
+ if ($next->value() eq "Error") {
+ $self->assertTokenValue($self->getToken(), "Error", __LINE__);
+
+ $type->name("Error");
+ return $type;
+ }
+ if ($next->value() eq "DOMException") {
+ $self->assertTokenValue($self->getToken(), "DOMException", __LINE__);
+
+ $type->name("DOMException");
+ return $type;
+ }
+ if ($next->value() eq "Date") {
+ $self->assertTokenValue($self->getToken(), "Date", __LINE__);
+
+ $type->name("Date");
+ return $type;
}
if ($next->value() eq "sequence") {
$self->assertTokenValue($self->getToken(), "sequence", __LINE__);
$self->assertTokenValue($self->getToken(), "<", __LINE__);
- my $type = $self->parseType();
+
+ my $subtype = $self->parseType();
+
$self->assertTokenValue($self->getToken(), ">", __LINE__);
- return "sequence<" . $type . ">" . $self->parseNull();
+
+ $type->name("sequence");
+ push(@{$type->subtypes}, $subtype);
+
+ return $type;
}
- if ($next->value() eq "object") {
- $self->assertTokenValue($self->getToken(), "object", __LINE__);
- return "object" . $self->parseTypeSuffix();
+ if ($next->value() eq "FrozenArray") {
+ $self->assertTokenValue($self->getToken(), "FrozenArray", __LINE__);
+ $self->assertTokenValue($self->getToken(), "<", __LINE__);
+
+ my $subtype = $self->parseType();
+
+ $self->assertTokenValue($self->getToken(), ">", __LINE__);
+
+ $type->name("FrozenArray");
+ push(@{$type->subtypes}, $subtype);
+
+ return $type;
}
- if ($next->value() eq "Date") {
- $self->assertTokenValue($self->getToken(), "Date", __LINE__);
- return "Date" . $self->parseTypeSuffix();
+ if ($next->value() eq "Promise") {
+ $self->assertTokenValue($self->getToken(), "Promise", __LINE__);
+ $self->assertTokenValue($self->getToken(), "<", __LINE__);
+
+ my $subtype = $self->parseReturnType();
+
+ $self->assertTokenValue($self->getToken(), ">", __LINE__);
+
+ $type->name("Promise");
+ push(@{$type->subtypes}, $subtype);
+
+ return $type;
}
- if ($next->type() == IdentifierToken || $next->value() eq "::") {
- my $name = identifierRemoveNullablePrefix($self->parseScopedName());
- return $name . $self->parseTypeSuffix();
+ if ($next->value() eq "record") {
+ $self->assertTokenValue($self->getToken(), "record", __LINE__);
+ $self->assertTokenValue($self->getToken(), "<", __LINE__);
+
+ my $keyType = IDLType->new();
+ $keyType->name($self->parseStringType());
+
+ $self->assertTokenValue($self->getToken(), ",", __LINE__);
+
+ my $valueType = $self->parseType();
+
+ $self->assertTokenValue($self->getToken(), ">", __LINE__);
+
+ $type->name("record");
+ push(@{$type->subtypes}, $keyType);
+ push(@{$type->subtypes}, $valueType);
+
+ return $type;
+ }
+ if ($next->type() == IdentifierToken) {
+ my $identifier = $self->getToken();
+
+ $type->name(identifierRemoveNullablePrefix($identifier->value()));
+ return $type;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -1893,12 +2176,40 @@ sub parseConstType
{
my $self = shift;
my $next = $self->nextToken();
+
+ my $type = IDLType->new();
+
if ($next->value() =~ /$nextNonAnyType_1/) {
- return $self->parsePrimitiveType() . $self->parseNull();
+ $type->name($self->parsePrimitiveType());
+ $type->isNullable($self->parseNull());
+ return $type;
}
if ($next->type() == IdentifierToken) {
- my $token = $self->getToken();
- return $token->value() . $self->parseNull();
+ my $identifier = $self->getToken();
+
+ $type->name($identifier->value());
+ $type->isNullable($self->parseNull());
+
+ return $type;
+ }
+ $self->assertUnexpectedToken($next->value(), __LINE__);
+}
+
+sub parseStringType
+{
+ my $self = shift;
+ my $next = $self->nextToken();
+ if ($next->value() eq "ByteString") {
+ $self->assertTokenValue($self->getToken(), "ByteString", __LINE__);
+ return "ByteString";
+ }
+ if ($next->value() eq "DOMString") {
+ $self->assertTokenValue($self->getToken(), "DOMString", __LINE__);
+ return "DOMString";
+ }
+ if ($next->value() eq "USVString") {
+ $self->assertTokenValue($self->getToken(), "USVString", __LINE__);
+ return "USVString";
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
@@ -2004,43 +2315,15 @@ sub parseOptionalLong
return 0;
}
-sub parseTypeSuffix
-{
- my $self = shift;
- my $next = $self->nextToken();
- if ($next->value() eq "[") {
- $self->assertTokenValue($self->getToken(), "[", __LINE__);
- $self->assertTokenValue($self->getToken(), "]", __LINE__);
- return "[]" . $self->parseTypeSuffix();
- }
- if ($next->value() eq "?") {
- $self->assertTokenValue($self->getToken(), "?", __LINE__);
- return "?" . $self->parseTypeSuffixStartingWithArray();
- }
- return "";
-}
-
-sub parseTypeSuffixStartingWithArray
-{
- my $self = shift;
- my $next = $self->nextToken();
- if ($next->value() eq "[") {
- $self->assertTokenValue($self->getToken(), "[", __LINE__);
- $self->assertTokenValue($self->getToken(), "]", __LINE__);
- return "[]" . $self->parseTypeSuffix();
- }
- return "";
-}
-
sub parseNull
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "?") {
$self->assertTokenValue($self->getToken(), "?", __LINE__);
- return "?";
+ return 1;
}
- return "";
+ return 0;
}
sub parseReturnType
@@ -2049,7 +2332,10 @@ sub parseReturnType
my $next = $self->nextToken();
if ($next->value() eq "void") {
$self->assertTokenValue($self->getToken(), "void", __LINE__);
- return "void";
+
+ my $voidType = IDLType->new();
+ $voidType->name("void");
+ return $voidType;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
return $self->parseType();
@@ -2057,17 +2343,6 @@ sub parseReturnType
$self->assertUnexpectedToken($next->value(), __LINE__);
}
-sub parseIn
-{
- my $self = shift;
- my $next = $self->nextToken();
- if ($next->value() eq "in") {
- $self->assertTokenValue($self->getToken(), "in", __LINE__);
- return "in";
- }
- return "";
-}
-
sub parseOptionalSemicolon
{
my $self = shift;
@@ -2077,115 +2352,72 @@ sub parseOptionalSemicolon
}
}
-sub parseScopedName
+sub parseNameNoComma
{
my $self = shift;
my $next = $self->nextToken();
- if ($next->value() eq "::") {
- return $self->parseAbsoluteScopedName();
- }
if ($next->type() == IdentifierToken) {
- return $self->parseRelativeScopedName();
+ my $identifier = $self->getToken();
+ return ($identifier->value());
}
- $self->assertUnexpectedToken($next->value());
-}
-sub parseAbsoluteScopedName
-{
- my $self = shift;
- my $next = $self->nextToken();
- if ($next->value() eq "::") {
- $self->assertTokenValue($self->getToken(), "::");
- my $token = $self->getToken();
- $self->assertTokenType($token, IdentifierToken);
- return "::" . $token->value() . $self->parseScopedNameParts();
- }
- $self->assertUnexpectedToken($next->value());
+ return ();
}
-sub parseRelativeScopedName
+sub parseName
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken) {
- my $token = $self->getToken();
- return $token->value() . $self->parseScopedNameParts();
+ my $identifier = $self->getToken();
+ return $identifier->value();
}
$self->assertUnexpectedToken($next->value());
}
-sub parseScopedNameParts
-{
- my $self = shift;
- my @names = ();
-
- while (1) {
- my $next = $self->nextToken();
- if ($next->value() eq "::") {
- $self->assertTokenValue($self->getToken(), "::");
- push(@names, "::");
- my $token = $self->getToken();
- $self->assertTokenType($token, IdentifierToken);
- push(@names, $token->value());
- } else {
- last;
- }
- }
- return join("", @names);
-}
-
-sub parseScopedNameList
-{
- my $self = shift;
- my $next = $self->nextToken();
- if ($next->type() == IdentifierToken || $next->value() eq "::") {
- my @names = ();
- push(@names, $self->parseScopedName());
- push(@names, @{$self->parseScopedNames()});
- return \@names;
- }
- $self->assertUnexpectedToken($next->value(), __LINE__);
-}
-
-sub parseScopedNames
-{
- my $self = shift;
- my @names = ();
-
- while (1) {
- my $next = $self->nextToken();
- if ($next->value() eq ",") {
- $self->assertTokenValue($self->getToken(), ",");
- push(@names, $self->parseScopedName());
- } else {
- last;
- }
- }
- return \@names;
-}
-
sub applyMemberList
{
my $interface = shift;
my $members = shift;
for my $item (@{$members}) {
- if (ref($item) eq "domAttribute") {
+ if (ref($item) eq "IDLAttribute") {
push(@{$interface->attributes}, $item);
next;
}
- if (ref($item) eq "domConstant") {
+ if (ref($item) eq "IDLConstant") {
push(@{$interface->constants}, $item);
next;
}
- if (ref($item) eq "domFunction") {
- if ($item->signature->name eq "") {
+ if (ref($item) eq "IDLIterable") {
+ $interface->iterable($item);
+ next;
+ }
+ if (ref($item) eq "IDLOperation") {
+ if ($item->name eq "") {
push(@{$interface->anonymousFunctions}, $item);
} else {
push(@{$interface->functions}, $item);
}
next;
}
+ if (ref($item) eq "IDLSerializable") {
+ $interface->serializable($item);
+ next;
+ }
+ }
+
+ if ($interface->serializable) {
+ my $numSerializerAttributes = @{$interface->serializable->attributes};
+ if ($interface->serializable->hasAttribute) {
+ foreach my $attribute (@{$interface->attributes}) {
+ push(@{$interface->serializable->attributes}, $attribute->name);
+ }
+ } elsif ($numSerializerAttributes == 0) {
+ foreach my $attribute (@{$interface->attributes}) {
+ push(@{$interface->serializable->attributes}, $attribute->name);
+ }
+ }
}
}
@@ -2198,25 +2430,22 @@ sub applyExtendedAttributeList
my @constructorParams = @{$extendedAttributeList->{"Constructors"}};
my $index = (@constructorParams == 1) ? 0 : 1;
foreach my $param (@constructorParams) {
- my $constructor = domFunction->new();
- $constructor->signature(domSignature->new());
- $constructor->signature->name("Constructor");
- $constructor->signature->extendedAttributes($extendedAttributeList);
- $constructor->parameters($param);
- $constructor->{overloadedIndex} = $index++;
+ my $constructor = IDLOperation->new();
+ $constructor->name("Constructor");
+ $constructor->extendedAttributes($extendedAttributeList);
+ $constructor->arguments($param);
push(@{$interface->constructors}, $constructor);
}
delete $extendedAttributeList->{"Constructors"};
$extendedAttributeList->{"Constructor"} = "VALUE_IS_MISSING";
} elsif (defined $extendedAttributeList->{"NamedConstructor"}) {
- my $newDataNode = domFunction->new();
- $newDataNode->signature(domSignature->new());
- $newDataNode->signature->name("NamedConstructor");
- $newDataNode->signature->extendedAttributes($extendedAttributeList);
+ my $newDataNode = IDLOperation->new();
+ $newDataNode->name("NamedConstructor");
+ $newDataNode->extendedAttributes($extendedAttributeList);
my %attributes = %{$extendedAttributeList->{"NamedConstructor"}};
my @attributeKeys = keys (%attributes);
my $constructorName = $attributeKeys[0];
- push(@{$newDataNode->parameters}, @{$attributes{$constructorName}});
+ push(@{$newDataNode->arguments}, @{$attributes{$constructorName}});
$extendedAttributeList->{"NamedConstructor"} = $constructorName;
push(@{$interface->constructors}, $newDataNode);
}
@@ -2224,12 +2453,10 @@ sub applyExtendedAttributeList
my @customConstructorParams = @{$extendedAttributeList->{"CustomConstructors"}};
my $index = (@customConstructorParams == 1) ? 0 : 1;
foreach my $param (@customConstructorParams) {
- my $customConstructor = domFunction->new();
- $customConstructor->signature(domSignature->new());
- $customConstructor->signature->name("CustomConstructor");
- $customConstructor->signature->extendedAttributes($extendedAttributeList);
- $customConstructor->parameters($param);
- $customConstructor->{overloadedIndex} = $index++;
+ my $customConstructor = IDLOperation->new();
+ $customConstructor->name("CustomConstructor");
+ $customConstructor->extendedAttributes($extendedAttributeList);
+ $customConstructor->arguments($param);
push(@{$interface->customConstructors}, $customConstructor);
}
delete $extendedAttributeList->{"CustomConstructors"};
diff --git a/Source/WebCore/bindings/scripts/InFilesCompiler.pm b/Source/WebCore/bindings/scripts/InFilesCompiler.pm
index 297568c97..0780d9456 100644
--- a/Source/WebCore/bindings/scripts/InFilesCompiler.pm
+++ b/Source/WebCore/bindings/scripts/InFilesCompiler.pm
@@ -14,7 +14,7 @@
# THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -37,7 +37,7 @@ require Config;
package InFilesCompiler;
-my $inputFile = "";
+my @inputFiles;
my $outputDir = ".";
my $defaultItemFactory;
@@ -82,11 +82,11 @@ sub new()
sub initializeFromCommandLine()
{
::GetOptions(
- 'input=s' => \$inputFile,
+ 'input=s' => \@inputFiles,
'outputDir=s' => \$outputDir,
);
- die "You must specify --input <file>" unless length($inputFile);
+ die "You must specify at least one --input <file>" unless scalar(@inputFiles);
::mkpath($outputDir);
@@ -99,14 +99,17 @@ sub compile()
my $object = shift;
my $generateCode = shift;
- my $file = new IO::File;
- open($file, $inputFile) or die "Failed to open file: $!";
-
my $InParser = InFilesParser->new();
- $InParser->parse($file, \&parameterHandler, \&itemHandler);
- close($file);
- die "Failed to read from file: $inputFile" if (keys %parsedItems == 0);
+ foreach my $inputFile (@inputFiles) {
+ my $file = new IO::File;
+ open($file, $inputFile) or die "Failed to open file: $!";
+
+ $InParser->parse($file, \&parameterHandler, \&itemHandler);
+
+ close($file);
+ die "Failed to read from file: $inputFile" if (keys %parsedItems == 0);
+ }
&$generateCode(\%parsedParameters, \%parsedItems);
}
@@ -130,7 +133,7 @@ sub license()
* THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
diff --git a/Source/WebCore/bindings/scripts/InFilesParser.pm b/Source/WebCore/bindings/scripts/InFilesParser.pm
index 65393807f..75db11999 100644
--- a/Source/WebCore/bindings/scripts/InFilesParser.pm
+++ b/Source/WebCore/bindings/scripts/InFilesParser.pm
@@ -11,10 +11,10 @@
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
-# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
diff --git a/Source/WebCore/bindings/scripts/StaticString.pm b/Source/WebCore/bindings/scripts/StaticString.pm
index b8feaa57e..9ba0c70a8 100644
--- a/Source/WebCore/bindings/scripts/StaticString.pm
+++ b/Source/WebCore/bindings/scripts/StaticString.pm
@@ -33,27 +33,26 @@ sub GenerateStrings($)
my @result = ();
- while ( my ($name, $value) = each %strings ) {
- push(@result, "static const LChar ${name}String8[] = \"${value}\";\n");
- }
-
- push(@result, "\n");
+ push(@result, <<END);
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4307)
+#endif
- while ( my ($name, $value) = each %strings ) {
- my $length = length($value);
- my $hash = Hasher::GenerateHashValue($value);
- push(@result, <<END);
-static StringImpl::StaticASCIILiteral ${name}Data = {
- StringImpl::StaticASCIILiteral::s_initialRefCount,
- $length,
- ${name}String8,
- 0,
- StringImpl::StaticASCIILiteral::s_initialFlags | (${hash} << StringImpl::StaticASCIILiteral::s_hashShift)
-};
END
+
+ for my $name (sort keys %strings) {
+ my $value = $strings{$name};
+ push(@result, "static StringImpl::StaticStringImpl ${name}Data(\"${value}\");\n");
}
- push(@result, "\n");
+ push(@result, <<END);
+
+#if COMPILER(MSVC)
+#pragma warning(pop)
+#endif
+
+END
return join "", @result;
}
@@ -67,7 +66,7 @@ sub GenerateStringAsserts($)
push(@result, "#ifndef NDEBUG\n");
- while ( my ($name, $value) = each %strings ) {
+ for my $name (sort keys %strings) {
push(@result, " reinterpret_cast<StringImpl*>(&${name}Data)->assertHashIsCorrect();\n");
}
diff --git a/Source/WebCore/bindings/scripts/generate-bindings-all.pl b/Source/WebCore/bindings/scripts/generate-bindings-all.pl
new file mode 100755
index 000000000..968ea113e
--- /dev/null
+++ b/Source/WebCore/bindings/scripts/generate-bindings-all.pl
@@ -0,0 +1,245 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2016 Sony Interactive Entertainment Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+use strict;
+use warnings;
+use FindBin;
+use lib $FindBin::Bin;
+
+use File::Basename;
+use File::Spec;
+use File::Find;
+use Getopt::Long;
+
+my $perl = $^X;
+my $scriptDir = $FindBin::Bin;
+my @idlDirectories;
+my $outputDirectory;
+my $idlFilesList;
+my $generator;
+my @generatorDependency;
+my $defines;
+my $preprocessor;
+my $supplementalDependencyFile;
+my @ppExtraOutput;
+my @ppExtraArgs;
+my $numOfJobs = 1;
+my $idlAttributesFile;
+my $showProgress;
+
+GetOptions('include=s@' => \@idlDirectories,
+ 'outputDir=s' => \$outputDirectory,
+ 'idlFilesList=s' => \$idlFilesList,
+ 'generator=s' => \$generator,
+ 'generatorDependency=s@' => \@generatorDependency,
+ 'defines=s' => \$defines,
+ 'preprocessor=s' => \$preprocessor,
+ 'supplementalDependencyFile=s' => \$supplementalDependencyFile,
+ 'ppExtraOutput=s@' => \@ppExtraOutput,
+ 'ppExtraArgs=s@' => \@ppExtraArgs,
+ 'idlAttributesFile=s' => \$idlAttributesFile,
+ 'numOfJobs=i' => \$numOfJobs,
+ 'showProgress' => \$showProgress);
+
+$| = 1;
+my @idlFiles;
+open(my $fh, '<', $idlFilesList) or die "Cannot open $idlFilesList";
+@idlFiles = map { CygwinPathIfNeeded(s/\r?\n?$//r) } <$fh>;
+close($fh) or die;
+
+my %oldSupplements;
+my %newSupplements;
+if ($supplementalDependencyFile) {
+ my @output = ($supplementalDependencyFile, @ppExtraOutput);
+ my @deps = ($idlFilesList, @idlFiles, @generatorDependency);
+ if (needsUpdate(\@output, \@deps)) {
+ readSupplementalDependencyFile($supplementalDependencyFile, \%oldSupplements) if -e $supplementalDependencyFile;
+ my @args = (File::Spec->catfile($scriptDir, 'preprocess-idls.pl'),
+ '--defines', $defines,
+ '--idlFilesList', $idlFilesList,
+ '--supplementalDependencyFile', $supplementalDependencyFile,
+ @ppExtraArgs);
+ printProgress("Preprocess IDL");
+ executeCommand($perl, @args) == 0 or die;
+ }
+ readSupplementalDependencyFile($supplementalDependencyFile, \%newSupplements);
+}
+
+my @args = (File::Spec->catfile($scriptDir, 'generate-bindings.pl'),
+ '--defines', $defines,
+ '--generator', $generator,
+ '--outputDir', $outputDirectory,
+ '--preprocessor', $preprocessor,
+ '--idlAttributesFile', $idlAttributesFile,
+ '--write-dependencies');
+push @args, map { ('--include', $_) } @idlDirectories;
+push @args, '--supplementalDependencyFile', $supplementalDependencyFile if $supplementalDependencyFile;
+
+my %directoryCache;
+buildDirectoryCache();
+
+my @idlFilesToUpdate = grep &{sub {
+ if (defined($oldSupplements{$_})
+ && @{$oldSupplements{$_}} ne @{$newSupplements{$_} or []}) {
+ # Re-process the IDL file if its supplemental dependencies were added or removed
+ return 1;
+ }
+ my ($filename, $dirs, $suffix) = fileparse($_, '.idl');
+ my $sourceFile = File::Spec->catfile($outputDirectory, "JS$filename.cpp");
+ my $headerFile = File::Spec->catfile($outputDirectory, "JS$filename.h");
+ my $depFile = File::Spec->catfile($outputDirectory, "JS$filename.dep");
+ my @output = ($sourceFile, $headerFile);
+ my @deps = ($_,
+ $idlAttributesFile,
+ @generatorDependency,
+ @{$newSupplements{$_} or []},
+ implicitDependencies($depFile));
+ needsUpdate(\@output, \@deps);
+}}, @idlFiles;
+
+my $abort = 0;
+my $totalCount = @idlFilesToUpdate;
+my $currentCount = 0;
+
+spawnGenerateBindingsIfNeeded() for (1 .. $numOfJobs);
+while (waitpid(-1, 0) != -1) {
+ if ($?) {
+ $abort = 1;
+ }
+ spawnGenerateBindingsIfNeeded();
+}
+exit $abort;
+
+sub needsUpdate
+{
+ my ($objects, $depends) = @_;
+ my $oldestObjectTime;
+ for (@$objects) {
+ return 1 if !-f;
+ my $m = mtime($_);
+ if (!defined $oldestObjectTime || $m < $oldestObjectTime) {
+ $oldestObjectTime = $m;
+ }
+ }
+ for (@$depends) {
+ die "Missing required dependency: $_" if !-f;
+ my $m = mtime($_);
+ if ($oldestObjectTime < $m) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub mtime
+{
+ my ($file) = @_;
+ return (stat $file)[9];
+}
+
+sub spawnGenerateBindingsIfNeeded
+{
+ return if $abort;
+ return unless @idlFilesToUpdate;
+ my $file = shift @idlFilesToUpdate;
+ $currentCount++;
+ my $basename = basename($file);
+ printProgress("[$currentCount/$totalCount] $basename");
+ my $pid = spawnCommand($perl, @args, $file);
+ $abort = 1 unless defined $pid;
+}
+
+sub buildDirectoryCache
+{
+ my $wanted = sub {
+ $directoryCache{$_} = $File::Find::name;
+ $File::Find::prune = 1 unless ~/\./;
+ };
+ find($wanted, @idlDirectories);
+}
+
+sub implicitDependencies
+{
+ my ($depFile) = @_;
+ return () unless -f $depFile;
+ open(my $fh, '<', $depFile) or die "Cannot open $depFile";
+ my $firstLine = <$fh>;
+ close($fh) or die;
+ my (undef, $deps) = split(/ : /, $firstLine);
+ my @deps = split(/\s+/, $deps);
+ return map { $directoryCache{$_} or () } @deps;
+}
+
+sub executeCommand
+{
+ if ($^O eq 'MSWin32') {
+ return system(quoteCommand(@_));
+ }
+ return system(@_);
+}
+
+sub spawnCommand
+{
+ my $pid = fork();
+ if ($pid == 0) {
+ @_ = quoteCommand(@_) if ($^O eq 'MSWin32');
+ exec(@_);
+ die "Cannot exec";
+ }
+ return $pid;
+}
+
+sub quoteCommand
+{
+ return map {
+ '"' . s/([\\\"])/\\$1/gr . '"';
+ } @_;
+}
+
+sub CygwinPathIfNeeded
+{
+ my $path = shift;
+ return Cygwin::win_to_posix_path($path) if ($^O eq 'cygwin');
+ return $path;
+}
+
+sub readSupplementalDependencyFile
+{
+ my $filename = shift;
+ my $supplements = shift;
+ open(my $fh, '<', $filename) or die "Cannot open $filename";
+ while (<$fh>) {
+ my ($idlFile, @followingIdlFiles) = split(/\s+/);
+ $supplements->{$idlFile} = [sort @followingIdlFiles];
+ }
+ close($fh) or die;
+}
+
+sub printProgress
+{
+ return unless $showProgress;
+ my $msg = shift;
+ print "$msg\n";
+}
diff --git a/Source/WebCore/bindings/scripts/generate-bindings.pl b/Source/WebCore/bindings/scripts/generate-bindings.pl
index f93434e40..1048a512e 100755
--- a/Source/WebCore/bindings/scripts/generate-bindings.pl
+++ b/Source/WebCore/bindings/scripts/generate-bindings.pl
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w
#
-# Copyright (C) 2005 Apple Computer, Inc.
+# Copyright (C) 2005 Apple Inc.
# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
#
# This file is part of WebKit
@@ -29,6 +29,8 @@
# <rdar://problems/4251781&4251785>
use strict;
+use FindBin;
+use lib '.', $FindBin::Bin;
use File::Path;
use File::Basename;
@@ -80,7 +82,7 @@ $targetIdlFile = Cwd::realpath($targetIdlFile);
if ($verbose) {
print "$generator: $targetIdlFile\n";
}
-my $targetInterfaceName = fileparse(basename($targetIdlFile), ".idl");
+my $targetInterfaceName = fileparse($targetIdlFile, ".idl");
my $idlFound = 0;
my @supplementedIdlFiles;
@@ -98,7 +100,7 @@ if ($supplementalDependencyFile) {
open FH, "< $supplementalDependencyFile" or die "Cannot open $supplementalDependencyFile\n";
while (my $line = <FH>) {
my ($idlFile, @followingIdlFiles) = split(/\s+/, $line);
- if ($idlFile and basename($idlFile) eq basename($targetIdlFile)) {
+ if ($idlFile and fileparse($idlFile) eq fileparse($targetIdlFile)) {
$idlFound = 1;
@supplementedIdlFiles = sort @followingIdlFiles;
}
@@ -110,11 +112,11 @@ if ($supplementalDependencyFile) {
# dependency file) but should generate .h and .cpp files.
if (!$idlFound and $additionalIdlFiles) {
my @idlFiles = shellwords($additionalIdlFiles);
- $idlFound = grep { $_ and basename($_) eq basename($targetIdlFile) } @idlFiles;
+ $idlFound = grep { $_ and fileparse($_) eq fileparse($targetIdlFile) } @idlFiles;
}
if (!$idlFound) {
- my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, $outputHeadersDirectory, 0, $preprocessor, $writeDependencies, $verbose);
+ my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, $outputHeadersDirectory, $preprocessor, $writeDependencies, $verbose);
# We generate empty .h and .cpp files just to tell build scripts that .h and .cpp files are created.
generateEmptyHeaderAndCpp($codeGen->FileNamePrefix(), $targetInterfaceName, $outputHeadersDirectory, $outputDirectory);
@@ -128,22 +130,26 @@ my $targetDocument = $targetParser->Parse($targetIdlFile, $defines, $preprocesso
if ($idlAttributesFile) {
my $idlAttributes = loadIDLAttributes($idlAttributesFile);
- checkIDLAttributes($idlAttributes, $targetDocument, basename($targetIdlFile));
+ checkIDLAttributes($idlAttributes, $targetDocument, fileparse($targetIdlFile));
}
foreach my $idlFile (@supplementedIdlFiles) {
next if $idlFile eq $targetIdlFile;
- my $interfaceName = fileparse(basename($idlFile), ".idl");
+ my $interfaceName = fileparse($idlFile, ".idl");
my $parser = IDLParser->new(!$verbose);
my $document = $parser->Parse($idlFile, $defines, $preprocessor);
foreach my $interface (@{$document->interfaces}) {
- if (!$interface->isPartial || $interface->name eq $targetInterfaceName) {
+ if (!$interface->isPartial || $interface->type->name eq $targetInterfaceName) {
my $targetDataNode;
+ my @targetGlobalContexts;
foreach my $interface (@{$targetDocument->interfaces}) {
- if ($interface->name eq $targetInterfaceName) {
+ if ($interface->type->name eq $targetInterfaceName) {
$targetDataNode = $interface;
+ my $exposedAttribute = $targetDataNode->extendedAttributes->{"Exposed"} || "Window";
+ $exposedAttribute = substr($exposedAttribute, 1, -1) if substr($exposedAttribute, 0, 1) eq "(";
+ @targetGlobalContexts = split(",", $exposedAttribute);
last;
}
}
@@ -151,30 +157,36 @@ foreach my $idlFile (@supplementedIdlFiles) {
# Support for attributes of partial interfaces.
foreach my $attribute (@{$interface->attributes}) {
+ next unless shouldPropertyBeExposed($attribute, \@targetGlobalContexts);
+
# Record that this attribute is implemented by $interfaceName.
- $attribute->signature->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial;
+ $attribute->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial;
# Add interface-wide extended attributes to each attribute.
foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) {
- $attribute->signature->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName};
+ $attribute->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName};
}
push(@{$targetDataNode->attributes}, $attribute);
}
# Support for methods of partial interfaces.
foreach my $function (@{$interface->functions}) {
+ next unless shouldPropertyBeExposed($function, \@targetGlobalContexts);
+
# Record that this method is implemented by $interfaceName.
- $function->signature->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial;
+ $function->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial;
# Add interface-wide extended attributes to each method.
foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) {
- $function->signature->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName};
+ $function->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName};
}
push(@{$targetDataNode->functions}, $function);
}
# Support for constants of partial interfaces.
foreach my $constant (@{$interface->constants}) {
+ next unless shouldPropertyBeExposed($constant, \@targetGlobalContexts);
+
# Record that this constant is implemented by $interfaceName.
$constant->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial;
@@ -191,9 +203,28 @@ foreach my $idlFile (@supplementedIdlFiles) {
}
# Generate desired output for the target IDL file.
-my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, $outputHeadersDirectory, 0, $preprocessor, $writeDependencies, $verbose, $targetIdlFile);
+my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, $outputHeadersDirectory, $preprocessor, $writeDependencies, $verbose, $targetIdlFile);
$codeGen->ProcessDocument($targetDocument, $defines);
+# Attributes / Operations / Constants of supplemental interfaces can have an [Exposed=XX] attribute which restricts
+# on which global contexts they should be exposed.
+sub shouldPropertyBeExposed
+{
+ my ($context, $targetGlobalContexts) = @_;
+
+ my $exposed = $context->extendedAttributes->{Exposed};
+
+ return 1 unless $exposed;
+
+ $exposed = substr($exposed, 1, -1) if substr($exposed, 0, 1) eq "(";
+ my @sourceGlobalContexts = split(",", $exposed);
+
+ for my $targetGlobalContext (@$targetGlobalContexts) {
+ return 1 if grep(/^$targetGlobalContext$/, @sourceGlobalContexts);
+ }
+ return 0;
+}
+
sub generateEmptyHeaderAndCpp
{
my ($prefix, $targetInterfaceName, $outputHeadersDirectory, $outputDirectory) = @_;
@@ -240,7 +271,7 @@ sub loadIDLAttributes
$idlAttributes{$name}{"VALUE_IS_MISSING"} = 1;
}
} else {
- die "The format of " . basename($idlAttributesFile) . " is wrong: line $.\n";
+ die "The format of " . fileparse($idlAttributesFile) . " is wrong: line $.\n";
}
}
close FH;
@@ -258,13 +289,13 @@ sub checkIDLAttributes
checkIfIDLAttributesExists($idlAttributes, $interface->extendedAttributes, $idlFile);
foreach my $attribute (@{$interface->attributes}) {
- checkIfIDLAttributesExists($idlAttributes, $attribute->signature->extendedAttributes, $idlFile);
+ checkIfIDLAttributesExists($idlAttributes, $attribute->extendedAttributes, $idlFile);
}
foreach my $function (@{$interface->functions}) {
- checkIfIDLAttributesExists($idlAttributes, $function->signature->extendedAttributes, $idlFile);
- foreach my $parameter (@{$function->parameters}) {
- checkIfIDLAttributesExists($idlAttributes, $parameter->extendedAttributes, $idlFile);
+ checkIfIDLAttributesExists($idlAttributes, $function->extendedAttributes, $idlFile);
+ foreach my $argument (@{$function->arguments}) {
+ checkIfIDLAttributesExists($idlAttributes, $argument->extendedAttributes, $idlFile);
}
}
}
diff --git a/Source/WebCore/bindings/scripts/gobject-generate-headers.pl b/Source/WebCore/bindings/scripts/gobject-generate-headers.pl
deleted file mode 100644
index b39cf253a..000000000
--- a/Source/WebCore/bindings/scripts/gobject-generate-headers.pl
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/perl -w
-#
-# Copyright (C) 2009 Adam Dingle <adam@yorba.org>
-#
-# This file is part of WebKit
-#
-# 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
-# aint with this library; see the file COPYING.LIB. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-# Boston, MA 02110-1301, USA.
-#
-
-my $classlist = <STDIN>;
-chomp($classlist);
-my @classes = split / /, $classlist;
-@classes = sort @classes;
-
-print <<EOF;
-/* This file is part of the WebKit open source project.
- This file has been generated by gobject-generate-headers.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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-EOF
-
-my $outType = $ARGV[0];
-my $header;
-if ($outType eq "defines") {
- $header = "webkitdomdefines_h";
-} elsif ($outType eq "gdom") {
- $header = "webkitdom_h";
-} else {
- die "unknown output type";
-}
-
-print "#ifndef ${header}\n";
-print "#define ${header}\n";
-print "\n";
-
-if ($outType eq "defines") {
- print "#include <glib.h>\n\n";
- print "#ifdef G_OS_WIN32\n";
- print " #ifdef BUILDING_WEBKIT\n";
- print " #define WEBKIT_API __declspec(dllexport)\n";
- print " #else\n";
- print " #define WEBKIT_API __declspec(dllimport)\n";
- print " #endif\n";
- print "#else\n";
- print " #define WEBKIT_API __attribute__((visibility(\"default\")))\n";
- print "#endif\n\n";
- print "#define WEBKIT_DEPRECATED WEBKIT_API G_DEPRECATED\n";
- print "#define WEBKIT_DEPRECATED_FOR(f) WEBKIT_API G_DEPRECATED_FOR(f)\n";
- print "\n";
- print "#ifndef WEBKIT_API\n";
- print " #define WEBKIT_API\n";
- print "#endif\n";
-
- foreach my $class (@classes) {
- if ($class ne "Deprecated" && $class ne "Custom") {
- print "typedef struct _WebKitDOM${class} WebKitDOM${class};\n";
- print "typedef struct _WebKitDOM${class}Class WebKitDOM${class}Class;\n";
- print "\n";
- }
- }
-} elsif ($outType eq "gdom") {
- print "#define __WEBKITDOM_H_INSIDE__\n\n";
- foreach my $class (@classes) {
- print "#include <webkitdom/WebKitDOM${class}.h>\n";
- }
- print "\n#undef __WEBKITDOM_H_INSIDE__\n";
-}
-
-print "\n";
-print "#endif\n";
diff --git a/Source/WebCore/bindings/scripts/preprocess-idls.pl b/Source/WebCore/bindings/scripts/preprocess-idls.pl
index d65df33cf..a984ab7c5 100644
--- a/Source/WebCore/bindings/scripts/preprocess-idls.pl
+++ b/Source/WebCore/bindings/scripts/preprocess-idls.pl
@@ -19,10 +19,13 @@
#
use strict;
+use FindBin;
+use lib $FindBin::Bin;
use File::Basename;
use Getopt::Long;
use Cwd;
+use Config;
my $defines;
my $preprocessor;
@@ -30,7 +33,6 @@ my $idlFilesList;
my $supplementalDependencyFile;
my $windowConstructorsFile;
my $workerGlobalScopeConstructorsFile;
-my $sharedWorkerGlobalScopeConstructorsFile;
my $dedicatedWorkerGlobalScopeConstructorsFile;
my $supplementalMakefileDeps;
@@ -40,7 +42,6 @@ GetOptions('defines=s' => \$defines,
'supplementalDependencyFile=s' => \$supplementalDependencyFile,
'windowConstructorsFile=s' => \$windowConstructorsFile,
'workerGlobalScopeConstructorsFile=s' => \$workerGlobalScopeConstructorsFile,
- 'sharedWorkerGlobalScopeConstructorsFile=s' => \$sharedWorkerGlobalScopeConstructorsFile,
'dedicatedWorkerGlobalScopeConstructorsFile=s' => \$dedicatedWorkerGlobalScopeConstructorsFile,
'supplementalMakefileDeps=s' => \$supplementalMakefileDeps);
@@ -48,13 +49,22 @@ die('Must specify #define macros using --defines.') unless defined($defines);
die('Must specify an output file using --supplementalDependencyFile.') unless defined($supplementalDependencyFile);
die('Must specify an output file using --windowConstructorsFile.') unless defined($windowConstructorsFile);
die('Must specify an output file using --workerGlobalScopeConstructorsFile.') unless defined($workerGlobalScopeConstructorsFile);
-die('Must specify an output file using --sharedWorkerGlobalScopeConstructorsFile.') unless defined($sharedWorkerGlobalScopeConstructorsFile);
die('Must specify an output file using --dedicatedWorkerGlobalScopeConstructorsFile.') unless defined($dedicatedWorkerGlobalScopeConstructorsFile);
die('Must specify the file listing all IDLs using --idlFilesList.') unless defined($idlFilesList);
+$supplementalDependencyFile = CygwinPathIfNeeded($supplementalDependencyFile);
+$windowConstructorsFile = CygwinPathIfNeeded($windowConstructorsFile);
+$workerGlobalScopeConstructorsFile = CygwinPathIfNeeded($workerGlobalScopeConstructorsFile);
+$dedicatedWorkerGlobalScopeConstructorsFile = CygwinPathIfNeeded($dedicatedWorkerGlobalScopeConstructorsFile);
+$supplementalMakefileDeps = CygwinPathIfNeeded($supplementalMakefileDeps);
+
open FH, "< $idlFilesList" or die "Cannot open $idlFilesList\n";
-my @idlFiles = <FH>;
-chomp(@idlFiles);
+my @idlFilesIn = <FH>;
+chomp(@idlFilesIn);
+my @idlFiles = ();
+foreach (@idlFilesIn) {
+ push @idlFiles, CygwinPathIfNeeded($_);
+}
close FH;
my %interfaceNameToIdlFile;
@@ -63,14 +73,13 @@ my %supplementalDependencies;
my %supplementals;
my $windowConstructorsCode = "";
my $workerGlobalScopeConstructorsCode = "";
-my $sharedWorkerGlobalScopeConstructorsCode = "";
my $dedicatedWorkerGlobalScopeConstructorsCode = "";
# Get rid of duplicates in idlFiles array.
my %idlFileHash = map { $_, 1 } @idlFiles;
# Populate $idlFileToInterfaceName and $interfaceNameToIdlFile.
-foreach my $idlFile (keys %idlFileHash) {
+foreach my $idlFile (sort keys %idlFileHash) {
my $fullPath = Cwd::realpath($idlFile);
my $interfaceName = fileparse(basename($idlFile), ".idl");
$idlFileToInterfaceName{$fullPath} = $interfaceName;
@@ -87,6 +96,13 @@ foreach my $idlFile (sort keys %idlFileHash) {
$supplementalDependencies{$fullPath} = [$partialInterfaceName];
next;
}
+
+ $supplementals{$fullPath} = [];
+
+ # Skip if the IDL file does not contain an interface, a callback interface or an exception.
+ # The IDL may contain a dictionary.
+ next unless containsInterfaceOrExceptionFromIDL($idlFileContents);
+
my $interfaceName = fileparse(basename($idlFile), ".idl");
# Handle implements statements.
my $implementedInterfaces = getImplementedInterfacesFromIDL($idlFileContents, $interfaceName);
@@ -99,29 +115,41 @@ foreach my $idlFile (sort keys %idlFileHash) {
$supplementalDependencies{$implementedIdlFile} = [$interfaceName];
}
}
- # Handle [NoInterfaceObject].
- unless (isCallbackInterfaceFromIDL($idlFileContents)) {
- my $extendedAttributes = getInterfaceExtendedAttributesFromIDL($idlFileContents);
- unless ($extendedAttributes->{"NoInterfaceObject"}) {
- my @globalContexts = split("&", $extendedAttributes->{"GlobalContext"} || "DOMWindow");
+
+ # For every interface that is exposed in a given ECMAScript global environment and:
+ # - is a callback interface that has constants declared on it, or
+ # - is a non-callback interface that is not declared with the [NoInterfaceObject] extended attribute, a corresponding
+ # property must exist on the ECMAScript environment's global object.
+ # See https://heycam.github.io/webidl/#es-interfaces
+ my $extendedAttributes = getInterfaceExtendedAttributesFromIDL($idlFileContents);
+ unless ($extendedAttributes->{"NoInterfaceObject"}) {
+ if (!isCallbackInterfaceFromIDL($idlFileContents) || interfaceHasConstantAttribute($idlFileContents)) {
+ my $exposedAttribute = $extendedAttributes->{"Exposed"} || "Window";
+ $exposedAttribute = substr($exposedAttribute, 1, -1) if substr($exposedAttribute, 0, 1) eq "(";
+ my @globalContexts = split(",", $exposedAttribute);
my $attributeCode = GenerateConstructorAttribute($interfaceName, $extendedAttributes);
- $windowConstructorsCode .= $attributeCode if grep(/^DOMWindow$/, @globalContexts);
- $workerGlobalScopeConstructorsCode .= $attributeCode if grep(/^WorkerGlobalScope$/, @globalContexts);
- $sharedWorkerGlobalScopeConstructorsCode .= $attributeCode if grep(/^SharedWorkerGlobalScope$/, @globalContexts);
- $dedicatedWorkerGlobalScopeConstructorsCode .= $attributeCode if grep(/^DedicatedWorkerGlobalScope$/, @globalContexts);
+ foreach my $globalContext (@globalContexts) {
+ if ($globalContext eq "Window") {
+ $windowConstructorsCode .= $attributeCode;
+ } elsif ($globalContext eq "Worker") {
+ $workerGlobalScopeConstructorsCode .= $attributeCode;
+ } elsif ($globalContext eq "DedicatedWorker") {
+ $dedicatedWorkerGlobalScopeConstructorsCode .= $attributeCode;
+ } else {
+ die "Unsupported global context '$globalContext' used in [Exposed] at $idlFile";
+ }
+ }
}
}
- $supplementals{$fullPath} = [];
}
# Generate partial interfaces for Constructors.
GeneratePartialInterface("DOMWindow", $windowConstructorsCode, $windowConstructorsFile);
GeneratePartialInterface("WorkerGlobalScope", $workerGlobalScopeConstructorsCode, $workerGlobalScopeConstructorsFile);
-GeneratePartialInterface("SharedWorkerGlobalScope", $sharedWorkerGlobalScopeConstructorsCode, $sharedWorkerGlobalScopeConstructorsFile);
GeneratePartialInterface("DedicatedWorkerGlobalScope", $dedicatedWorkerGlobalScopeConstructorsCode, $dedicatedWorkerGlobalScopeConstructorsFile);
# Resolves partial interfaces and implements dependencies.
-foreach my $idlFile (keys %supplementalDependencies) {
+foreach my $idlFile (sort keys %supplementalDependencies) {
my $baseFiles = $supplementalDependencies{$idlFile};
foreach my $baseFile (@{$baseFiles}) {
my $targetIdlFile = $interfaceNameToIdlFile{$baseFile};
@@ -165,6 +193,21 @@ if ($supplementalMakefileDeps) {
WriteFileIfChanged($supplementalMakefileDeps, $makefileDeps);
}
+my $cygwinPathAdded;
+sub CygwinPathIfNeeded
+{
+ my $path = shift;
+ if ($path && $Config{osname} eq "cygwin") {
+ if (not $cygwinPathAdded) {
+ $ENV{PATH} = "$ENV{PATH}:/cygdrive/c/cygwin/bin";
+ $cygwinPathAdded = 1;
+ }
+ chomp($path = `cygpath -u '$path'`);
+ $path =~ s/[\r\n]//;
+ }
+ return $path;
+}
+
sub WriteFileIfChanged
{
my $fileName = shift;
@@ -202,8 +245,8 @@ sub GenerateConstructorAttribute
my $code = " ";
my @extendedAttributesList;
- foreach my $attributeName (keys %{$extendedAttributes}) {
- next unless ($attributeName eq "Conditional" || $attributeName eq "EnabledAtRuntime" || $attributeName eq "EnabledBySetting");
+ foreach my $attributeName (sort keys %{$extendedAttributes}) {
+ next unless ($attributeName eq "Conditional" || $attributeName eq "EnabledAtRuntime" || $attributeName eq "EnabledForWorld" || $attributeName eq "EnabledBySetting" || $attributeName eq "PrivateIdentifier" || $attributeName eq "PublicIdentifier");
my $extendedAttribute = $attributeName;
$extendedAttribute .= "=" . $extendedAttributes->{$attributeName} unless $extendedAttributes->{$attributeName} eq "VALUE_IS_MISSING";
push(@extendedAttributesList, $extendedAttribute);
@@ -270,6 +313,16 @@ sub isCallbackInterfaceFromIDL
return ($fileContents =~ /callback\s+interface\s+\w+/gs);
}
+sub containsInterfaceOrExceptionFromIDL
+{
+ my $fileContents = shift;
+
+ return 1 if $fileContents =~ /\bcallback\s+interface\s+\w+/gs;
+ return 1 if $fileContents =~ /\binterface\s+\w+/gs;
+ return 1 if $fileContents =~ /\bexception\s+\w+/gs;
+ return 0;
+}
+
sub trim
{
my $string = shift;
@@ -283,8 +336,13 @@ sub getInterfaceExtendedAttributesFromIDL
my $extendedAttributes = {};
- if ($fileContents =~ /\[(.*)\]\s+(interface|exception)\s+(\w+)/gs) {
- my @parts = split(',', $1);
+ # Remove comments from fileContents before processing.
+ # FIX: Preference to use Regex::Common::comment, however it is not available on
+ # all build systems.
+ $fileContents =~ s/(?:(?:(?:\/\/)(?:[^\n]*)(?:\n))|(?:(?:\/\*)(?:(?:[^\*]+|\*(?!\/))*)(?:\*\/)))//g;
+
+ if ($fileContents =~ /\[(.*)\]\s+(callback interface|interface|exception)\s+(\w+)/gs) {
+ my @parts = split(m/,(?![^()]*\))/, $1);
foreach my $part (@parts) {
my @keyValue = split('=', $part);
my $key = trim($keyValue[0]);
@@ -297,3 +355,10 @@ sub getInterfaceExtendedAttributesFromIDL
return $extendedAttributes;
}
+
+sub interfaceHasConstantAttribute
+{
+ my $fileContents = shift;
+
+ return $fileContents =~ /\s+const[\s\w]+=\s+[\w]+;/gs;
+}
diff --git a/Source/WebCore/bindings/scripts/preprocessor.pm b/Source/WebCore/bindings/scripts/preprocessor.pm
index d92590d77..2321d5191 100644
--- a/Source/WebCore/bindings/scripts/preprocessor.pm
+++ b/Source/WebCore/bindings/scripts/preprocessor.pm
@@ -51,18 +51,20 @@ sub applyPreprocessor
$preprocessor = "/usr/sfw/bin/gcc";
} elsif (-x "/usr/bin/clang") {
$preprocessor = "/usr/bin/clang";
- } elsif ($Config{osname} eq 'msys') {
- $preprocessor = "gcc";
} else {
$preprocessor = "/usr/bin/gcc";
}
- push(@args, qw(-E -P -x c++));
+ if ($Config::Config{"osname"} eq "MSWin32") {
+ push(@args, qw(/EP));
+ } else {
+ push(@args, qw(-E -P -x c++));
+ }
}
if ($Config::Config{"osname"} eq "darwin") {
push(@args, "-I" . $ENV{BUILT_PRODUCTS_DIR} . "/usr/local/include") if $ENV{BUILT_PRODUCTS_DIR};
push(@args, "-isysroot", $ENV{SDKROOT}) if $ENV{SDKROOT};
- $defines .= " WTF_PLATFORM_IOS" if defined $ENV{PLATFORM_NAME} && $ENV{PLATFORM_NAME} =~ /iphone(os|simulator)/;
+ $defines .= " WTF_PLATFORM_IOS" if defined $ENV{PLATFORM_NAME} && $ENV{PLATFORM_NAME} !~ /macosx/;
}
# Remove double quotations from $defines and extract macros.
@@ -73,19 +75,34 @@ sub applyPreprocessor
@macros = map { "-D$_" } @macros;
my $pid = 0;
- if ($Config{osname} eq "cygwin" || $Config{osname} eq 'MSWin32' || $Config{osname} eq 'msys') {
+ if ($Config{osname} eq "cygwin") {
+ $ENV{PATH} = "$ENV{PATH}:/cygdrive/c/cygwin/bin";
+ my @preprocessorAndFlags;
+ if ($preprocessor eq "/usr/bin/gcc") {
+ @preprocessorAndFlags = split(' ', $preprocessor);
+ } else {
+ $preprocessor =~ /"(.*)"/;
+ chomp(my $preprocessor = `cygpath -u '$1'`) if (defined $1);
+ chomp($fileName = `cygpath -w '$fileName'`);
+ @preprocessorAndFlags = ($preprocessor, "/nologo", "/EP");
+ }
# This call can fail if Windows rebases cygwin, so retry a few times until it succeeds.
for (my $tries = 0; !$pid && ($tries < 20); $tries++) {
eval {
# Suppress STDERR so that if we're using cl.exe, the output
# name isn't needlessly echoed.
use Symbol 'gensym'; my $err = gensym;
- $pid = open3(\*PP_IN, \*PP_OUT, $err, split(' ', $preprocessor), @args, @macros, $fileName);
+ $pid = open3(\*PP_IN, \*PP_OUT, $err, @preprocessorAndFlags, @args, @macros, $fileName);
1;
} or do {
sleep 1;
}
};
+ } elsif ($Config::Config{"osname"} eq "MSWin32") {
+ # Suppress STDERR so that if we're using cl.exe, the output
+ # name isn't needlessly echoed.
+ use Symbol 'gensym'; my $err = gensym;
+ $pid = open3(\*PP_IN, \*PP_OUT, $err, $preprocessor, @args, @macros, $fileName);
} else {
$pid = open2(\*PP_OUT, \*PP_IN, split(' ', $preprocessor), @args, @macros, $fileName);
}