Changeset 189396 in webkit
- Timestamp:
- Sep 4, 2015 3:47:23 PM (9 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r189382 r189396 1 2015-09-04 Sukolsak Sakshuwong <sukolsak@gmail.com> 2 3 Implement the signed division instruction in WebAssembly 4 https://bugs.webkit.org/show_bug.cgi?id=148772 5 6 Reviewed by Geoffrey Garen. 7 8 This patch implements the signed division instruction in WebAssembly 9 for 32-bit integers. We use the IDIV instruction on x86 and x86-64 and 10 use a C function on all other platforms. We throw an exception if 11 - the denominator is zero, or 12 - the numerator is -2^31 and the denominator is -1. 13 14 * jit/JITOperations.cpp: 15 * jit/JITOperations.h: 16 * tests/stress/wasm-arithmetic.js: 17 (shouldBe): 18 (shouldThrow): 19 * tests/stress/wasm-arithmetic.wasm: 20 * wasm/WASMFunctionCompiler.h: 21 (JSC::operationDiv): 22 (JSC::WASMFunctionCompiler::endFunction): 23 (JSC::WASMFunctionCompiler::buildBinaryI32): 24 (JSC::WASMFunctionCompiler::appendCall): 25 (JSC::WASMFunctionCompiler::appendCallWithExceptionCheck): 26 (JSC::WASMFunctionCompiler::callOperation): 27 (JSC::WASMFunctionCompiler::throwStackOverflowError): Deleted. 28 * wasm/WASMFunctionParser.cpp: 29 (JSC::WASMFunctionParser::parseExpressionI32): 30 1 31 2015-09-04 Sukolsak Sakshuwong <sukolsak@gmail.com> 2 32 -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r189339 r189396 96 96 } 97 97 98 #if ENABLE(WEBASSEMBLY) 99 void JIT_OPERATION operationThrowDivideError(ExecState* exec) 100 { 101 VM* vm = &exec->vm(); 102 VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame; 103 CallFrame* callerFrame = exec->callerFrame(vmEntryFrame); 104 105 NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame); 106 ErrorHandlingScope errorScope(*vm); 107 vm->throwException(callerFrame, createError(callerFrame, ASCIILiteral("Division by zero or division overflow."))); 108 } 109 #endif 110 98 111 int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec) 99 112 { -
trunk/Source/JavaScriptCore/jit/JITOperations.h
r189279 r189396 246 246 247 247 void JIT_OPERATION operationThrowStackOverflowError(ExecState*, CodeBlock*) WTF_INTERNAL; 248 #if ENABLE(WEBASSEMBLY) 249 void JIT_OPERATION operationThrowDivideError(ExecState*) WTF_INTERNAL; 250 #endif 248 251 int32_t JIT_OPERATION operationCallArityCheck(ExecState*) WTF_INTERNAL; 249 252 int32_t JIT_OPERATION operationConstructArityCheck(ExecState*) WTF_INTERNAL; -
trunk/Source/JavaScriptCore/tests/stress/wasm-arithmetic.js
r189303 r189396 1 1 //@ skip 2 3 function shouldBe(actual, expected) { 4 if (actual !== expected) 5 throw new Error('bad value: ' + actual); 6 } 7 8 function shouldThrow(func, message) { 9 var error = null; 10 try { 11 func(); 12 } catch (e) { 13 error = e; 14 } 15 if (!error) 16 throw new Error("not thrown."); 17 if (String(error) !== message) 18 throw new Error("bad error: " + String(error)); 19 } 2 20 3 21 /* … … 7 25 "use asm"; 8 26 9 function main() { 10 return (10 + 40) - 8; 27 function addSubtract() { 28 return ((10 + 40) - 8) | 0; 29 } 30 31 function addOverflow() { 32 return (2147483647 + 1) | 0; 33 } 34 35 function divide() { 36 return (42 / 5) | 0; 37 } 38 39 function divideByZero() { 40 return (1 / 0) | 0; 41 } 42 43 function divideOverflow() { 44 return (-2147483648 / -1) | 0; 11 45 } 12 46 13 47 return { 14 main: main 48 addSubtract: addSubtract, 49 addOverflow: addOverflow, 50 divide: divide, 51 divideByZero: divideByZero, 52 divideOverflow: divideOverflow, 15 53 }; 16 54 } … … 18 56 19 57 var module = loadWebAssembly("wasm-arithmetic.wasm"); 20 var result = module.main(); 21 if (result != 42) 22 throw "Error: bad result: " + result; 58 59 shouldBe(module.addSubtract(), 42); 60 61 shouldBe(module.addOverflow(), -2147483648); 62 63 shouldBe(module.divide(), 8); 64 65 shouldThrow(() => { 66 module.divideByZero(); 67 }, "Error: Division by zero or division overflow."); 68 69 shouldThrow(() => { 70 module.divideOverflow(); 71 }, "Error: Division by zero or division overflow."); -
trunk/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h
r189382 r189396 38 38 namespace JSC { 39 39 40 #if !CPU(X86) && !CPU(X86_64) 41 static int32_t JIT_OPERATION operationDiv(int32_t left, int32_t right) 42 { 43 return left / right; 44 } 45 #endif 46 40 47 class WASMFunctionCompiler : private CCallHelpers { 41 48 public: … … 109 116 if (maxFrameExtentForSlowPathCall) 110 117 addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister); 111 throwStackOverflowError(); 118 setupArgumentsWithExecState(TrustedImmPtr(m_codeBlock)); 119 appendCallWithExceptionCheck(operationThrowStackOverflowError); 112 120 113 121 // FIXME: Implement arity check. … … 117 125 jump(m_beginLabel); 118 126 127 if (!m_divideErrorJumpList.empty()) { 128 m_divideErrorJumpList.link(this); 129 130 if (maxFrameExtentForSlowPathCall) 131 addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister); 132 setupArgumentsExecState(); 133 appendCallWithExceptionCheck(operationThrowDivideError); 134 } 135 136 if (!m_exceptionChecks.empty()) { 137 m_exceptionChecks.link(this); 138 139 // lookupExceptionHandler is passed two arguments, the VM and the exec (the CallFrame*). 140 move(TrustedImmPtr(vm()), GPRInfo::argumentGPR0); 141 move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1); 142 143 #if CPU(X86) 144 // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer! 145 poke(GPRInfo::argumentGPR0); 146 poke(GPRInfo::argumentGPR1, 1); 147 #endif 148 m_calls.append(std::make_pair(call(), FunctionPtr(lookupExceptionHandlerFromCallerFrame).value())); 149 jumpToExceptionHandler(); 150 } 151 119 152 LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock, JITCompilationMustSucceed); 120 153 … … 190 223 sub32(GPRInfo::regT1, GPRInfo::regT0); 191 224 break; 225 case WASMOpExpressionI32::SDiv: { 226 m_divideErrorJumpList.append(branchTest32(Zero, GPRInfo::regT1)); 227 Jump denominatorNotNeg1 = branch32(NotEqual, GPRInfo::regT1, TrustedImm32(-1)); 228 m_divideErrorJumpList.append(branch32(Equal, GPRInfo::regT0, TrustedImm32(-2147483647-1))); 229 denominatorNotNeg1.link(this); 230 #if CPU(X86) || CPU(X86_64) 231 ASSERT(GPRInfo::regT0 == X86Registers::eax); 232 move(GPRInfo::regT1, X86Registers::ecx); 233 m_assembler.cdq(); 234 m_assembler.idivl_r(X86Registers::ecx); 235 #else 236 if (maxFrameExtentForSlowPathCall) 237 addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister); 238 callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); 239 if (maxFrameExtentForSlowPathCall) 240 addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister); 241 #endif 242 break; 243 } 192 244 default: 193 245 ASSERT_NOT_REACHED(); … … 217 269 } 218 270 219 void throwStackOverflowError()220 { 221 setupArgumentsWithExecState(TrustedImmPtr(m_codeBlock));222 223 m_calls.append(std::make_pair(call(), FunctionPtr(operationThrowStackOverflowError).value())); 224 225 // lookupExceptionHandlerFromCallerFrame is passed two arguments, the VM and the exec (the CallFrame*).226 move(TrustedImmPtr(m_vm), GPRInfo::argumentGPR0);227 m ove(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);228 #if CPU(X86) 229 // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer! 230 poke(GPRInfo::argumentGPR0);231 poke(GPRInfo::argumentGPR1, 1);232 #endif 233 m_calls.append(std::make_pair(call(), FunctionPtr(lookupExceptionHandlerFromCallerFrame).value()));234 jumpToExceptionHandler();271 void appendCall(const FunctionPtr& function) 272 { 273 m_calls.append(std::make_pair(call(), function.value())); 274 } 275 276 void appendCallWithExceptionCheck(const FunctionPtr& function) 277 { 278 appendCall(function); 279 m_exceptionChecks.append(emitExceptionCheck()); 280 } 281 282 void callOperation(int32_t JIT_OPERATION (*operation)(int32_t, int32_t), GPRReg src1, GPRReg src2, GPRReg dst) 283 { 284 setupArguments(src1, src2); 285 appendCall(operation); 286 move(GPRInfo::returnValueGPR, dst); 235 287 } 236 288 … … 241 293 Label m_beginLabel; 242 294 Jump m_stackOverflow; 295 JumpList m_divideErrorJumpList; 296 JumpList m_exceptionChecks; 243 297 244 298 Vector<std::pair<Call, void*>> m_calls; -
trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp
r189382 r189396 431 431 case WASMOpExpressionI32::Add: 432 432 case WASMOpExpressionI32::Sub: 433 case WASMOpExpressionI32::SDiv: 433 434 return parseBinaryExpressionI32(context, op); 434 435 case WASMOpExpressionI32::ConstantPoolIndex: … … 461 462 case WASMOpExpressionI32::Negate: 462 463 case WASMOpExpressionI32::Mul: 463 case WASMOpExpressionI32::SDiv:464 464 case WASMOpExpressionI32::UDiv: 465 465 case WASMOpExpressionI32::SMod:
Note: See TracChangeset
for help on using the changeset viewer.