From a28343a33ed28b4d5c83c37e350aceaf09b5246f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 5 Dec 2019 13:09:21 -0600 Subject: Add string parameter to WASM_UNREACHABLE (#2499) This works more like llvm's unreachable handler in that is preserves information even in release builds. --- src/abi/stack.h | 2 +- src/asm2wasm.h | 8 +- src/asmjs/asm_v_wasm.cpp | 10 +-- src/binaryen-c.cpp | 8 +- src/cfg/cfg-traversal.h | 2 +- src/compiler-support.h | 23 +----- src/dataflow/graph.h | 4 +- src/dataflow/node.h | 2 +- src/dataflow/utils.h | 2 - src/ir/ReFinalize.cpp | 16 ++-- src/ir/abstract.h | 10 +-- src/ir/bits.h | 4 +- src/ir/branch-utils.h | 4 +- src/ir/cost.h | 4 +- src/ir/utils.h | 14 ++-- src/literal.h | 6 +- src/parsing.h | 2 +- src/pass.h | 8 +- src/passes/AlignmentLowering.cpp | 8 +- src/passes/Asyncify.cpp | 2 +- src/passes/ConstHoisting.cpp | 5 +- src/passes/DataFlowOpts.cpp | 11 +-- src/passes/DeadCodeElimination.cpp | 4 +- src/passes/Flatten.cpp | 2 +- src/passes/FuncCastEmulation.cpp | 18 ++--- src/passes/I64ToI32Lowering.cpp | 12 +-- src/passes/InstrumentLocals.cpp | 5 +- src/passes/OptimizeInstructions.cpp | 4 +- src/passes/Print.cpp | 12 +-- src/passes/ReReloop.cpp | 4 +- src/passes/RemoveUnusedNames.cpp | 2 +- src/passes/Souperify.cpp | 17 ++--- src/passes/SpillPointers.cpp | 4 +- src/passes/TrapMode.cpp | 2 +- src/shell-interface.h | 2 +- src/support/CMakeLists.txt | 1 + src/support/bits.cpp | 3 +- src/support/utilities.cpp | 45 +++++++++++ src/support/utilities.h | 14 ++++ src/tools/fuzzing.h | 74 +++++++++--------- src/tools/spec-wrapper.h | 2 +- src/tools/wasm-ctor-eval.cpp | 3 +- src/tools/wasm-reduce.cpp | 18 ++--- src/tools/wasm-shell.cpp | 3 +- src/wasm-binary.h | 2 +- src/wasm-features.h | 3 +- src/wasm-interpreter.h | 146 +++++++++++++++++++----------------- src/wasm-traversal.h | 10 +-- src/wasm/literal.cpp | 138 +++++++++++++++++----------------- src/wasm/wasm-binary.cpp | 15 ++-- src/wasm/wasm-emscripten.cpp | 2 +- src/wasm/wasm-stack.cpp | 46 ++++++------ src/wasm/wasm-type.cpp | 10 +-- src/wasm/wasm-validator.cpp | 10 +-- src/wasm/wasm.cpp | 14 ++-- src/wasm2js.h | 68 +++++++---------- 56 files changed, 450 insertions(+), 420 deletions(-) create mode 100644 src/support/utilities.cpp (limited to 'src') diff --git a/src/abi/stack.h b/src/abi/stack.h index 22cd8ba3c..68ac7f08a 100644 --- a/src/abi/stack.h +++ b/src/abi/stack.h @@ -93,7 +93,7 @@ getStackSpace(Index local, Function* func, Index size, Module& wasm) { builder.makeLocalGet(local, PointerType), builder.makeConst(Literal(int32_t(size)))); } else { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unhandled PointerType"); } block->list.push_back(builder.makeGlobalSet(stackPointer->name, added)); auto makeStackRestore = [&]() { diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 24e9ddc76..048d363ef 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -1548,7 +1548,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) { break; } default: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } } else { assert(old == none); @@ -2060,7 +2060,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { ret->op = NegFloat32; ret->type = Type::f32; } else { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected asm type"); } return ret; } else if (ast[1] == B_NOT) { @@ -2195,7 +2195,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { ret->type = value->type; return ret; } else { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } } if (name == Math_floor || name == Math_sqrt || name == Math_ceil) { @@ -2328,7 +2328,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { process(ast[2][2]), asmToWasmType(view.type)); } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected atomic op"); } bool tableCall = false; if (wasmOnly) { diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp index 143d6667e..2fba0520a 100644 --- a/src/asmjs/asm_v_wasm.cpp +++ b/src/asmjs/asm_v_wasm.cpp @@ -38,7 +38,7 @@ Type asmToWasmType(AsmType asmType) { case ASM_INT32X4: return Type::v128; } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid type"); } AsmType wasmToAsmType(Type type) { @@ -60,9 +60,9 @@ AsmType wasmToAsmType(Type type) { case none: return ASM_NONE; case unreachable: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid type"); } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid type"); } char getSig(Type type) { @@ -84,9 +84,9 @@ char getSig(Type type) { case none: return 'v'; case unreachable: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid type"); } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid type"); } std::string getSig(const FunctionType* type) { diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 697d9a1e3..87e1fdb0b 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -74,7 +74,7 @@ BinaryenLiteral toBinaryenLiteral(Literal x) { case Type::exnref: // there's no exnref literals case Type::none: case Type::unreachable: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } return ret; } @@ -95,9 +95,9 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) { case Type::exnref: // there's no exnref literals case Type::none: case Type::unreachable: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid type"); } // Mutexes (global for now; in theory if multiple modules @@ -216,7 +216,7 @@ void printArg(std::ostream& setup, std::ostream& out, BinaryenLiteral arg) { case Type::exnref: // there's no exnref literals case Type::none: case Type::unreachable: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } } diff --git a/src/cfg/cfg-traversal.h b/src/cfg/cfg-traversal.h index 2e4c45950..8693831ad 100644 --- a/src/cfg/cfg-traversal.h +++ b/src/cfg/cfg-traversal.h @@ -365,7 +365,7 @@ private: return; } } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("not found"); } }; diff --git a/src/compiler-support.h b/src/compiler-support.h index c75676d54..5f3edacea 100644 --- a/src/compiler-support.h +++ b/src/compiler-support.h @@ -25,27 +25,10 @@ #define __has_builtin(x) 0 #endif -// If control flow reaches the point of the WASM_UNREACHABLE(), the program is -// undefined. -#if __has_builtin(__builtin_unreachable) && defined(NDEBUG) -#define WASM_UNREACHABLE() __builtin_unreachable() +#if __has_builtin(__builtin_unreachable) +#define WASM_BUILTIN_UNREACHABLE __builtin_unreachable() #elif defined(_MSC_VER) -#define WASM_UNREACHABLE() __assume(false) -#elif __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) -#include "sanitizer/common_interface_defs.h" -#define WASM_UNREACHABLE() \ - do { \ - __sanitizer_print_stack_trace(); \ - __builtin_trap(); \ - } while (0) -#else -#include -#include -#define WASM_UNREACHABLE() \ - do { \ - assert(false); \ - abort(); \ - } while (0) +#define WASM_BUILTIN_UNREACHABLE __assume(false) #endif #ifdef __GNUC__ diff --git a/src/dataflow/graph.h b/src/dataflow/graph.h index 2d9b87873..873c4f218 100644 --- a/src/dataflow/graph.h +++ b/src/dataflow/graph.h @@ -547,7 +547,7 @@ struct Graph : public UnifiedExpressionVisitor { opposite = LeUInt64; break; default: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected op"); } auto* ret = visitBinary(builder.makeBinary(opposite, curr->right, curr->left)); @@ -783,7 +783,7 @@ struct Graph : public UnifiedExpressionVisitor { // variable value. return Builder(*module).makeCall(FAKE_CALL, {}, node->wasmType); } else { - WASM_UNREACHABLE(); // TODO + WASM_UNREACHABLE("unexpected node type"); // TODO } } diff --git a/src/dataflow/node.h b/src/dataflow/node.h index 2966034ac..612a2f613 100644 --- a/src/dataflow/node.h +++ b/src/dataflow/node.h @@ -165,7 +165,7 @@ struct Node { case Bad: return unreachable; default: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid node type"); } } diff --git a/src/dataflow/utils.h b/src/dataflow/utils.h index 2d32dbeac..436ccc4d8 100644 --- a/src/dataflow/utils.h +++ b/src/dataflow/utils.h @@ -67,8 +67,6 @@ inline std::ostream& dump(Node* node, std::ostream& o, size_t indent = 0) { case Node::Type::Bad: o << "bad"; break; - default: - WASM_UNREACHABLE(); } if (!node->values.empty()) { o << '\n'; diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index bc5522c10..a8054d261 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -151,13 +151,15 @@ void ReFinalize::visitFunction(Function* curr) { } } -void ReFinalize::visitFunctionType(FunctionType* curr) { WASM_UNREACHABLE(); } -void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE(); } -void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE(); } -void ReFinalize::visitTable(Table* curr) { WASM_UNREACHABLE(); } -void ReFinalize::visitMemory(Memory* curr) { WASM_UNREACHABLE(); } -void ReFinalize::visitEvent(Event* curr) { WASM_UNREACHABLE(); } -void ReFinalize::visitModule(Module* curr) { WASM_UNREACHABLE(); } +void ReFinalize::visitFunctionType(FunctionType* curr) { + WASM_UNREACHABLE("unimp"); +} +void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); } +void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); } +void ReFinalize::visitTable(Table* curr) { WASM_UNREACHABLE("unimp"); } +void ReFinalize::visitMemory(Memory* curr) { WASM_UNREACHABLE("unimp"); } +void ReFinalize::visitEvent(Event* curr) { WASM_UNREACHABLE("unimp"); } +void ReFinalize::visitModule(Module* curr) { WASM_UNREACHABLE("unimp"); } void ReFinalize::updateBreakValueType(Name name, Type type) { if (type != unreachable || breakValues.count(name) == 0) { diff --git a/src/ir/abstract.h b/src/ir/abstract.h index 2653218b0..384f8b555 100644 --- a/src/ir/abstract.h +++ b/src/ir/abstract.h @@ -78,8 +78,7 @@ inline UnaryOp getUnary(Type type, Op op) { break; } case v128: { - assert(false && "v128 not implemented yet"); - WASM_UNREACHABLE(); + WASM_UNREACHABLE("v128 not implemented yet"); } case anyref: // there's no unary instructions for anyref case exnref: // there's no unary instructions for exnref @@ -88,7 +87,7 @@ inline UnaryOp getUnary(Type type, Op op) { return InvalidUnary; } } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid type"); } inline BinaryOp getBinary(Type type, Op op) { @@ -210,8 +209,7 @@ inline BinaryOp getBinary(Type type, Op op) { break; } case v128: { - assert(false && "v128 not implemented yet"); - WASM_UNREACHABLE(); + WASM_UNREACHABLE("v128 not implemented yet"); } case anyref: // there's no binary instructions for anyref case exnref: // there's no binary instructions for exnref @@ -220,7 +218,7 @@ inline BinaryOp getBinary(Type type, Op op) { return InvalidBinary; } } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid type"); } } // namespace Abstract diff --git a/src/ir/bits.h b/src/ir/bits.h index faae4c723..cbac70d77 100644 --- a/src/ir/bits.h +++ b/src/ir/bits.h @@ -60,7 +60,7 @@ struct Bits { } else if (type == i64) { return amount & 63; } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } static Index getEffectiveShifts(Expression* expr) { @@ -70,7 +70,7 @@ struct Bits { } else if (amount->type == i64) { return getEffectiveShifts(amount->value.geti64(), i64); } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } static Expression* makeSignExt(Expression* value, Index bytes, Module& wasm) { diff --git a/src/ir/branch-utils.h b/src/ir/branch-utils.h index 53279eee6..a22301e54 100644 --- a/src/ir/branch-utils.h +++ b/src/ir/branch-utils.h @@ -49,7 +49,7 @@ inline bool isBranchReachable(Expression* expr) { } else if (auto* br = expr->dynCast()) { return isBranchReachable(br); } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected expression type"); } inline std::set getUniqueTargets(Break* br) { return {br->name}; } @@ -90,7 +90,7 @@ inline bool replacePossibleTarget(Expression* branch, Name from, Name to) { worked = true; } } else { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected expression type"); } return worked; } diff --git a/src/ir/cost.h b/src/ir/cost.h index 60eb84b08..79be195f7 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -188,7 +188,7 @@ struct CostAnalyzer : public Visitor { case WidenHighUVecI16x8ToVecI32x4: return 1; case InvalidUnary: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid unary op"); } return ret + visit(curr->value); } @@ -709,7 +709,7 @@ struct CostAnalyzer : public Visitor { ret = 1; break; case InvalidBinary: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid binary op"); } return ret + visit(curr->left) + visit(curr->right); } diff --git a/src/ir/utils.h b/src/ir/utils.h index e8c5b78b3..722277bc3 100644 --- a/src/ir/utils.h +++ b/src/ir/utils.h @@ -220,13 +220,13 @@ struct ReFinalizeNode : public OverriddenVisitor { void visitPush(Push* curr) { curr->finalize(); } void visitPop(Pop* curr) { curr->finalize(); } - void visitFunctionType(FunctionType* curr) { WASM_UNREACHABLE(); } - void visitExport(Export* curr) { WASM_UNREACHABLE(); } - void visitGlobal(Global* curr) { WASM_UNREACHABLE(); } - void visitTable(Table* curr) { WASM_UNREACHABLE(); } - void visitMemory(Memory* curr) { WASM_UNREACHABLE(); } - void visitEvent(Event* curr) { WASM_UNREACHABLE(); } - void visitModule(Module* curr) { WASM_UNREACHABLE(); } + void visitFunctionType(FunctionType* curr) { WASM_UNREACHABLE("unimp"); } + void visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); } + void visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); } + void visitTable(Table* curr) { WASM_UNREACHABLE("unimp"); } + void visitMemory(Memory* curr) { WASM_UNREACHABLE("unimp"); } + void visitEvent(Event* curr) { WASM_UNREACHABLE("unimp"); } + void visitModule(Module* curr) { WASM_UNREACHABLE("unimp"); } // given a stack of nested expressions, update them all from child to parent static void updateStack(ExpressionStack& expressionStack) { diff --git a/src/literal.h b/src/literal.h index 1106d1c27..c77c21947 100644 --- a/src/literal.h +++ b/src/literal.h @@ -84,9 +84,9 @@ public: case Type::exnref: // there's no exnref literals case none: case unreachable: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } inline static Literal makeZero(Type type) { return makeFromInt32(0, type); } @@ -467,7 +467,7 @@ template<> struct less { case wasm::Type::unreachable: return false; } - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected type"); } }; } // namespace std diff --git a/src/parsing.h b/src/parsing.h index 2591c4357..7017fdb0f 100644 --- a/src/parsing.h +++ b/src/parsing.h @@ -265,7 +265,7 @@ parseConst(cashew::IString s, Type type, MixedArena& allocator) { case v128: case anyref: // there's no anyref.const case exnref: // there's no exnref.const - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected const type"); case none: case unreachable: { return nullptr; diff --git a/src/pass.h b/src/pass.h index 46b603f00..760feb7c0 100644 --- a/src/pass.h +++ b/src/pass.h @@ -254,13 +254,15 @@ public: virtual void prepareToRun(PassRunner* runner, Module* module) {} // Implement this with code to run the pass on the whole module - virtual void run(PassRunner* runner, Module* module) { WASM_UNREACHABLE(); } + virtual void run(PassRunner* runner, Module* module) { + WASM_UNREACHABLE("unimplemented"); + } // Implement this with code to run the pass on a single function, for // a function-parallel pass virtual void runOnFunction(PassRunner* runner, Module* module, Function* function) { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unimplemented"); } // Function parallelism. By default, passes are not run in parallel, but you @@ -285,7 +287,7 @@ public: // This method is used to create instances per function for a // function-parallel pass. You may need to override this if you subclass a // Walker, as otherwise this will create the parent class. - virtual Pass* create() { WASM_UNREACHABLE(); } + virtual Pass* create() { WASM_UNREACHABLE("unimplenented"); } // Whether this pass modifies the Binaryen IR in the module. This is true for // most passes, except for passes that have no side effects, or passes that diff --git a/src/passes/AlignmentLowering.cpp b/src/passes/AlignmentLowering.cpp index 05ec2892f..d659fcb69 100644 --- a/src/passes/AlignmentLowering.cpp +++ b/src/passes/AlignmentLowering.cpp @@ -103,10 +103,10 @@ struct AlignmentLowering : public WalkerPass> { i32), builder.makeConst(Literal(int32_t(16))))); } else { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid alignment"); } } else { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid size"); } replaceCurrent( builder.makeBlock({builder.makeLocalSet(temp, curr->ptr), ret})); @@ -199,10 +199,10 @@ struct AlignmentLowering : public WalkerPass> { builder.makeConst(Literal(int32_t(16)))), i32)); } else { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid alignment"); } } else { - WASM_UNREACHABLE(); + WASM_UNREACHABLE("invalid size"); } block->finalize(); replaceCurrent(block); diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp index 818d61907..d92181639 100644 --- a/src/passes/Asyncify.cpp +++ b/src/passes/Asyncify.cpp @@ -841,7 +841,7 @@ private: // the state, so there should be nothing that can reach here - add it // earlier as necessary. // std::cout << *curr << '\n'; - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected expression type"); } // Possibly skip some code, if rewinding. diff --git a/src/passes/ConstHoisting.cpp b/src/passes/ConstHoisting.cpp index 08fede1df..9eb853878 100644 --- a/src/passes/ConstHoisting.cpp +++ b/src/passes/ConstHoisting.cpp @@ -97,9 +97,8 @@ private: return false; } case none: - case unreachable: { - WASM_UNREACHABLE(); - } + case unreachable: + WASM_UNREACHABLE("unexpected type"); } // compute the benefit, of replacing the uses with // one use + a set and then a get for each use diff --git a/src/passes/DataFlowOpts.cpp b/src/passes/DataFlowOpts.cpp index dc8f6ca94..d4a3cc087 100644 --- a/src/passes/DataFlowOpts.cpp +++ b/src/passes/DataFlowOpts.cpp @@ -215,7 +215,7 @@ struct DataFlowOpts : public WalkerPass> { break; } default: - WASM_UNREACHABLE(); + WASM_UNREACHABLE("unexpected dataflow node type"); } } // No one is a user of this node after we replaced all the uses. @@ -234,9 +234,8 @@ struct DataFlowOpts : public WalkerPass> { return &binary->left; } else if (index == 1) { return &binary->right; - } else { - WASM_UNREACHABLE(); } + WASM_UNREACHABLE("unexpected index"); } else if (auto* select = expr->dynCast