+2016-12-23 Keith Miller <keith_miller@apple.com>
+
+ WebAssembly: trap on bad division.
+ https://bugs.webkit.org/show_bug.cgi?id=164786
+
+ Reviewed by Mark Lam.
+
+ Also, mark conversions as passing.
+
+ * wasm.yaml:
+ * wasm/wasm.json:
+
2016-12-22 Keith Miller <keith_miller@apple.com>
WebAssembly: Make spec-tests/f32.wast.js and spec-tests/f64.wast.js pass
cmd: runWebAssemblySpecTest :normal
- path: wasm/spec-tests/conversions.wast.js
- cmd: runWebAssemblySpecTest :skip
+ cmd: runWebAssemblySpecTest :normal
- path: wasm/spec-tests/custom_section.wast.js
cmd: runWebAssemblySpecTest :skip
cmd: runWebAssemblySpecTest :skip
- path: wasm/spec-tests/i32.wast.js
- cmd: runWebAssemblySpecTest :skip
+ cmd: runWebAssemblySpecTest :normal
- path: wasm/spec-tests/i64.wast.js
- cmd: runWebAssemblySpecTest :skip
+ cmd: runWebAssemblySpecTest :normal
- path: wasm/spec-tests/imports.wast.js
cmd: runWebAssemblySpecTest :skip
"i32.add": { "category": "arithmetic", "value": 106, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Add" },
"i32.sub": { "category": "arithmetic", "value": 107, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Sub" },
"i32.mul": { "category": "arithmetic", "value": 108, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Mul" },
- "i32.div_s": { "category": "arithmetic", "value": 109, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Div" },
- "i32.div_u": { "category": "arithmetic", "value": 110, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "UDiv" },
- "i32.rem_s": { "category": "arithmetic", "value": 111, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Mod" },
- "i32.rem_u": { "category": "arithmetic", "value": 112, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "UMod" },
+ "i32.div_s": { "category": "arithmetic", "value": 109, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [] },
+ "i32.div_u": { "category": "arithmetic", "value": 110, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [] },
+ "i32.rem_s": { "category": "arithmetic", "value": 111, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [] },
+ "i32.rem_u": { "category": "arithmetic", "value": 112, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [] },
"i32.and": { "category": "arithmetic", "value": 113, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "BitAnd" },
"i32.or": { "category": "arithmetic", "value": 114, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "BitOr" },
"i32.xor": { "category": "arithmetic", "value": 115, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "BitXor" },
"i64.add": { "category": "arithmetic", "value": 124, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Add" },
"i64.sub": { "category": "arithmetic", "value": 125, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Sub" },
"i64.mul": { "category": "arithmetic", "value": 126, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Mul" },
- "i64.div_s": { "category": "arithmetic", "value": 127, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Div" },
- "i64.div_u": { "category": "arithmetic", "value": 128, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "UDiv" },
- "i64.rem_s": { "category": "arithmetic", "value": 129, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Mod" },
- "i64.rem_u": { "category": "arithmetic", "value": 130, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "UDiv" },
+ "i64.div_s": { "category": "arithmetic", "value": 127, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [] },
+ "i64.div_u": { "category": "arithmetic", "value": 128, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [] },
+ "i64.rem_s": { "category": "arithmetic", "value": 129, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [] },
+ "i64.rem_u": { "category": "arithmetic", "value": 130, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [] },
"i64.and": { "category": "arithmetic", "value": 131, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "BitAnd" },
"i64.or": { "category": "arithmetic", "value": 132, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "BitOr" },
"i64.xor": { "category": "arithmetic", "value": 133, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "BitXor" },
+2016-12-23 Keith Miller <keith_miller@apple.com>
+
+ WebAssembly: trap on bad division.
+ https://bugs.webkit.org/show_bug.cgi?id=164786
+
+ Reviewed by Mark Lam.
+
+ This patch adds traps for division / modulo by zero and for
+ division by int_min / -1.
+
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::emitChecksForModOrDiv):
+ * wasm/WasmExceptionType.h:
+ * wasm/WasmPlan.cpp:
+ (JSC::Wasm::Plan::run):
+ * wasm/wasm.json:
+
2016-12-23 Mark Lam <mark.lam@apple.com>
Fix broken LLINT_SLOW_PATH_TRACING build.
void unifyValuesWithBlock(const ExpressionList& resultStack, ResultList& stack);
Value* zeroForType(Type);
+ void emitChecksForModOrDiv(B3::Opcode, ExpressionType left, ExpressionType right);
+
VM& m_vm;
const ImmutableFunctionIndexSpace& m_functionIndexSpace;
const ModuleInformation& m_info;
// Custom wasm ops. These are the ones too messy to do in wasm.json.
+void B3IRGenerator::emitChecksForModOrDiv(B3::Opcode operation, ExpressionType left, ExpressionType right)
+{
+ ASSERT(operation == Div || operation == Mod || operation == UDiv || operation == UMod);
+ const B3::Type type = left->type();
+
+ {
+ CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
+ m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), right,
+ m_currentBlock->appendIntConstant(m_proc, Origin(), type, 0)));
+
+ check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+ this->emitExceptionCheck(jit, ExceptionType::DivisionByZero);
+ });
+ }
+
+ if (operation == Div) {
+ int64_t min = type == Int32 ? std::numeric_limits<int32_t>::min() : std::numeric_limits<int64_t>::min();
+
+ CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
+ m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+ m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), left,
+ m_currentBlock->appendIntConstant(m_proc, Origin(), type, min)),
+ m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), right,
+ m_currentBlock->appendIntConstant(m_proc, Origin(), type, -1))));
+
+ check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+ this->emitExceptionCheck(jit, ExceptionType::IntegerOverflow);
+ });
+ }
+}
+
+template<>
+auto B3IRGenerator::addOp<OpType::I32DivS>(ExpressionType left, ExpressionType right, ExpressionType& result) -> PartialResult
+{
+ const B3::Opcode op = Div;
+ emitChecksForModOrDiv(op, left, right);
+ result = m_currentBlock->appendNew<Value>(m_proc, op, Origin(), left, right);
+ return { };
+}
+
+template<>
+auto B3IRGenerator::addOp<OpType::I32RemS>(ExpressionType left, ExpressionType right, ExpressionType& result) -> PartialResult
+{
+ const B3::Opcode op = Mod;
+ emitChecksForModOrDiv(op, left, right);
+ result = m_currentBlock->appendNew<Value>(m_proc, chill(op), Origin(), left, right);
+ return { };
+}
+
+template<>
+auto B3IRGenerator::addOp<OpType::I32DivU>(ExpressionType left, ExpressionType right, ExpressionType& result) -> PartialResult
+{
+ const B3::Opcode op = UDiv;
+ emitChecksForModOrDiv(op, left, right);
+ result = m_currentBlock->appendNew<Value>(m_proc, op, Origin(), left, right);
+ return { };
+}
+
+template<>
+auto B3IRGenerator::addOp<OpType::I32RemU>(ExpressionType left, ExpressionType right, ExpressionType& result) -> PartialResult
+{
+ const B3::Opcode op = UMod;
+ emitChecksForModOrDiv(op, left, right);
+ result = m_currentBlock->appendNew<Value>(m_proc, op, Origin(), left, right);
+ return { };
+}
+
+template<>
+auto B3IRGenerator::addOp<OpType::I64DivS>(ExpressionType left, ExpressionType right, ExpressionType& result) -> PartialResult
+{
+ const B3::Opcode op = Div;
+ emitChecksForModOrDiv(op, left, right);
+ result = m_currentBlock->appendNew<Value>(m_proc, op, Origin(), left, right);
+ return { };
+}
+
+template<>
+auto B3IRGenerator::addOp<OpType::I64RemS>(ExpressionType left, ExpressionType right, ExpressionType& result) -> PartialResult
+{
+ const B3::Opcode op = Mod;
+ emitChecksForModOrDiv(op, left, right);
+ result = m_currentBlock->appendNew<Value>(m_proc, chill(op), Origin(), left, right);
+ return { };
+}
+
+template<>
+auto B3IRGenerator::addOp<OpType::I64DivU>(ExpressionType left, ExpressionType right, ExpressionType& result) -> PartialResult
+{
+ const B3::Opcode op = UDiv;
+ emitChecksForModOrDiv(op, left, right);
+ result = m_currentBlock->appendNew<Value>(m_proc, op, Origin(), left, right);
+ return { };
+}
+
+template<>
+auto B3IRGenerator::addOp<OpType::I64RemU>(ExpressionType left, ExpressionType right, ExpressionType& result) -> PartialResult
+{
+ const B3::Opcode op = UMod;
+ emitChecksForModOrDiv(op, left, right);
+ result = m_currentBlock->appendNew<Value>(m_proc, op, Origin(), left, right);
+ return { };
+}
+
template<>
auto B3IRGenerator::addOp<OpType::I32Ctz>(ExpressionType arg, ExpressionType& result) -> PartialResult
{
macro(BadSignature, "call_indirect to a signature that does not match") \
macro(OutOfBoundsTrunc, "Out of bounds Trunc operation") \
macro(Unreachable, "Unreachable code should not be executed") \
+ macro(DivisionByZero, "Division by zero") \
+ macro(IntegerOverflow, "Integer overflow")
enum class ExceptionType : uint32_t {
#define MAKE_ENUM(enumName, error) enumName,
if (verbose || Options::reportCompileTimes())
startTime = MonotonicTime::now();
- uint32_t threadCount = WTF::numberOfProcessorCores();
+ uint32_t threadCount = Options::useConcurrentJIT() ? WTF::numberOfProcessorCores() : 1;
uint32_t numWorkerThreads = threadCount - 1;
Vector<ThreadIdentifier> threads;
threads.reserveCapacity(numWorkerThreads);
"i32.add": { "category": "arithmetic", "value": 106, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Add" },
"i32.sub": { "category": "arithmetic", "value": 107, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Sub" },
"i32.mul": { "category": "arithmetic", "value": 108, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Mul" },
- "i32.div_s": { "category": "arithmetic", "value": 109, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Div" },
- "i32.div_u": { "category": "arithmetic", "value": 110, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "UDiv" },
- "i32.rem_s": { "category": "arithmetic", "value": 111, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "Mod" },
- "i32.rem_u": { "category": "arithmetic", "value": 112, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "UMod" },
+ "i32.div_s": { "category": "arithmetic", "value": 109, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [] },
+ "i32.div_u": { "category": "arithmetic", "value": 110, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [] },
+ "i32.rem_s": { "category": "arithmetic", "value": 111, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [] },
+ "i32.rem_u": { "category": "arithmetic", "value": 112, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [] },
"i32.and": { "category": "arithmetic", "value": 113, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "BitAnd" },
"i32.or": { "category": "arithmetic", "value": 114, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "BitOr" },
"i32.xor": { "category": "arithmetic", "value": 115, "return": ["i32"], "parameter": ["i32", "i32"], "immediate": [], "b3op": "BitXor" },
"i64.add": { "category": "arithmetic", "value": 124, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Add" },
"i64.sub": { "category": "arithmetic", "value": 125, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Sub" },
"i64.mul": { "category": "arithmetic", "value": 126, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Mul" },
- "i64.div_s": { "category": "arithmetic", "value": 127, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Div" },
- "i64.div_u": { "category": "arithmetic", "value": 128, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "UDiv" },
- "i64.rem_s": { "category": "arithmetic", "value": 129, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "Mod" },
- "i64.rem_u": { "category": "arithmetic", "value": 130, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "UDiv" },
+ "i64.div_s": { "category": "arithmetic", "value": 127, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [] },
+ "i64.div_u": { "category": "arithmetic", "value": 128, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [] },
+ "i64.rem_s": { "category": "arithmetic", "value": 129, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [] },
+ "i64.rem_u": { "category": "arithmetic", "value": 130, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [] },
"i64.and": { "category": "arithmetic", "value": 131, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "BitAnd" },
"i64.or": { "category": "arithmetic", "value": 132, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "BitOr" },
"i64.xor": { "category": "arithmetic", "value": 133, "return": ["i64"], "parameter": ["i64", "i64"], "immediate": [], "b3op": "BitXor" },