Changeset 189946 in webkit
- Timestamp:
- Sep 17, 2015 5:03:49 PM (9 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r189941 r189946 1 2015-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 1 42 2015-09-17 Yusuke Suzuki <utatane.tea@gmail.com> 2 43 -
trunk/Source/JavaScriptCore/tests/stress/wasm-type-conversion.js
r189624 r189946 9 9 wasm/type-conversion.wasm is generated by pack-asmjs <https://github.com/WebAssembly/polyfill-prototype-1> from the following script: 10 10 11 function asmModule(global, env, buffer) {11 function asmModule(global, imports, buffer) { 12 12 "use asm"; 13 13 14 14 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; 15 19 16 20 function takeAndReturnInt32(x) { 17 21 x = x | 0; 18 return x ;22 return x | 0; 19 23 } 20 24 … … 29 33 } 30 34 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 31 67 return { 32 68 takeAndReturnInt32: takeAndReturnInt32, 69 takeAndReturnFloat: takeAndReturnFloat, 33 70 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, 34 80 }; 35 81 } 36 82 */ 37 83 38 var module = loadWebAssembly("wasm/type-conversion.wasm"); 84 var imports = { 85 getInt32: () => 42, 86 getDouble: () => 4.2, 87 getString: () => "4.2", 88 getBoolean: () => true, 89 }; 90 var module = loadWebAssembly("wasm/type-conversion.wasm", imports); 39 91 40 92 var two = { … … 71 123 shouldBe(module.takeAndReturnDouble([2.5]), 2.5); 72 124 shouldBe(module.takeAndReturnDouble(two), 2); 125 126 shouldBe(module.returnInt32FromInt32(), 42); 127 shouldBe(module.returnInt32FromDouble(), 4); 128 shouldBe(module.returnInt32FromString(), 4); 129 shouldBe(module.returnInt32FromBoolean(), 1); 130 shouldBe(module.returnDoubleFromInt32(), 42); 131 shouldBe(module.returnDoubleFromDouble(), 4.2); 132 shouldBe(module.returnDoubleFromString(), 4.2); 133 shouldBe(module.returnDoubleFromBoolean(), 1); -
trunk/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h
r189918 r189946 113 113 unsigned localIndex = 0; 114 114 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 115 117 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); 116 124 switch (arguments[i]) { 117 125 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); 123 127 store32(GPRInfo::regT0, localAddress(localIndex++)); 124 128 break; … … 126 130 case WASMType::F64: 127 131 #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); 131 135 #endif 132 136 if (arguments[i] == WASMType::F32) … … 286 290 if (returnType == WASMExpressionType::F32) 287 291 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); 293 293 m_tempStackTop--; 294 294 break; … … 939 939 for (size_t i = 0; i < argumentCount; ++i) { 940 940 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 941 946 switch (arguments[i]) { 942 947 case WASMType::I32: … … 949 954 store32(TrustedImm32(JSValue::Int32Tag), address.withOffset(TagOffset)); 950 955 #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); 951 964 break; 952 965 default: … … 989 1002 checkStackPointerAlignment(); 990 1003 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 991 1011 switch (returnType) { 992 1012 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++)); 994 1026 break; 995 1027 case WASMExpressionType::Void: … … 1001 1033 1002 1034 #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()); 1010 1040 1011 1041 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); 1020 1049 JumpList end; 1021 1050 1022 callOperation(operationConvertJSValueToDouble, tempRegs.gpr(), dst);1051 callOperation(operationConvertJSValueToDouble, valueRegs.gpr(), dst); 1023 1052 end.append(jump()); 1024 1053 1025 1054 checkJSInt32.link(this); 1026 convertInt32ToDouble( tempRegs.gpr(), dst);1055 convertInt32ToDouble(valueRegs.gpr(), dst); 1027 1056 end.append(jump()); 1028 1057 1029 1058 checkJSNumber.link(this); 1030 unboxDoubleWithoutAssertions( tempRegs.gpr(), dst);1059 unboxDoubleWithoutAssertions(valueRegs.gpr(), dst); 1031 1060 end.link(this); 1032 1061 } 1033 1062 #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()); 1041 1068 1042 1069 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); 1051 1077 JumpList end; 1052 1078 1053 callOperation(operationConvertJSValueToDouble, tempRegs.tagGPR(), tempRegs.payloadGPR(), dst);1079 callOperation(operationConvertJSValueToDouble, valueRegs.tagGPR(), valueRegs.payloadGPR(), dst); 1054 1080 end.append(jump()); 1055 1081 1056 1082 checkJSInt32.link(this); 1057 convertInt32ToDouble( tempRegs.payloadGPR(), dst);1083 convertInt32ToDouble(valueRegs.payloadGPR(), dst); 1058 1084 end.append(jump()); 1059 1085 1060 1086 checkJSNumber.link(this); 1061 unboxDouble( tempRegs.tagGPR(), tempRegs.payloadGPR(), dst, fpScratch);1087 unboxDouble(valueRegs.tagGPR(), valueRegs.payloadGPR(), dst, fpScratch); 1062 1088 end.link(this); 1063 1089 } 1064 1090 #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 } 1065 1100 1066 1101 JSWASMModule* m_module; -
trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp
r189892 r189946 530 530 return parseGetGlobalExpressionI32(context); 531 531 case WASMOpExpressionI32::CallInternal: 532 return parseCallInternal ExpressionI32(context);532 return parseCallInternal(context, WASMExpressionType::I32); 533 533 case WASMOpExpressionI32::CallIndirect: 534 534 return parseCallIndirect(context, WASMExpressionType::I32); … … 682 682 683 683 template <class Context> 684 ContextExpression WASMFunctionParser::parseCallInternalExpressionI32(Context& context)685 {686 return parseCallInternal(context, WASMExpressionType::I32);687 }688 689 template <class Context>690 684 ContextExpression WASMFunctionParser::parseUnaryExpressionI32(Context& context, WASMOpExpressionI32 op) 691 685 { … … 753 747 case WASMOpExpressionF32::GetGlobal: 754 748 return parseGetGlobalExpressionF32(context); 749 case WASMOpExpressionF32::CallInternal: 750 return parseCallInternal(context, WASMExpressionType::F32); 755 751 case WASMOpExpressionF32::CallIndirect: 756 752 return parseCallIndirect(context, WASMExpressionType::F32); … … 772 768 case WASMOpExpressionF32::Store: 773 769 case WASMOpExpressionF32::StoreWithOffset: 774 case WASMOpExpressionF32::CallInternal:775 770 case WASMOpExpressionF32::Conditional: 776 771 case WASMOpExpressionF32::Comma: … … 881 876 case WASMOpExpressionF64::GetGlobal: 882 877 return parseGetGlobalExpressionF64(context); 878 case WASMOpExpressionF64::CallInternal: 879 return parseCallInternal(context, WASMExpressionType::F64); 883 880 case WASMOpExpressionF64::CallImport: 884 881 return parseCallImport(context, WASMExpressionType::F64); … … 891 888 case WASMOpExpressionF64::Store: 892 889 case WASMOpExpressionF64::StoreWithOffset: 893 case WASMOpExpressionF64::CallInternal:894 890 case WASMOpExpressionF64::Conditional: 895 891 case WASMOpExpressionF64::Comma: -
trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h
r189892 r189946 90 90 template <class Context> ContextExpression parseGetLocalExpressionI32(Context&); 91 91 template <class Context> ContextExpression parseGetGlobalExpressionI32(Context&); 92 template <class Context> ContextExpression parseCallInternalExpressionI32(Context&);93 92 template <class Context> ContextExpression parseUnaryExpressionI32(Context&, WASMOpExpressionI32); 94 93 template <class Context> ContextExpression parseBinaryExpressionI32(Context&, WASMOpExpressionI32);
Note: See TracChangeset
for help on using the changeset viewer.