Modified: trunk/Source/_javascript_Core/testWASM.cpp (205768 => 205769)
--- trunk/Source/_javascript_Core/testWASM.cpp 2016-09-09 21:29:47 UTC (rev 205768)
+++ trunk/Source/_javascript_Core/testWASM.cpp 2016-09-09 21:30:51 UTC (rev 205769)
@@ -241,6 +241,138 @@
static void runWASMTests()
{
{
+ // Generated from:
+ // (module
+ // (func "dumb-eq" (param $x i32) (param $y i32) (result i32)
+ // (if (i32.eq (get_local $x) (get_local $y))
+ // (then (br 0))
+ // (else (return (i32.const 1))))
+ // (return (i32.const 0))
+ // )
+ // )
+ Vector<uint8_t> vector = {
+ 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x87, 0x80, 0x80,
+ 0x00, 0x01, 0x40, 0x02, 0x01, 0x01, 0x01, 0x01, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x82, 0x80, 0x80, 0x00, 0x01, 0x00, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x91, 0x80,
+ 0x80, 0x00, 0x01, 0x00, 0x0e, 0x64, 0x75, 0x6d, 0x62, 0x2d, 0x6c, 0x65, 0x73, 0x73, 0x2d, 0x74,
+ 0x68, 0x61, 0x6e, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x97, 0x80, 0x80, 0x00, 0x01, 0x92, 0x80, 0x80,
+ 0x00, 0x00, 0x14, 0x00, 0x14, 0x01, 0x4d, 0x03, 0x10, 0x00, 0x09, 0x01, 0x04, 0x10, 0x01, 0x09,
+ 0x01, 0x0f, 0x0f
+ };
+
+ Plan plan(*vm, vector);
+ if (plan.result.size() != 1 || !plan.result[0]) {
+ dataLogLn("Module failed to compile correctly.");
+ CRASH();
+ }
+
+ // Test this doesn't crash.
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 1);
+ }
+
+ {
+ // Generated from:
+ // (module
+ // (func "dumb-less-than" (param $x i32) (param $y i32) (result i32)
+ // (loop
+ // (if (i32.eq (get_local $x) (get_local $y))
+ // (then (return (i32.const 0)))
+ // (else (if (i32.eq (get_local $x) (i32.const 0))
+ // (return (i32.const 1)))))
+ // (set_local $x (i32.sub (get_local $x) (i32.const 1)))
+ // (br 0)
+ // )
+ // )
+ // )
+ Vector<uint8_t> vector = {
+ 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x87, 0x80, 0x80,
+ 0x00, 0x01, 0x40, 0x02, 0x01, 0x01, 0x01, 0x01, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x82, 0x80, 0x80, 0x00, 0x01, 0x00, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x91, 0x80,
+ 0x80, 0x00, 0x01, 0x00, 0x0e, 0x64, 0x75, 0x6d, 0x62, 0x2d, 0x6c, 0x65, 0x73, 0x73, 0x2d, 0x74,
+ 0x68, 0x61, 0x6e, 0x04, 0x63, 0x6f, 0x64, 0x65, 0xaa, 0x80, 0x80, 0x00, 0x01, 0xa5, 0x80, 0x80,
+ 0x00, 0x00, 0x02, 0x14, 0x00, 0x14, 0x01, 0x4d, 0x03, 0x10, 0x00, 0x09, 0x01, 0x04, 0x14, 0x00,
+ 0x10, 0x00, 0x4d, 0x03, 0x10, 0x01, 0x09, 0x01, 0x0f, 0x0f, 0x14, 0x00, 0x10, 0x01, 0x41, 0x15,
+ 0x00, 0x06, 0x00, 0x00, 0x0f, 0x0f
+ };
+
+ Plan plan(*vm, vector);
+ if (plan.result.size() != 1 || !plan.result[0]) {
+ dataLogLn("Module failed to compile correctly.");
+ CRASH();
+ }
+
+ // Test this doesn't crash.
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 0);
+ }
+
+ {
+ // Generated from:
+ // (module
+ // (func "dumb-less-than" (param $x i32) (param $y i32) (result i32)
+ // (loop
+ // (block
+ // (block
+ // (br_if 0 (i32.eq (get_local $x) (i32.const 0)))
+ // (br 1)
+ // )
+ // (return (i32.const 1))
+ // )
+ // (block
+ // (block
+ // (br_if 0 (i32.eq (get_local $x) (get_local $y)))
+ // (br 1)
+ // )
+ // (return (i32.const 0))
+ // )
+ // (set_local $x (i32.sub (get_local $x) (i32.const 1)))
+ // (br 0)
+ // )
+ // )
+ // )
+ Vector<uint8_t> vector = {
+ 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x87, 0x80, 0x80,
+ 0x00, 0x01, 0x40, 0x02, 0x01, 0x01, 0x01, 0x01, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x82, 0x80, 0x80, 0x00, 0x01, 0x00, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x91, 0x80,
+ 0x80, 0x00, 0x01, 0x00, 0x0e, 0x64, 0x75, 0x6d, 0x62, 0x2d, 0x6c, 0x65, 0x73, 0x73, 0x2d, 0x74,
+ 0x68, 0x61, 0x6e, 0x04, 0x63, 0x6f, 0x64, 0x65, 0xb9, 0x80, 0x80, 0x00, 0x01, 0xb4, 0x80, 0x80,
+ 0x00, 0x00, 0x02, 0x01, 0x01, 0x14, 0x00, 0x14, 0x01, 0x4d, 0x07, 0x00, 0x00, 0x06, 0x00, 0x01,
+ 0x0f, 0x10, 0x00, 0x09, 0x01, 0x0f, 0x01, 0x01, 0x14, 0x00, 0x10, 0x00, 0x4d, 0x07, 0x00, 0x00,
+ 0x06, 0x00, 0x01, 0x0f, 0x10, 0x01, 0x09, 0x01, 0x0f, 0x14, 0x00, 0x10, 0x01, 0x41, 0x15, 0x00,
+ 0x06, 0x00, 0x00, 0x0f, 0x0f
+ };
+
+ Plan plan(*vm, vector);
+ if (plan.result.size() != 1 || !plan.result[0]) {
+ dataLogLn("Module failed to compile correctly.");
+ CRASH();
+ }
+
+ // Test this doesn't crash.
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
+ CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 0);
+ }
+
+ {
// Generated from: (module (func "return-i32" (result i32) (return (i32.const 5))) )
Vector<uint8_t> vector = {
0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x85, 0x80, 0x80,
Modified: trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.cpp (205768 => 205769)
--- trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.cpp 2016-09-09 21:29:47 UTC (rev 205768)
+++ trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.cpp 2016-09-09 21:30:51 UTC (rev 205769)
@@ -39,6 +39,12 @@
#include "WASMFunctionParser.h"
#include <wtf/Optional.h>
+void dumpProcedure(void* ptr)
+{
+ JSC::B3::Procedure* proc = static_cast<JSC::B3::Procedure*>(ptr);
+ proc->dump(WTF::dataFile());
+}
+
namespace JSC { namespace WASM {
namespace {
@@ -71,8 +77,13 @@
private:
class LazyBlock {
public:
- explicit operator bool() { return !!m_block; }
+ LazyBlock(BasicBlock* block)
+ : m_block(block)
+ {
+ }
+ explicit operator bool() const { return !!m_block; }
+
BasicBlock* get(Procedure& proc)
{
if (!m_block)
@@ -92,9 +103,11 @@
BasicBlock* m_block { nullptr };
};
+public:
struct ControlData {
- ControlData(Optional<Vector<Variable*>>&& stack, BasicBlock* loopTarget = nullptr)
- : loopTarget(loopTarget)
+ ControlData(Optional<Vector<Variable*>>&& stack, BasicBlock* special = nullptr, BasicBlock* continuation = nullptr)
+ : continuation(continuation)
+ , special(special)
, stack(stack)
{
}
@@ -101,32 +114,52 @@
void dump(PrintStream& out) const
{
- out.print("Continuation: ", continuation, ", Target: ");
- if (loopTarget)
- out.print(*loopTarget);
+ switch (type()) {
+ case BlockType::If:
+ out.print("If: ");
+ break;
+ case BlockType::Block:
+ out.print("Block: ");
+ break;
+ case BlockType::Loop:
+ out.print("Loop: ");
+ break;
+ }
+ out.print("Continuation: ", continuation, ", Special: ");
+ if (special)
+ out.print(*special);
else
- out.print(continuation);
+ out.print("None");
}
+ BlockType type() const
+ {
+ if (!special)
+ return BlockType::Block;
+ if (continuation)
+ return BlockType::If;
+ return BlockType::Loop;
+ }
+
BasicBlock* targetBlockForBranch(Procedure& proc)
{
- if (loopTarget)
- return loopTarget;
+ if (special)
+ return special;
return continuation.get(proc);
}
- bool isLoop() { return !!loopTarget; }
-
+ private:
+ friend class B3IRGenerator;
// We use a LazyBlock for the continuation since B3::validate does not like orphaned blocks. Note,
// it's possible to create an orphaned block by doing something like (block (return (...))). In
// that example, if we eagerly allocate a BasicBlock for the continuation it will never be reachable.
LazyBlock continuation;
- BasicBlock* loopTarget;
+ BasicBlock* special;
Optional<Vector<Variable*>> stack;
};
-public:
typedef Value* ExpressionType;
+ typedef ControlData ControlType;
static constexpr ExpressionType emptyExpression = nullptr;
B3IRGenerator(Procedure&);
@@ -141,29 +174,26 @@
bool WARN_UNUSED_RETURN binaryOp(BinaryOpType, ExpressionType left, ExpressionType right, ExpressionType& result);
bool WARN_UNUSED_RETURN unaryOp(UnaryOpType, ExpressionType arg, ExpressionType& result);
- bool WARN_UNUSED_RETURN addBlock();
- bool WARN_UNUSED_RETURN addLoop();
- bool WARN_UNUSED_RETURN endBlock(Vector<ExpressionType, 1>& expressionStack);
+ ControlData WARN_UNUSED_RETURN addBlock();
+ ControlData WARN_UNUSED_RETURN addLoop();
+ ControlData WARN_UNUSED_RETURN addIf(ExpressionType condition);
+ bool WARN_UNUSED_RETURN addElse(ControlData&);
bool WARN_UNUSED_RETURN addReturn(const Vector<ExpressionType, 1>& returnValues);
- bool WARN_UNUSED_RETURN addBranch(ExpressionType condition, const Vector<ExpressionType, 1>& returnValues, uint32_t target);
+ bool WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const Vector<ExpressionType, 1>& returnValues);
+ bool WARN_UNUSED_RETURN endBlock(ControlData&, Vector<ExpressionType, 1>& expressionStack);
- void dumpGraphAndControlStack();
+ bool isContinuationReachable(ControlData&);
+ void dump(const Vector<ControlType>& controlStack, const Vector<ExpressionType, 1>& expressionStack);
+
private:
- ControlData& controlDataForLevel(unsigned);
void unify(Variable* target, const ExpressionType source);
Vector<Variable*> initializeIncommingTypes(BasicBlock*, const Vector<ExpressionType, 1>&);
void unifyValuesWithBlock(const Vector<ExpressionType, 1>& resultStack, Optional<Vector<Variable*>>& stack, BasicBlock* target);
-public:
- unsigned unreachable { 0 };
-
-private:
Procedure& m_proc;
BasicBlock* m_currentBlock;
- // This is a pair of the continuation and the types expected on the stack for that continuation.
- Vector<ControlData> m_controlStack;
Vector<Variable*> m_locals;
};
@@ -235,109 +265,59 @@
}
}
-bool B3IRGenerator::addBlock()
+B3IRGenerator::ControlData B3IRGenerator::addBlock()
{
- if (unreachable) {
- unreachable++;
- return true;
- }
-
- if (verbose) {
- dataLogLn("Adding block");
- dumpGraphAndControlStack();
- }
- m_controlStack.append(ControlData(Nullopt));
-
- return true;
+ return ControlData(Nullopt);
}
-bool B3IRGenerator::addLoop()
+B3IRGenerator::ControlData B3IRGenerator::addLoop()
{
- if (unreachable) {
- unreachable++;
- return true;
- }
-
- if (verbose) {
- dataLogLn("Adding loop");
- dumpGraphAndControlStack();
- }
BasicBlock* body = m_proc.addBlock();
m_currentBlock->appendNewControlValue(m_proc, Jump, Origin(), body);
body->addPredecessor(m_currentBlock);
m_currentBlock = body;
- m_controlStack.append(ControlData(Vector<Variable*>(), body));
- return true;
+ return ControlData(Vector<Variable*>(), body);
}
-bool B3IRGenerator::endBlock(Vector<ExpressionType, 1>& expressionStack)
+B3IRGenerator::ControlData B3IRGenerator::addIf(ExpressionType condition)
{
- if (unreachable > 1) {
- unreachable--;
- return true;
- }
+ // FIXME: This needs to do some kind of stack passing.
- if (verbose) {
- dataLogLn("Falling out of block");
- dumpGraphAndControlStack();
- }
- // This means that we are exiting the function.
- if (!m_controlStack.size()) {
- // FIXME: Should this require the stack is empty? It's not clear from the current spec.
- return !expressionStack.size();
- }
+ BasicBlock* taken = m_proc.addBlock();
+ BasicBlock* notTaken = m_proc.addBlock();
+ BasicBlock* continuation = m_proc.addBlock();
- ControlData data = ""
- if (unreachable) {
- // If nothing targets the continuation of the current block then we don't want to create
- // an orphaned BasicBlock since it can't be reached by fallthrough.
- if (data.continuation) {
- m_currentBlock = data.continuation.get(m_proc);
- unreachable--;
- }
- return true;
- }
+ m_currentBlock->appendNew<Value>(m_proc, B3::Branch, Origin(), condition);
+ m_currentBlock->setSuccessors(FrequentedBlock(taken), FrequentedBlock(notTaken));
+ taken->addPredecessor(m_currentBlock);
+ notTaken->addPredecessor(m_currentBlock);
- BasicBlock* continuation = data.continuation.get(m_proc);
- unifyValuesWithBlock(expressionStack, data.stack, continuation);
- m_currentBlock->appendNewControlValue(m_proc, Jump, Origin(), continuation);
- continuation->addPredecessor(m_currentBlock);
- m_currentBlock = continuation;
+ m_currentBlock = taken;
+ return ControlData(Nullopt, notTaken, continuation);
+}
+
+bool B3IRGenerator::addElse(ControlData& data)
+{
+ ASSERT(data.continuation);
+ m_currentBlock = data.special;
+ // Clear the special pointer so that when we parse the end we don't think that this block is an if block.
+ data.special = nullptr;
+ ASSERT(data.type() == BlockType::Block);
return true;
}
bool B3IRGenerator::addReturn(const Vector<ExpressionType, 1>& returnValues)
{
- if (unreachable)
- return true;
-
- if (verbose) {
- dataLogLn("Adding return");
- dumpGraphAndControlStack();
- }
-
ASSERT(returnValues.size() <= 1);
if (returnValues.size())
m_currentBlock->appendNewControlValue(m_proc, B3::Return, Origin(), returnValues[0]);
else
m_currentBlock->appendNewControlValue(m_proc, B3::Return, Origin());
- unreachable = 1;
return true;
}
-bool B3IRGenerator::addBranch(ExpressionType condition, const Vector<ExpressionType, 1>& returnValues, uint32_t level)
+bool B3IRGenerator::addBranch(ControlData& data, ExpressionType condition, const Vector<ExpressionType, 1>& returnValues)
{
- if (unreachable)
- return true;
-
- ASSERT(level < m_controlStack.size());
- ControlData& data = ""
- if (verbose) {
- dataLogLn("Adding Branch from: ", *m_currentBlock, " targeting: ", level, " with data: ", data);
- dumpGraphAndControlStack();
- }
-
-
BasicBlock* target = data.targetBlockForBranch(m_proc);
unifyValuesWithBlock(returnValues, data.stack, target);
if (condition) {
@@ -350,12 +330,48 @@
} else {
m_currentBlock->appendNewControlValue(m_proc, Jump, Origin(), FrequentedBlock(target));
target->addPredecessor(m_currentBlock);
- unreachable = 1;
}
return true;
}
+bool B3IRGenerator::endBlock(ControlData& data, Vector<ExpressionType, 1>& expressionStack)
+{
+ if (!data.continuation)
+ return true;
+
+ BasicBlock* continuation = data.continuation.get(m_proc);
+ if (data.type() == BlockType::If) {
+ ASSERT(!data.special->size() && !data.special->successors().size());
+ // Since we don't have any else block we need to point the notTaken branch to the continuation.
+ data.special->appendNewControlValue(m_proc, Jump, Origin());
+ data.special->setSuccessors(FrequentedBlock(continuation));
+ continuation->addPredecessor(data.special);
+ }
+
+ unifyValuesWithBlock(expressionStack, data.stack, continuation);
+ m_currentBlock->appendNewControlValue(m_proc, Jump, Origin(), continuation);
+ continuation->addPredecessor(m_currentBlock);
+ m_currentBlock = continuation;
+ return true;
+}
+
+bool B3IRGenerator::isContinuationReachable(ControlData& data)
+{
+ // If nothing targets the continuation of the current block then we don't want to create
+ // an orphaned BasicBlock since it can't be reached by fallthrough.
+ if (!data.continuation)
+ return false;
+
+ m_currentBlock = data.continuation.get(m_proc);
+ if (data.type() == BlockType::If) {
+ data.special->appendNewControlValue(m_proc, Jump, Origin(), m_currentBlock);
+ m_currentBlock->addPredecessor(data.special);
+ }
+
+ return true;
+}
+
void B3IRGenerator::unify(Variable* variable, ExpressionType source)
{
m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), variable, source);
@@ -387,20 +403,18 @@
for (size_t i = 0; i < resultStack.size(); ++i)
unify(stack.value()[i], resultStack[i]);
}
-
-B3IRGenerator::ControlData& B3IRGenerator::controlDataForLevel(unsigned level)
-{
- return m_controlStack[m_controlStack.size() - 1 - level];
-}
-void B3IRGenerator::dumpGraphAndControlStack()
+void B3IRGenerator::dump(const Vector<ControlType>& controlStack, const Vector<ExpressionType, 1>& expressionStack)
{
dataLogLn("Processing Graph:");
dataLog(m_proc);
dataLogLn("With current block:", *m_currentBlock);
- dataLogLn("With Control Stack:");
- for (unsigned i = 0; i < m_controlStack.size(); ++i)
- dataLogLn("[", i, "] ", m_controlStack[i]);
+ dataLogLn("Control stack:");
+ for (const ControlType& data : controlStack)
+ dataLogLn(" ", data);
+ dataLogLn("ExpressionStack:");
+ for (const ExpressionType& _expression_ : expressionStack)
+ dataLogLn(" ", *_expression_);
dataLogLn("\n");
}
@@ -414,6 +428,7 @@
if (!parser.parse())
RELEASE_ASSERT_NOT_REACHED();
+ procedure.resetReachability();
validate(procedure, "After parsing:\n");
fixSSA(procedure);