Changeset 189405 in webkit
- Timestamp:
- Sep 4, 2015 5:14:21 PM (9 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r189398 r189405 1 2015-09-04 Sukolsak Sakshuwong <sukolsak@gmail.com> 2 3 Implement the division and modulo instructions in WebAssembly 4 https://bugs.webkit.org/show_bug.cgi?id=148791 5 6 Reviewed by Geoffrey Garen. 7 8 This patch implements the unsigned division, signed modulo, and unsigned 9 modulo instructions for 32-bit integers in WebAssembly. It also 10 implements the context pool index instructions, which are needed for 11 testing. (pack-asmjs puts numbers that are used more than once in the 12 constant pool.) 13 14 * assembler/X86Assembler.h: 15 (JSC::X86Assembler::divl_r): 16 * tests/stress/wasm-arithmetic.js: 17 * tests/stress/wasm-arithmetic.wasm: 18 * wasm/WASMFunctionCompiler.h: 19 (JSC::operationMod): 20 (JSC::operationUnsignedDiv): 21 (JSC::operationUnsignedMod): 22 (JSC::WASMFunctionCompiler::buildBinaryI32): 23 (JSC::WASMFunctionCompiler::callOperation): 24 * wasm/WASMFunctionParser.cpp: 25 (JSC::WASMFunctionParser::parseExpressionI32): 26 (JSC::WASMFunctionParser::parseConstantPoolIndexExpressionI32): 27 * wasm/WASMFunctionParser.h: 28 1 29 2015-09-04 Basile Clement <basile_clement@apple.com> 2 30 -
trunk/Source/JavaScriptCore/assembler/X86Assembler.h
r189357 r189405 312 312 GROUP3_OP_NOT = 2, 313 313 GROUP3_OP_NEG = 3, 314 GROUP3_OP_DIV = 6, 314 315 GROUP3_OP_IDIV = 7, 315 316 … … 931 932 m_formatter.oneByteOp(OP_IMUL_GvEvIz, dst, src); 932 933 m_formatter.immediate32(value); 934 } 935 936 void divl_r(RegisterID dst) 937 { 938 m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_DIV, dst); 933 939 } 934 940 -
trunk/Source/JavaScriptCore/tests/stress/wasm-arithmetic.js
r189396 r189405 45 45 } 46 46 47 function unsignedDivide() { 48 return ((-1 >>> 0) / 2) | 0; 49 } 50 51 function unsignedDivideByZero() { 52 return ((-1 >>> 0) / 0) | 0; 53 } 54 55 function modulo() { 56 return (42 % 5) | 0; 57 } 58 59 function moduloNegative() { 60 return (-42 % 5) | 0; 61 } 62 63 function moduloZero() { 64 return (1 % 0) | 0; 65 } 66 67 function moduloOverflow() { 68 return (-2147483648 % -1) | 0; 69 } 70 71 function unsignedModulo() { 72 return ((-1 >>> 0) % 100000) | 0; 73 } 74 75 function unsignedModuloZero() { 76 return ((-1 >>> 0) % 0) | 0; 77 } 78 47 79 return { 48 80 addSubtract: addSubtract, … … 51 83 divideByZero: divideByZero, 52 84 divideOverflow: divideOverflow, 85 unsignedDivide: unsignedDivide, 86 unsignedDivideByZero: unsignedDivideByZero, 87 modulo: modulo, 88 moduloNegative: moduloNegative, 89 moduloZero: moduloZero, 90 moduloOverflow: moduloOverflow, 91 unsignedModulo: unsignedModulo, 92 unsignedModuloZero: unsignedModuloZero, 53 93 }; 54 94 } … … 70 110 module.divideOverflow(); 71 111 }, "Error: Division by zero or division overflow."); 112 113 shouldBe(module.unsignedDivide(), 2147483647); 114 115 shouldThrow(() => { 116 module.unsignedDivideByZero(); 117 }, "Error: Division by zero or division overflow."); 118 119 shouldBe(module.modulo(), 2); 120 121 shouldBe(module.moduloNegative(), -2); 122 123 shouldThrow(() => { 124 module.moduloZero(); 125 }, "Error: Division by zero or division overflow."); 126 127 shouldThrow(() => { 128 module.moduloOverflow(); 129 }, "Error: Division by zero or division overflow."); 130 131 shouldBe(module.unsignedModulo(), 67295); 132 133 shouldThrow(() => { 134 module.unsignedModuloZero(); 135 }, "Error: Division by zero or division overflow."); -
trunk/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h
r189396 r189405 43 43 return left / right; 44 44 } 45 46 static int32_t JIT_OPERATION operationMod(int32_t left, int32_t right) 47 { 48 return left % right; 49 } 50 51 static uint32_t JIT_OPERATION operationUnsignedDiv(uint32_t left, uint32_t right) 52 { 53 return left / right; 54 } 55 56 static uint32_t JIT_OPERATION operationUnsignedMod(uint32_t left, uint32_t right) 57 { 58 return left % right; 59 } 45 60 #endif 46 61 … … 223 238 sub32(GPRInfo::regT1, GPRInfo::regT0); 224 239 break; 225 case WASMOpExpressionI32::SDiv: { 240 case WASMOpExpressionI32::SDiv: 241 case WASMOpExpressionI32::UDiv: 242 case WASMOpExpressionI32::SMod: 243 case WASMOpExpressionI32::UMod: { 226 244 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); 245 if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) { 246 Jump denominatorNotNeg1 = branch32(NotEqual, GPRInfo::regT1, TrustedImm32(-1)); 247 m_divideErrorJumpList.append(branch32(Equal, GPRInfo::regT0, TrustedImm32(-2147483647-1))); 248 denominatorNotNeg1.link(this); 249 } 230 250 #if CPU(X86) || CPU(X86_64) 231 251 ASSERT(GPRInfo::regT0 == X86Registers::eax); 232 252 move(GPRInfo::regT1, X86Registers::ecx); 233 m_assembler.cdq(); 234 m_assembler.idivl_r(X86Registers::ecx); 253 if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) { 254 m_assembler.cdq(); 255 m_assembler.idivl_r(X86Registers::ecx); 256 } else { 257 ASSERT(op == WASMOpExpressionI32::UDiv || op == WASMOpExpressionI32::UMod); 258 xor32(X86Registers::edx, X86Registers::edx); 259 m_assembler.divl_r(X86Registers::ecx); 260 } 261 if (op == WASMOpExpressionI32::SMod || op == WASMOpExpressionI32::UMod) 262 move(X86Registers::edx, GPRInfo::regT0); 235 263 #else 264 // FIXME: We should be able to do an inline div on ARMv7 and ARM64. 236 265 if (maxFrameExtentForSlowPathCall) 237 266 addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister); 238 callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); 267 switch (op) { 268 case WASMOpExpressionI32::SDiv: 269 callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); 270 break; 271 case WASMOpExpressionI32::UDiv: 272 callOperation(operationUnsignedDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); 273 break; 274 case WASMOpExpressionI32::SMod: 275 callOperation(operationMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); 276 break; 277 case WASMOpExpressionI32::UMod: 278 callOperation(operationUnsignedMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); 279 break; 280 default: 281 ASSERT_NOT_REACHED(); 282 } 239 283 if (maxFrameExtentForSlowPathCall) 240 284 addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister); … … 287 331 } 288 332 333 void callOperation(uint32_t JIT_OPERATION (*operation)(uint32_t, uint32_t), GPRReg src1, GPRReg src2, GPRReg dst) 334 { 335 setupArguments(src1, src2); 336 appendCall(operation); 337 move(GPRInfo::returnValueGPR, dst); 338 } 339 289 340 unsigned m_stackHeight; 290 341 unsigned m_numberOfLocals; -
trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp
r189396 r189405 425 425 if (!hasImmediate) { 426 426 switch (op) { 427 case WASMOpExpressionI32::ConstantPoolIndex: 428 return parseConstantPoolIndexExpressionI32(context); 427 429 case WASMOpExpressionI32::Immediate: 428 430 return parseImmediateExpressionI32(context); … … 432 434 case WASMOpExpressionI32::Sub: 433 435 case WASMOpExpressionI32::SDiv: 436 case WASMOpExpressionI32::UDiv: 437 case WASMOpExpressionI32::SMod: 438 case WASMOpExpressionI32::UMod: 434 439 return parseBinaryExpressionI32(context, op); 435 case WASMOpExpressionI32::ConstantPoolIndex:436 440 case WASMOpExpressionI32::GetGlobal: 437 441 case WASMOpExpressionI32::SetLocal: … … 462 466 case WASMOpExpressionI32::Negate: 463 467 case WASMOpExpressionI32::Mul: 464 case WASMOpExpressionI32::UDiv:465 case WASMOpExpressionI32::SMod:466 case WASMOpExpressionI32::UMod:467 468 case WASMOpExpressionI32::BitNot: 468 469 case WASMOpExpressionI32::BitOr: … … 508 509 } else { 509 510 switch (opWithImmediate) { 511 case WASMOpExpressionI32WithImmediate::ConstantPoolIndex: 512 return parseConstantPoolIndexExpressionI32(context, immediate); 510 513 case WASMOpExpressionI32WithImmediate::Immediate: 511 514 return parseImmediateExpressionI32(context, immediate); 512 515 case WASMOpExpressionI32WithImmediate::GetLocal: 513 516 return parseGetLocalExpressionI32(context, immediate); 514 case WASMOpExpressionI32WithImmediate::ConstantPoolIndex:515 // FIXME: Implement these instructions.516 FAIL_WITH_MESSAGE("Unsupported instruction.");517 517 default: 518 518 ASSERT_NOT_REACHED(); … … 520 520 } 521 521 return 0; 522 } 523 524 template <class Context> 525 ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionI32(Context& context, uint32_t constantPoolIndex) 526 { 527 FAIL_IF_FALSE(constantPoolIndex < m_module->i32Constants().size(), "The constant pool index is incorrect."); 528 return context.buildImmediateI32(m_module->i32Constants()[constantPoolIndex]); 529 } 530 531 template <class Context> 532 ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionI32(Context& context) 533 { 534 uint32_t constantPoolIndex; 535 READ_COMPACT_UINT32_OR_FAIL(constantPoolIndex, "Cannot read the constant pool index."); 536 return parseConstantPoolIndexExpressionI32(context, constantPoolIndex); 522 537 } 523 538 -
trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h
r189382 r189405 79 79 80 80 template <class Context> ContextExpression parseExpressionI32(Context&); 81 template <class Context> ContextExpression parseConstantPoolIndexExpressionI32(Context&, uint32_t constantPoolIndex); 82 template <class Context> ContextExpression parseConstantPoolIndexExpressionI32(Context&); 81 83 template <class Context> ContextExpression parseImmediateExpressionI32(Context&, uint32_t immediate); 82 84 template <class Context> ContextExpression parseImmediateExpressionI32(Context&);
Note: See TracChangeset
for help on using the changeset viewer.