Changeset 189946 in webkit


Ignore:
Timestamp:
Sep 17, 2015 5:03:49 PM (9 years ago)
Author:
commit-queue@webkit.org
Message:

Convert return values from JavaScript functions to the expected types in WebAssembly
https://bugs.webkit.org/show_bug.cgi?id=149200

Patch by Sukolsak Sakshuwong <Sukolsak Sakshuwong> on 2015-09-17
Reviewed by Mark Lam.

When a WebAssembly function calls a JavaScript function, there is no
guarantee that the JavaScript function will always return values of the
type we expect. This patch converts the return values to the expected
types.

(The reverse is also true: When a WebAssembly function is called from a
JavaScript function, there is no guarantee that the arguments to the
WebAssembly function will always be of the types we expect. We have
fixed this in Bug 149033.)

We don't need to type check the return values if the callee is a
WebAssembly function. We don't need to type check the arguments if the
caller is a WebAssembly function. This optimization will be
implemented in the future. See https://bugs.webkit.org/show_bug.cgi?id=149310

  • tests/stress/wasm-type-conversion.js:
  • tests/stress/wasm/type-conversion.wasm:
  • wasm/WASMFunctionCompiler.h:

(JSC::WASMFunctionCompiler::startFunction):
(JSC::WASMFunctionCompiler::buildReturn):
(JSC::WASMFunctionCompiler::boxArgumentsAndAdjustStackPointer):
(JSC::WASMFunctionCompiler::callAndUnboxResult):
(JSC::WASMFunctionCompiler::convertValueToInt32):
(JSC::WASMFunctionCompiler::convertValueToDouble):
(JSC::WASMFunctionCompiler::convertDoubleToValue):
(JSC::WASMFunctionCompiler::loadValueAndConvertToInt32): Deleted.
(JSC::WASMFunctionCompiler::loadValueAndConvertToDouble): Deleted.

  • wasm/WASMFunctionParser.cpp:

(JSC::WASMFunctionParser::parseExpressionI32):
(JSC::WASMFunctionParser::parseExpressionF32):
(JSC::WASMFunctionParser::parseExpressionF64):
(JSC::WASMFunctionParser::parseCallInternalExpressionI32): Deleted.

  • wasm/WASMFunctionParser.h:
