Changeset 57653 in webkit


Ignore:
Timestamp:
Apr 15, 2010 10:33:34 AM (14 years ago)
Author:
eric@webkit.org
Message:

2010-04-15 Yaar Schnitman <yaar@chromium.org>

Reviewed by Nate Chapin.

Overloads auto-generation in V8
https://bugs.webkit.org/show_bug.cgi?id=37373

This will be used by XHR.send/open, Canvas.*, WebGL.* methods that are currently custom. When more than a single overload exists for a method, the correct overload is chosen based on the total number of arguments passed as well as the values passed to non-primitive arguments.

Overload dispatch order depends on the order the functions are defined in the IDL. Overloads must be specified from the most precise (overloads with wrapper type arguments) to the least precise (overloads with only primitive type arguments).

  • bindings/scripts/CodeGeneratorV8.pm: Identify and output overloads callbacks and dispatch code.
  • bindings/v8/test/TestObj.idl: Overloads sample.
  • bindings/v8/test/V8TestObj.cpp: Output change.
Location:
trunk/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r57652 r57653  
     12010-04-15  Yaar Schnitman  <yaar@chromium.org>
     2
     3        Reviewed by Nate Chapin.
     4
     5        Overloads auto-generation in V8
     6        https://bugs.webkit.org/show_bug.cgi?id=37373
     7
     8        This will be used by XHR.send/open, Canvas.*, WebGL.* methods that are currently custom. When more than a single overload exists for a method, the correct overload is chosen based on the total number of arguments passed as well as the values passed to non-primitive arguments.
     9
     10        Overload dispatch order depends on the order the functions are defined in the IDL. Overloads must be specified from the most precise (overloads with wrapper type arguments) to the least precise (overloads with only primitive type arguments).
     11
     12        * bindings/scripts/CodeGeneratorV8.pm: Identify and output overloads callbacks and dispatch code.
     13        * bindings/v8/test/TestObj.idl: Overloads sample.
     14        * bindings/v8/test/V8TestObj.cpp: Output change.
     15
    1162010-04-15  Ben Murdoch  <benm@google.com>
    217
  • trunk/WebCore/bindings/scripts/CodeGeneratorV8.pm

    r57505 r57653  
    194194        return "";
    195195    }
     196}
     197
     198sub LinkOverloadedFunctions
     199{
     200    my $dataNode = shift;
     201
     202    # Identifies overloaded functions and for each function adds an array with
     203    # links to its respective overloads (including itself).
     204    my %nameToFunctionsMap = ();
     205    foreach my $function (@{$dataNode->functions}) {
     206        my $name = $function->signature->name;
     207        $nameToFunctionsMap{$name} = [] if !exists $nameToFunctionsMap{$name};
     208        push(@{$nameToFunctionsMap{$name}}, $function);
     209        $function->{overloads} = $nameToFunctionsMap{$name};
     210        $function->{overloadIndex} = @{$nameToFunctionsMap{$name}};
     211    }
     212
    196213}
    197214
     
    10021019}
    10031020
    1004 sub GenerateFunctionCallback
     1021sub GenerateParametersCheckExpression
     1022{
     1023    my $numParameters = shift;
     1024    my $function = shift;
     1025
     1026    my @andExpression = ();
     1027    push(@andExpression, "args.Length() == $numParameters");
     1028    my $parameterIndex = 0;
     1029    foreach $parameter (@{$function->parameters}) {
     1030        last if $parameterIndex >= $numParameters;
     1031        my $value = "args[$parameterIndex]";
     1032        my $type = GetTypeFromSignature($parameter);
     1033
     1034        # Only DOMString or wrapper types are checked.
     1035        # For DOMString, Null or Undefined are accepted too, as these are
     1036        # usually acceptable values for a DOMString argument.
     1037        push(@andExpression, "(${value}.IsNull() || ${value}.IsUndefined() || ${value}.IsString())") if $codeGenerator->IsStringType($type);
     1038        push(@andExpression, "V8${type}::HasInstance($value)") if IsWrapperType($type);
     1039
     1040        $parameterIndex++;
     1041    }
     1042    my $res = join(" && ", @andExpression);
     1043    $res = "($res)" if @andExpression > 1;
     1044    return $res;
     1045}
     1046
     1047sub GenerateFunctionParametersCheck
     1048{
     1049    my $function = shift;
     1050
     1051    my @orExpression = ();
     1052    my $numParameters = 0;
     1053    foreach $parameter (@{$function->parameters}) {
     1054        if ($parameter->extendedAttributes->{"Optional"}) {
     1055            push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
     1056        }
     1057        $numParameters++;
     1058    }
     1059    push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
     1060    return join(" || ", @orExpression);
     1061}
     1062
     1063sub GenerateOverloadedFunctionCallback
    10051064{
    10061065    my $function = shift;
     
    10081067    my $implClassName = shift;
    10091068
     1069    # Generate code for choosing the correct overload to call. Overloads are
     1070    # chosen based on the total number of arguments passed and the type of
     1071    # values passed in non-primitive argument slots. When more than a single
     1072    # overload is applicable, precedence is given according to the order of
     1073    # declaration in the IDL.
     1074
     1075    my $name = $function->signature->name;
     1076    push(@implContentDecls, <<END);
     1077static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) {
     1078    INC_STATS(\"DOM.$implClassName.$name\");
     1079END
     1080    foreach my $overload (@{$function->{overloads}}) {
     1081        my $parametersCheck = GenerateFunctionParametersCheck($overload);
     1082        if ($overload->{overloadIndex} == 1) {
     1083            push(@implContentDecls, "    if ($parametersCheck) {\n");
     1084        } else {
     1085            push(@implContentDecls, "    } else if ($parametersCheck) {\n");
     1086        }
     1087        push(@implContentDecls, "        return ${name}$overload->{overloadIndex}Callback(args);\n");
     1088    }
     1089    push(@implContentDecls, <<END);
     1090    } else {
     1091        V8Proxy::setDOMException(SYNTAX_ERR);
     1092        return notHandledByInterceptor();
     1093    }
     1094END
     1095    push(@implContentDecls, "}\n\n");
     1096}
     1097
     1098sub GenerateFunctionCallback
     1099{
     1100    my $function = shift;
     1101    my $dataNode = shift;
     1102    my $implClassName = shift;
     1103
    10101104    my $interfaceName = $dataNode->name;
    10111105    my $name = $function->signature->name;
     1106
     1107    if (@{$function->{overloads}} > 1) {
     1108        # Append a number to an overloaded method's name to make it unique:
     1109        $name = $name . $function->{overloadIndex};
     1110    }
    10121111
    10131112    # Adding and removing event listeners are not standard callback behavior,
     
    10441143    }
    10451144
    1046   # Check domain security if needed
     1145    # Check domain security if needed
    10471146    if (($dataNode->extendedAttributes->{"CheckDomainSecurity"}
    10481147       || $interfaceName eq "DOMWindow")
     
    15621661    }
    15631662
     1663    LinkOverloadedFunctions($dataNode);
     1664
    15641665    my $indexer;
    15651666    my $namedPropertyGetter;
     
    15681669        if (!($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"})) {
    15691670            GenerateFunctionCallback($function, $dataNode, $implClassName);
     1671            if ($function->{overloadIndex} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) {
     1672                GenerateOverloadedFunctionCallback($function, $dataNode, $implClassName);
     1673            }
    15701674        }
    15711675
     
    16251729    $has_callbacks = 0;
    16261730    foreach my $function (@{$dataNode->functions}) {
     1731        # Only one table entry is needed for overloaded methods:
     1732        next if $function->{overloadIndex} > 1;
     1733
    16271734        my $attrExt = $function->signature->extendedAttributes;
    16281735        # Don't put any nonstandard functions into this table:
     
    17861893    $total_functions = 0;
    17871894    foreach my $function (@{$dataNode->functions}) {
     1895        # Only one accessor is needed for overloaded methods:
     1896        next if $function->{overloadIndex} > 1;
     1897
    17881898        $total_functions++;
    17891899        my $attrExt = $function->signature->extendedAttributes;
  • trunk/WebCore/bindings/v8/test/TestObj.idl

    r57378 r57653  
    6262        void    methodWithNonOptionalArgAndOptionalArg(in long nonOpt, in [Optional] long opt);
    6363        void    methodWithNonOptionalArgAndTwoOptionalArgs(in long nonOpt, in [Optional] long opt1, in long opt2);
     64
     65        // Overloads
     66        void    overloadedMethod(in TestObj objArg, in DOMString strArg);
     67        void    overloadedMethod(in TestObj objArg, in [Optional] long intArg);
     68        void    overloadedMethod(in DOMString strArg);
     69        void    overloadedMethod(in long intArg);
    6470    };
    6571}
  • trunk/WebCore/bindings/v8/test/V8TestObj.cpp

    r57378 r57653  
    264264    imp->methodWithNonOptionalArgAndTwoOptionalArgs(nonOpt, opt1, opt2);
    265265    return v8::Handle<v8::Value>();
     266}
     267
     268static v8::Handle<v8::Value> overloadedMethod1Callback(const v8::Arguments& args) {
     269    INC_STATS("DOM.TestObj.overloadedMethod1");
     270    TestObj* imp = V8TestObj::toNative(args.Holder());
     271    TestObj* objArg = V8TestObj::HasInstance(args[0]) ? V8TestObj::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
     272    V8Parameter<> strArg = args[1];
     273    imp->overloadedMethod(objArg, strArg);
     274    return v8::Handle<v8::Value>();
     275}
     276
     277static v8::Handle<v8::Value> overloadedMethod2Callback(const v8::Arguments& args) {
     278    INC_STATS("DOM.TestObj.overloadedMethod2");
     279    TestObj* imp = V8TestObj::toNative(args.Holder());
     280    TestObj* objArg = V8TestObj::HasInstance(args[0]) ? V8TestObj::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
     281    if (args.Length() <= 1) {
     282        imp->overloadedMethod(objArg);
     283        return v8::Handle<v8::Value>();
     284    }
     285    int intArg = toInt32(args[1]);
     286    imp->overloadedMethod(objArg, intArg);
     287    return v8::Handle<v8::Value>();
     288}
     289
     290static v8::Handle<v8::Value> overloadedMethod3Callback(const v8::Arguments& args) {
     291    INC_STATS("DOM.TestObj.overloadedMethod3");
     292    TestObj* imp = V8TestObj::toNative(args.Holder());
     293    V8Parameter<> strArg = args[0];
     294    imp->overloadedMethod(strArg);
     295    return v8::Handle<v8::Value>();
     296}
     297
     298static v8::Handle<v8::Value> overloadedMethod4Callback(const v8::Arguments& args) {
     299    INC_STATS("DOM.TestObj.overloadedMethod4");
     300    TestObj* imp = V8TestObj::toNative(args.Holder());
     301    int intArg = toInt32(args[0]);
     302    imp->overloadedMethod(intArg);
     303    return v8::Handle<v8::Value>();
     304}
     305
     306static v8::Handle<v8::Value> overloadedMethodCallback(const v8::Arguments& args) {
     307    INC_STATS("DOM.TestObj.overloadedMethod");
     308    if ((args.Length() == 2 && V8TestObj::HasInstance(args[0]) && (args[1].IsNull() || args[1].IsUndefined() || args[1].IsString()))) {
     309        return overloadedMethod1Callback(args);
     310    } else if ((args.Length() == 1 && V8TestObj::HasInstance(args[0])) || (args.Length() == 2 && V8TestObj::HasInstance(args[0]))) {
     311        return overloadedMethod2Callback(args);
     312    } else if ((args.Length() == 1 && (args[0].IsNull() || args[0].IsUndefined() || args[0].IsString()))) {
     313        return overloadedMethod3Callback(args);
     314    } else if (args.Length() == 1) {
     315        return overloadedMethod4Callback(args);
     316    } else {
     317        V8Proxy::setDOMException(SYNTAX_ERR);
     318        return notHandledByInterceptor();
     319    }
    266320}
    267321
     
    408462    proto->Set(v8::String::New("objMethodWithArgs"), v8::FunctionTemplate::New(TestObjInternal::objMethodWithArgsCallback, v8::Handle<v8::Value>(), objMethodWithArgs_signature));
    409463
     464    // Custom Signature 'overloadedMethod'
     465    const int overloadedMethod_argc = 2;
     466    v8::Handle<v8::FunctionTemplate> overloadedMethod_argv[overloadedMethod_argc] = { V8TestObj::GetRawTemplate(), v8::Handle<v8::FunctionTemplate>() };
     467    v8::Handle<v8::Signature> overloadedMethod_signature = v8::Signature::New(desc, overloadedMethod_argc, overloadedMethod_argv);
     468    proto->Set(v8::String::New("overloadedMethod"), v8::FunctionTemplate::New(TestObjInternal::overloadedMethodCallback, v8::Handle<v8::Value>(), overloadedMethod_signature));
     469
    410470    // Custom toString template
    411471    desc->Set(getToStringName(), getToStringTemplate());
Note: See TracChangeset for help on using the changeset viewer.