WebAssembly: trap on bad division.
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Dec 2016 19:08:43 +0000 (19:08 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Dec 2016 19:08:43 +0000 (19:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=164786

Reviewed by Mark Lam.

JSTests:

Also, mark conversions as passing.

* wasm.yaml:
* wasm/wasm.json:

Source/JavaScriptCore:

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:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@210137 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/wasm.yaml
JSTests/wasm/wasm.json
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmExceptionType.h
Source/JavaScriptCore/wasm/WasmPlan.cpp
Source/JavaScriptCore/wasm/wasm.json

index a69413e..55cd99b 100644 (file)
@@ -1,3 +1,15 @@
+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
index 2f9ec15..db9a1dd 100644 (file)
@@ -59,7 +59,7 @@
   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
index 8ea5c6c..c51fb74 100644 (file)
         "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"       },
index 68a6c14..5ede504 100644 (file)
@@ -1,3 +1,20 @@
+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.
index dad5dca..8e6b6c4 100644 (file)
@@ -212,6 +212,8 @@ private:
     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;
@@ -993,6 +995,109 @@ Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm,
 
 // 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
 {
index 1a67eaf..34bb3d2 100644 (file)
@@ -38,6 +38,8 @@ namespace Wasm {
     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,
index c8531c8..ed28bbc 100644 (file)
@@ -194,7 +194,7 @@ void Plan::run()
     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);
index 8ea5c6c..c51fb74 100644 (file)
         "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"       },