Location:
trunk/Source/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r189941 r189946  
     12015-09-17  Sukolsak Sakshuwong  <sukolsak@gmail.com>
     2
     3        Convert return values from JavaScript functions to the expected types in WebAssembly
     4        https://bugs.webkit.org/show_bug.cgi?id=149200
     5
     6        Reviewed by Mark Lam.
     7
     8        When a WebAssembly function calls a JavaScript function, there is no
     9        guarantee that the JavaScript function will always return values of the
     10        type we expect. This patch converts the return values to the expected
     11        types.
     12
     13        (The reverse is also true: When a WebAssembly function is called from a
     14        JavaScript function, there is no guarantee that the arguments to the
     15        WebAssembly function will always be of the types we expect. We have
     16        fixed this in Bug 149033.)
     17
     18        We don't need to type check the return values if the callee is a
     19        WebAssembly function. We don't need to type check the arguments if the
     20        caller is a WebAssembly function. This optimization will be
     21        implemented in the future. See https://bugs.webkit.org/show_bug.cgi?id=149310
     22
     23        * tests/stress/wasm-type-conversion.js:
     24        * tests/stress/wasm/type-conversion.wasm:
     25        * wasm/WASMFunctionCompiler.h:
     26        (JSC::WASMFunctionCompiler::startFunction):
     27        (JSC::WASMFunctionCompiler::buildReturn):
     28        (JSC::WASMFunctionCompiler::boxArgumentsAndAdjustStackPointer):
     29        (JSC::WASMFunctionCompiler::callAndUnboxResult):
     30        (JSC::WASMFunctionCompiler::convertValueToInt32):
     31        (JSC::WASMFunctionCompiler::convertValueToDouble):
     32        (JSC::WASMFunctionCompiler::convertDoubleToValue):
     33        (JSC::WASMFunctionCompiler::loadValueAndConvertToInt32): Deleted.
     34        (JSC::WASMFunctionCompiler::loadValueAndConvertToDouble): Deleted.
     35        * wasm/WASMFunctionParser.cpp:
     36        (JSC::WASMFunctionParser::parseExpressionI32):
     37        (JSC::WASMFunctionParser::parseExpressionF32):
     38        (JSC::WASMFunctionParser::parseExpressionF64):
     39        (JSC::WASMFunctionParser::parseCallInternalExpressionI32): Deleted.
     40        * wasm/WASMFunctionParser.h:
     41
    1422015-09-17  Yusuke Suzuki  <utatane.tea@gmail.com>
    243
  • trunk/Source/JavaScriptCore/tests/stress/wasm-type-conversion.js

    r189624 r189946  
    99wasm/type-conversion.wasm is generated by pack-asmjs <https://github.com/WebAssembly/polyfill-prototype-1> from the following script:
    1010
    11 function asmModule(global, env, buffer) {
     11function asmModule(global, imports, buffer) {
    1212    "use asm";
    1313
    1414    var fround = global.Math.fround;
     15    var getInt32 = imports.getInt32;
     16    var getDouble = imports.getDouble;
     17    var getString = imports.getString;
     18    var getBoolean = imports.getBoolean;
    1519
    1620    function takeAndReturnInt32(x) {
    1721        x = x | 0;
    18         return x;
     22        return x | 0;
    1923    }
    2024
     
    2933    }
    3034
     35    function returnInt32FromInt32() {
     36        return getInt32() | 0;
     37    }
     38
     39    function returnInt32FromDouble() {
     40        return getDouble() | 0;
     41    }
     42
     43    function returnInt32FromString() {
     44        return getString() | 0;
     45    }
     46
     47    function returnInt32FromBoolean() {
     48        return getBoolean() | 0;
     49    }
     50
     51    function returnDoubleFromInt32() {
     52        return +getInt32();
     53    }
     54
     55    function returnDoubleFromDouble() {
     56        return +getDouble();
     57    }
     58
     59    function returnDoubleFromString() {
     60        return +getString();
     61    }
     62
     63    function returnDoubleFromBoolean() {
     64        return +getBoolean();
     65    }
     66
    3167    return {
    3268        takeAndReturnInt32: takeAndReturnInt32,
     69        takeAndReturnFloat: takeAndReturnFloat,
    3370        takeAndReturnDouble: takeAndReturnDouble,
     71
     72        returnInt32FromInt32: returnInt32FromInt32,
     73        returnInt32FromDouble: returnInt32FromDouble,
     74        returnInt32FromString: returnInt32FromString,
     75        returnInt32FromBoolean: returnInt32FromBoolean,
     76        returnDoubleFromInt32: returnDoubleFromInt32,
     77        returnDoubleFromDouble: returnDoubleFromDouble,
     78        returnDoubleFromString: returnDoubleFromString,
     79        returnDoubleFromBoolean: returnDoubleFromBoolean,
    3480    };
    3581}
    3682*/
    3783
    38 var module = loadWebAssembly("wasm/type-conversion.wasm");
     84var imports = {
     85    getInt32: () => 42,
     86    getDouble: () => 4.2,
     87    getString: () => "4.2",
     88    getBoolean: () => true,
     89};
     90var module = loadWebAssembly("wasm/type-conversion.wasm", imports);
    3991
    4092var two = {
     
    71123shouldBe(module.takeAndReturnDouble([2.5]), 2.5);
    72124shouldBe(module.takeAndReturnDouble(two), 2);
     125
     126shouldBe(module.returnInt32FromInt32(), 42);
     127shouldBe(module.returnInt32FromDouble(), 4);
     128shouldBe(module.returnInt32FromString(), 4);
     129shouldBe(module.returnInt32FromBoolean(), 1);
     130shouldBe(module.returnDoubleFromInt32(), 42);
     131shouldBe(module.returnDoubleFromDouble(), 4.2);
     132shouldBe(module.returnDoubleFromString(), 4.2);
     133shouldBe(module.returnDoubleFromBoolean(), 1);
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h

    r189918 r189946  
    113113        unsigned localIndex = 0;
    114114        for (size_t i = 0; i < arguments.size(); ++i) {
     115            // FIXME: No need to do type conversion if the caller is a WebAssembly function.
     116            // https://bugs.webkit.org/show_bug.cgi?id=149310
    115117            Address address(GPRInfo::callFrameRegister, CallFrame::argumentOffset(i) * sizeof(Register));
     118#if USE(JSVALUE64)
     119            JSValueRegs valueRegs(GPRInfo::regT0);
     120#else
     121            JSValueRegs valueRegs(GPRInfo::regT1, GPRInfo::regT0);
     122#endif
     123            loadValue(address, valueRegs);
    116124            switch (arguments[i]) {
    117125            case WASMType::I32:
    118 #if USE(JSVALUE64)
    119                 loadValueAndConvertToInt32(address, GPRInfo::regT0);
    120 #else
    121                 loadValueAndConvertToInt32(address, GPRInfo::regT0, GPRInfo::regT1);
    122 #endif
     126                convertValueToInt32(valueRegs, GPRInfo::regT0);
    123127                store32(GPRInfo::regT0, localAddress(localIndex++));
    124128                break;
     
    126130            case WASMType::F64:
    127131#if USE(JSVALUE64)
    128                 loadValueAndConvertToDouble(address, FPRInfo::fpRegT0, GPRInfo::regT0, GPRInfo::regT1);
    129 #else
    130                 loadValueAndConvertToDouble(address, FPRInfo::fpRegT0, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT2, FPRInfo::fpRegT1);
     132                convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::regT1);
     133#else
     134                convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::regT2, FPRInfo::fpRegT1);
    131135#endif
    132136                if (arguments[i] == WASMType::F32)
     
    286290            if (returnType == WASMExpressionType::F32)
    287291                convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
    288 #if USE(JSVALUE64)
    289             boxDouble(FPRInfo::fpRegT0, GPRInfo::returnValueGPR);
    290 #else
    291             boxDouble(FPRInfo::fpRegT0, GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
    292 #endif
     292            convertDoubleToValue(FPRInfo::fpRegT0, returnValueRegs);
    293293            m_tempStackTop--;
    294294            break;
     
    939939        for (size_t i = 0; i < argumentCount; ++i) {
    940940            Address address(GPRInfo::callFrameRegister, (stackOffset + CallFrame::argumentOffset(i)) * sizeof(Register));
     941#if USE(JSVALUE64)
     942            JSValueRegs valueRegs(GPRInfo::regT0);
     943#else
     944            JSValueRegs valueRegs(GPRInfo::regT1, GPRInfo::regT0);
     945#endif
    941946            switch (arguments[i]) {
    942947            case WASMType::I32:
     
    949954                store32(TrustedImm32(JSValue::Int32Tag), address.withOffset(TagOffset));
    950955#endif
     956                break;
     957            case WASMType::F32:
     958            case WASMType::F64:
     959                loadDouble(temporaryAddress(m_tempStackTop - argumentCount + i), FPRInfo::fpRegT0);
     960                if (arguments[i] == WASMType::F32)
     961                    convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
     962                convertDoubleToValue(FPRInfo::fpRegT0, valueRegs);
     963                storeValue(valueRegs, address);
    951964                break;
    952965            default:
     
    9891002        checkStackPointerAlignment();
    9901003
     1004        // FIXME: No need to do type conversion if the callee is a WebAssembly function.
     1005        // https://bugs.webkit.org/show_bug.cgi?id=149310
     1006#if USE(JSVALUE64)
     1007        JSValueRegs valueRegs(GPRInfo::returnValueGPR);
     1008#else
     1009        JSValueRegs valueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
     1010#endif
    9911011        switch (returnType) {
    9921012        case WASMExpressionType::I32:
    993             store32(GPRInfo::returnValueGPR, temporaryAddress(m_tempStackTop++));
     1013            convertValueToInt32(valueRegs, GPRInfo::regT0);
     1014            store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++));
     1015            break;
     1016        case WASMExpressionType::F32:
     1017        case WASMExpressionType::F64:
     1018#if USE(JSVALUE64)
     1019            convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::nonPreservedNonReturnGPR);
     1020#else
     1021            convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::nonPreservedNonReturnGPR, FPRInfo::fpRegT1);
     1022#endif
     1023            if (returnType == WASMExpressionType::F32)
     1024                convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
     1025            storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++));
    9941026            break;
    9951027        case WASMExpressionType::Void:
     
    10011033
    10021034#if USE(JSVALUE64)
    1003     void loadValueAndConvertToInt32(Address address, GPRReg dst)
    1004     {
    1005         JSValueRegs tempRegs(dst);
    1006         loadValue(address, tempRegs);
    1007         Jump checkJSInt32 = branchIfInt32(tempRegs);
    1008 
    1009         callOperation(operationConvertJSValueToInt32, dst, dst);
     1035    void convertValueToInt32(JSValueRegs valueRegs, GPRReg dst)
     1036    {
     1037        Jump checkJSInt32 = branchIfInt32(valueRegs);
     1038
     1039        callOperation(operationConvertJSValueToInt32, valueRegs.gpr(), valueRegs.gpr());
    10101040
    10111041        checkJSInt32.link(this);
    1012     }
    1013 
    1014     void loadValueAndConvertToDouble(Address address, FPRReg dst, GPRReg scratch1, GPRReg scratch2)
    1015     {
    1016         JSValueRegs tempRegs(scratch1);
    1017         loadValue(address, tempRegs);
    1018         Jump checkJSInt32 = branchIfInt32(tempRegs);
    1019         Jump checkJSNumber = branchIfNumber(tempRegs, scratch2);
     1042        move(valueRegs.gpr(), dst);
     1043    }
     1044
     1045    void convertValueToDouble(JSValueRegs valueRegs, FPRReg dst, GPRReg scratch)
     1046    {
     1047        Jump checkJSInt32 = branchIfInt32(valueRegs);
     1048        Jump checkJSNumber = branchIfNumber(valueRegs, scratch);
    10201049        JumpList end;
    10211050
    1022         callOperation(operationConvertJSValueToDouble, tempRegs.gpr(), dst);
     1051        callOperation(operationConvertJSValueToDouble, valueRegs.gpr(), dst);
    10231052        end.append(jump());
    10241053
    10251054        checkJSInt32.link(this);
    1026         convertInt32ToDouble(tempRegs.gpr(), dst);
     1055        convertInt32ToDouble(valueRegs.gpr(), dst);
    10271056        end.append(jump());
    10281057
    10291058        checkJSNumber.link(this);
    1030         unboxDoubleWithoutAssertions(tempRegs.gpr(), dst);
     1059        unboxDoubleWithoutAssertions(valueRegs.gpr(), dst);
    10311060        end.link(this);
    10321061    }
    10331062#else
    1034     void loadValueAndConvertToInt32(Address address, GPRReg dst, GPRReg scratch)
    1035     {
    1036         JSValueRegs tempRegs(scratch, dst);
    1037         loadValue(address, tempRegs);
    1038         Jump checkJSInt32 = branchIfInt32(tempRegs);
    1039 
    1040         callOperation(operationConvertJSValueToInt32, tempRegs.tagGPR(), tempRegs.payloadGPR(), dst);
     1063    void convertValueToInt32(JSValueRegs valueRegs, GPRReg dst)
     1064    {
     1065        Jump checkJSInt32 = branchIfInt32(valueRegs);
     1066
     1067        callOperation(operationConvertJSValueToInt32, valueRegs.tagGPR(), valueRegs.payloadGPR(), valueRegs.payloadGPR());
    10411068
    10421069        checkJSInt32.link(this);
    1043     }
    1044 
    1045     void loadValueAndConvertToDouble(Address address, FPRReg dst, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, FPRReg fpScratch)
    1046     {
    1047         JSValueRegs tempRegs(scratch2, scratch1);
    1048         loadValue(address, tempRegs);
    1049         Jump checkJSInt32 = branchIfInt32(tempRegs);
    1050         Jump checkJSNumber = branchIfNumber(tempRegs, scratch3);
     1070        move(valueRegs.payloadGPR(), dst);
     1071    }
     1072
     1073    void convertValueToDouble(JSValueRegs valueRegs, FPRReg dst, GPRReg scratch, FPRReg fpScratch)
     1074    {
     1075        Jump checkJSInt32 = branchIfInt32(valueRegs);
     1076        Jump checkJSNumber = branchIfNumber(valueRegs, scratch);
    10511077        JumpList end;
    10521078
    1053         callOperation(operationConvertJSValueToDouble, tempRegs.tagGPR(), tempRegs.payloadGPR(), dst);
     1079        callOperation(operationConvertJSValueToDouble, valueRegs.tagGPR(), valueRegs.payloadGPR(), dst);
    10541080        end.append(jump());
    10551081
    10561082        checkJSInt32.link(this);
    1057         convertInt32ToDouble(tempRegs.payloadGPR(), dst);
     1083        convertInt32ToDouble(valueRegs.payloadGPR(), dst);
    10581084        end.append(jump());
    10591085
    10601086        checkJSNumber.link(this);
    1061         unboxDouble(tempRegs.tagGPR(), tempRegs.payloadGPR(), dst, fpScratch);
     1087        unboxDouble(valueRegs.tagGPR(), valueRegs.payloadGPR(), dst, fpScratch);
    10621088        end.link(this);
    10631089    }
    10641090#endif
     1091
     1092    void convertDoubleToValue(FPRReg fpr, JSValueRegs valueRegs)
     1093    {
     1094#if USE(JSVALUE64)
     1095        boxDouble(fpr, valueRegs.gpr());
     1096#else
     1097        boxDouble(fpr, valueRegs.tagGPR(), valueRegs.payloadGPR());
     1098#endif
     1099    }
    10651100
    10661101    JSWASMModule* m_module;
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp

    r189892 r189946  
    530530            return parseGetGlobalExpressionI32(context);
    531531        case WASMOpExpressionI32::CallInternal:
    532             return parseCallInternalExpressionI32(context);
     532            return parseCallInternal(context, WASMExpressionType::I32);
    533533        case WASMOpExpressionI32::CallIndirect:
    534534            return parseCallIndirect(context, WASMExpressionType::I32);
     
    682682
    683683template <class Context>
    684 ContextExpression WASMFunctionParser::parseCallInternalExpressionI32(Context& context)
    685 {
    686     return parseCallInternal(context, WASMExpressionType::I32);
    687 }
    688 
    689 template <class Context>
    690684ContextExpression WASMFunctionParser::parseUnaryExpressionI32(Context& context, WASMOpExpressionI32 op)
    691685{
     
    753747        case WASMOpExpressionF32::GetGlobal:
    754748            return parseGetGlobalExpressionF32(context);
     749        case WASMOpExpressionF32::CallInternal:
     750            return parseCallInternal(context, WASMExpressionType::F32);
    755751        case WASMOpExpressionF32::CallIndirect:
    756752            return parseCallIndirect(context, WASMExpressionType::F32);
     
    772768        case WASMOpExpressionF32::Store:
    773769        case WASMOpExpressionF32::StoreWithOffset:
    774         case WASMOpExpressionF32::CallInternal:
    775770        case WASMOpExpressionF32::Conditional:
    776771        case WASMOpExpressionF32::Comma:
     
    881876        case WASMOpExpressionF64::GetGlobal:
    882877            return parseGetGlobalExpressionF64(context);
     878        case WASMOpExpressionF64::CallInternal:
     879            return parseCallInternal(context, WASMExpressionType::F64);
    883880        case WASMOpExpressionF64::CallImport:
    884881            return parseCallImport(context, WASMExpressionType::F64);
     
    891888        case WASMOpExpressionF64::Store:
    892889        case WASMOpExpressionF64::StoreWithOffset:
    893         case WASMOpExpressionF64::CallInternal:
    894890        case WASMOpExpressionF64::Conditional:
    895891        case WASMOpExpressionF64::Comma:
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h

    r189892 r189946  
    9090    template <class Context> ContextExpression parseGetLocalExpressionI32(Context&);
    9191    template <class Context> ContextExpression parseGetGlobalExpressionI32(Context&);
    92     template <class Context> ContextExpression parseCallInternalExpressionI32(Context&);
    9392    template <class Context> ContextExpression parseUnaryExpressionI32(Context&, WASMOpExpressionI32);
    9493    template <class Context> ContextExpression parseBinaryExpressionI32(Context&, WASMOpExpressionI32);
Note: See TracChangeset for help on using the changeset viewer.