Commit 0f54b832 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Turn out-of-line traps into stub calls.

This avoids embedding {RelocInfo::CODE_TARGET} addresses into WasmCode
by calling a WebAssembly runtime stub instead. The stubs themselves are
not yet independent of the Isolate, but will be made so soon.

Note that this also introduces a proper {compiler::TrapId} to avoid
accidental parameter type confusion with {TrapIf} and {TrapUnless}
operators.

R=clemensh@chromium.org
BUG=v8:7424

Change-Id: I32ef5a1253f336fc739d2192247826e9458456df
Reviewed-on: https://chromium-review.googlesource.com/1086937Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53557}
parent 86a27207
......@@ -323,6 +323,14 @@ bool Builtins::IsIsolateIndependent(int index) {
// TODO(mstarzinger): Will be made Isolate independent once the CEntry stub
// is loaded from the instance.
case kWasmStackGuard:
case kThrowWasmTrapUnreachable:
case kThrowWasmTrapMemOutOfBounds:
case kThrowWasmTrapDivByZero:
case kThrowWasmTrapDivUnrepresentable:
case kThrowWasmTrapRemByZero:
case kThrowWasmTrapFloatUnrepresentable:
case kThrowWasmTrapFuncInvalid:
case kThrowWasmTrapFuncSigMismatch:
return false;
default:
return true;
......
......@@ -2792,15 +2792,14 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
void Generate() final {
ArmOperandConverter i(gen_, instr_);
Builtins::Name trap_id =
static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
private:
void GenerateCallToTrap(Builtins::Name trap_id) {
if (trap_id == Builtins::builtin_count) {
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
// We use the context register as the scratch register, because we do
......@@ -2816,8 +2815,9 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Ret();
} else {
gen_->AssembleSourcePosition(instr_);
__ Call(__ isolate()->builtins()->builtin_handle(trap_id),
RelocInfo::CODE_TARGET);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
......
......@@ -2256,14 +2256,14 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
: OutOfLineCode(gen), instr_(instr), gen_(gen) {}
void Generate() final {
Arm64OperandConverter i(gen_, instr_);
Builtins::Name trap_id =
static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
private:
void GenerateCallToTrap(Builtins::Name trap_id) {
if (trap_id == Builtins::builtin_count) {
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
__ CallCFunction(
......@@ -2277,8 +2277,9 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Ret();
} else {
gen_->AssembleSourcePosition(instr_);
__ Call(__ isolate()->builtins()->builtin_handle(trap_id),
RelocInfo::CODE_TARGET);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
......
......@@ -41,6 +41,25 @@ std::ostream& operator<<(std::ostream& os, IsSafetyCheck is_safety_check) {
UNREACHABLE();
}
std::ostream& operator<<(std::ostream& os, TrapId trap_id) {
switch (trap_id) {
#define TRAP_CASE(Name) \
case TrapId::k##Name: \
return os << #Name;
FOREACH_WASM_TRAPREASON(TRAP_CASE)
#undef TRAP_CASE
case TrapId::kInvalid:
return os << "Invalid";
}
UNREACHABLE();
}
TrapId TrapIdOf(const Operator* const op) {
DCHECK(op->opcode() == IrOpcode::kTrapIf ||
op->opcode() == IrOpcode::kTrapUnless);
return OpParameter<TrapId>(op);
}
std::ostream& operator<<(std::ostream& os, BranchOperatorInfo info) {
return os << info.hint << "|" << info.is_safety_check;
}
......@@ -742,35 +761,33 @@ struct CommonOperatorGlobalCache final {
CACHED_DEOPTIMIZE_UNLESS_LIST(CACHED_DEOPTIMIZE_UNLESS)
#undef CACHED_DEOPTIMIZE_UNLESS
template <int32_t trap_id>
struct TrapIfOperator final : public Operator1<int32_t> {
template <TrapId trap_id>
struct TrapIfOperator final : public Operator1<TrapId> {
TrapIfOperator()
: Operator1<int32_t>( // --
: Operator1<TrapId>( // --
IrOpcode::kTrapIf, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties
"TrapIf", // name
1, 1, 1, 0, 0, 1, // counts
trap_id) {} // parameter
};
#define CACHED_TRAP_IF(Trap) \
TrapIfOperator<static_cast<int32_t>(Builtins::kThrowWasm##Trap)> \
kTrapIf##Trap##Operator;
#define CACHED_TRAP_IF(Trap) \
TrapIfOperator<TrapId::k##Trap> kTrapIf##Trap##Operator;
CACHED_TRAP_IF_LIST(CACHED_TRAP_IF)
#undef CACHED_TRAP_IF
template <int32_t trap_id>
struct TrapUnlessOperator final : public Operator1<int32_t> {
template <TrapId trap_id>
struct TrapUnlessOperator final : public Operator1<TrapId> {
TrapUnlessOperator()
: Operator1<int32_t>( // --
: Operator1<TrapId>( // --
IrOpcode::kTrapUnless, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties
"TrapUnless", // name
1, 1, 1, 0, 0, 1, // counts
trap_id) {} // parameter
};
#define CACHED_TRAP_UNLESS(Trap) \
TrapUnlessOperator<static_cast<int32_t>(Builtins::kThrowWasm##Trap)> \
kTrapUnless##Trap##Operator;
#define CACHED_TRAP_UNLESS(Trap) \
TrapUnlessOperator<TrapId::k##Trap> kTrapUnless##Trap##Operator;
CACHED_TRAP_UNLESS_LIST(CACHED_TRAP_UNLESS)
#undef CACHED_TRAP_UNLESS
......@@ -973,10 +990,10 @@ const Operator* CommonOperatorBuilder::DeoptimizeUnless(
parameter); // parameter
}
const Operator* CommonOperatorBuilder::TrapIf(int32_t trap_id) {
const Operator* CommonOperatorBuilder::TrapIf(TrapId trap_id) {
switch (trap_id) {
#define CACHED_TRAP_IF(Trap) \
case Builtins::kThrowWasm##Trap: \
#define CACHED_TRAP_IF(Trap) \
case TrapId::k##Trap: \
return &cache_.kTrapIf##Trap##Operator;
CACHED_TRAP_IF_LIST(CACHED_TRAP_IF)
#undef CACHED_TRAP_IF
......@@ -984,7 +1001,7 @@ const Operator* CommonOperatorBuilder::TrapIf(int32_t trap_id) {
break;
}
// Uncached
return new (zone()) Operator1<int>( // --
return new (zone()) Operator1<TrapId>( // --
IrOpcode::kTrapIf, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties
"TrapIf", // name
......@@ -992,10 +1009,10 @@ const Operator* CommonOperatorBuilder::TrapIf(int32_t trap_id) {
trap_id); // parameter
}
const Operator* CommonOperatorBuilder::TrapUnless(int32_t trap_id) {
const Operator* CommonOperatorBuilder::TrapUnless(TrapId trap_id) {
switch (trap_id) {
#define CACHED_TRAP_UNLESS(Trap) \
case Builtins::kThrowWasm##Trap: \
#define CACHED_TRAP_UNLESS(Trap) \
case TrapId::k##Trap: \
return &cache_.kTrapUnless##Trap##Operator;
CACHED_TRAP_UNLESS_LIST(CACHED_TRAP_UNLESS)
#undef CACHED_TRAP_UNLESS
......@@ -1003,7 +1020,7 @@ const Operator* CommonOperatorBuilder::TrapUnless(int32_t trap_id) {
break;
}
// Uncached
return new (zone()) Operator1<int>( // --
return new (zone()) Operator1<TrapId>( // --
IrOpcode::kTrapUnless, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties
"TrapUnless", // name
......
......@@ -59,6 +59,19 @@ inline size_t hash_value(IsSafetyCheck is_safety_check) {
return static_cast<size_t>(is_safety_check);
}
enum class TrapId : uint32_t {
#define DEF_ENUM(Name, ...) k##Name,
FOREACH_WASM_TRAPREASON(DEF_ENUM)
#undef DEF_ENUM
kInvalid
};
inline size_t hash_value(TrapId id) { return static_cast<uint32_t>(id); }
std::ostream& operator<<(std::ostream&, TrapId trap_id);
TrapId TrapIdOf(const Operator* const op);
struct BranchOperatorInfo {
BranchHint hint;
IsSafetyCheck is_safety_check;
......@@ -451,8 +464,8 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
const Operator* TrapIf(int32_t trap_id);
const Operator* TrapUnless(int32_t trap_id);
const Operator* TrapIf(TrapId trap_id);
const Operator* TrapUnless(TrapId trap_id);
const Operator* Return(int value_input_count = 1);
const Operator* Terminate();
......
......@@ -3481,15 +3481,14 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
void Generate() final {
IA32OperandConverter i(gen_, instr_);
Builtins::Name trap_id =
static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
private:
void GenerateCallToTrap(Builtins::Name trap_id) {
if (trap_id == Builtins::builtin_count) {
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
__ PrepareCallCFunction(0, esi);
......@@ -3502,8 +3501,9 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Ret(static_cast<int>(pop_size), ecx);
} else {
gen_->AssembleSourcePosition(instr_);
__ Call(__ isolate()->builtins()->builtin_handle(trap_id),
RelocInfo::CODE_TARGET);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
__ wasm_call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
......
......@@ -720,7 +720,8 @@ Instruction* InstructionSelector::EmitWithContinuation(
} else if (cont->IsSet()) {
continuation_outputs_.push_back(g.DefineAsRegister(cont->result()));
} else if (cont->IsTrap()) {
continuation_inputs_.push_back(g.UseImmediate(cont->trap_id()));
int trap_id = static_cast<int>(cont->trap_id());
continuation_inputs_.push_back(g.UseImmediate(trap_id));
} else {
DCHECK(cont->IsNone());
}
......@@ -1272,11 +1273,9 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kDeoptimizeUnless:
return VisitDeoptimizeUnless(node);
case IrOpcode::kTrapIf:
return VisitTrapIf(node, static_cast<Runtime::FunctionId>(
OpParameter<int32_t>(node->op())));
return VisitTrapIf(node, TrapIdOf(node->op()));
case IrOpcode::kTrapUnless:
return VisitTrapUnless(node, static_cast<Runtime::FunctionId>(
OpParameter<int32_t>(node->op())));
return VisitTrapUnless(node, TrapIdOf(node->op()));
case IrOpcode::kFrameState:
case IrOpcode::kStateValues:
case IrOpcode::kObjectState:
......@@ -2754,16 +2753,15 @@ void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
}
}
void InstructionSelector::VisitTrapIf(Node* node, Runtime::FunctionId func_id) {
void InstructionSelector::VisitTrapIf(Node* node, TrapId trap_id) {
FlagsContinuation cont =
FlagsContinuation::ForTrap(kNotEqual, func_id, node->InputAt(1));
FlagsContinuation::ForTrap(kNotEqual, trap_id, node->InputAt(1));
VisitWordCompareZero(node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitTrapUnless(Node* node,
Runtime::FunctionId func_id) {
void InstructionSelector::VisitTrapUnless(Node* node, TrapId trap_id) {
FlagsContinuation cont =
FlagsContinuation::ForTrap(kEqual, func_id, node->InputAt(1));
FlagsContinuation::ForTrap(kEqual, trap_id, node->InputAt(1));
VisitWordCompareZero(node, node->InputAt(0), &cont);
}
......
......@@ -76,8 +76,8 @@ class FlagsContinuation final {
}
// Creates a new flags continuation for a wasm trap.
static FlagsContinuation ForTrap(FlagsCondition condition,
Runtime::FunctionId trap_id, Node* result) {
static FlagsContinuation ForTrap(FlagsCondition condition, TrapId trap_id,
Node* result) {
return FlagsContinuation(condition, trap_id, result);
}
......@@ -118,7 +118,7 @@ class FlagsContinuation final {
DCHECK(IsSet());
return frame_state_or_result_;
}
Runtime::FunctionId trap_id() const {
TrapId trap_id() const {
DCHECK(IsTrap());
return trap_id_;
}
......@@ -210,8 +210,7 @@ class FlagsContinuation final {
DCHECK_NOT_NULL(result);
}
FlagsContinuation(FlagsCondition condition, Runtime::FunctionId trap_id,
Node* result)
FlagsContinuation(FlagsCondition condition, TrapId trap_id, Node* result)
: mode_(kFlags_trap),
condition_(condition),
frame_state_or_result_(result),
......@@ -228,7 +227,7 @@ class FlagsContinuation final {
// or mode_ == kFlags_set.
BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch*.
BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch*.
Runtime::FunctionId trap_id_; // Only valid if mode_ == kFlags_trap.
TrapId trap_id_; // Only valid if mode_ == kFlags_trap.
};
// This struct connects nodes of parameters which are going to be pushed on the
......@@ -567,8 +566,8 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
BasicBlock* handler = nullptr);
void VisitDeoptimizeIf(Node* node);
void VisitDeoptimizeUnless(Node* node);
void VisitTrapIf(Node* node, Runtime::FunctionId func_id);
void VisitTrapUnless(Node* node, Runtime::FunctionId func_id);
void VisitTrapIf(Node* node, TrapId trap_id);
void VisitTrapUnless(Node* node, TrapId trap_id);
void VisitTailCall(Node* call);
void VisitGoto(BasicBlock* target);
void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
......
......@@ -2952,15 +2952,14 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
void Generate() final {
MipsOperandConverter i(gen_, instr_);
Builtins::Name trap_id =
static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
private:
void GenerateCallToTrap(Builtins::Name trap_id) {
if (trap_id == Builtins::builtin_count) {
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
// We use the context register as the scratch register, because we do
......@@ -2976,8 +2975,9 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Ret();
} else {
gen_->AssembleSourcePosition(instr_);
__ Call(tasm()->isolate()->builtins()->builtin_handle(trap_id),
RelocInfo::CODE_TARGET);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
......
......@@ -3194,14 +3194,14 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
: OutOfLineCode(gen), instr_(instr), gen_(gen) {}
void Generate() final {
MipsOperandConverter i(gen_, instr_);
Builtins::Name trap_id =
static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
private:
void GenerateCallToTrap(Builtins::Name trap_id) {
if (trap_id == Builtins::builtin_count) {
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
// We use the context register as the scratch register, because we do
......@@ -3218,8 +3218,9 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Ret();
} else {
gen_->AssembleSourcePosition(instr_);
__ Call(tasm()->isolate()->builtins()->builtin_handle(trap_id),
RelocInfo::CODE_TARGET);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
......
......@@ -2120,15 +2120,14 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
void Generate() final {
PPCOperandConverter i(gen_, instr_);
Builtins::Name trap_id =
static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
private:
void GenerateCallToTrap(Builtins::Name trap_id) {
if (trap_id == Builtins::builtin_count) {
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
// We use the context register as the scratch register, because we do
......@@ -2144,8 +2143,9 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Ret();
} else {
gen_->AssembleSourcePosition(instr_);
__ Call(__ isolate()->builtins()->builtin_handle(trap_id),
RelocInfo::CODE_TARGET);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
......
......@@ -2799,15 +2799,14 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
void Generate() final {
S390OperandConverter i(gen_, instr_);
Builtins::Name trap_id =
static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
private:
void GenerateCallToTrap(Builtins::Name trap_id) {
if (trap_id == Builtins::builtin_count) {
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
// We use the context register as the scratch register, because we do
......@@ -2823,8 +2822,9 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Ret();
} else {
gen_->AssembleSourcePosition(instr_);
__ Call(__ isolate()->builtins()->builtin_handle(trap_id),
RelocInfo::CODE_TARGET);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
......
......@@ -897,22 +897,25 @@ Node* WasmGraphBuilder::BranchExpectFalse(Node* cond, Node** true_node,
BranchHint::kFalse);
}
Builtins::Name WasmGraphBuilder::GetBuiltinIdForTrap(wasm::TrapReason reason) {
TrapId WasmGraphBuilder::GetTrapIdForTrap(wasm::TrapReason reason) {
// TODO(wasm): "!env_" should not happen when compiling an actual wasm
// function.
if (!env_ || !env_->runtime_exception_support) {
// We use Builtins::builtin_count as a marker to tell the code generator
// We use TrapId::kInvalid as a marker to tell the code generator
// to generate a call to a testing c-function instead of a runtime
// function. This code should only be called from a cctest.
return Builtins::builtin_count;
// stub. This code should only be called from a cctest.
return TrapId::kInvalid;
}
switch (reason) {
#define TRAPREASON_TO_MESSAGE(name) \
case wasm::k##name: \
return Builtins::kThrowWasm##name;
FOREACH_WASM_TRAPREASON(TRAPREASON_TO_MESSAGE)
#undef TRAPREASON_TO_MESSAGE
#define TRAPREASON_TO_TRAPID(name) \
case wasm::k##name: \
static_assert( \
static_cast<int>(TrapId::k##name) == wasm::WasmCode::kThrowWasm##name, \
"trap id mismatch"); \
return TrapId::k##name;
FOREACH_WASM_TRAPREASON(TRAPREASON_TO_TRAPID)
#undef TRAPREASON_TO_TRAPID
default:
UNREACHABLE();
}
......@@ -920,7 +923,7 @@ Builtins::Name WasmGraphBuilder::GetBuiltinIdForTrap(wasm::TrapReason reason) {
Node* WasmGraphBuilder::TrapIfTrue(wasm::TrapReason reason, Node* cond,
wasm::WasmCodePosition position) {
Builtins::Name trap_id = GetBuiltinIdForTrap(reason);
TrapId trap_id = GetTrapIdForTrap(reason);
Node* node = graph()->NewNode(mcgraph()->common()->TrapIf(trap_id), cond,
Effect(), Control());
*control_ = node;
......@@ -930,8 +933,7 @@ Node* WasmGraphBuilder::TrapIfTrue(wasm::TrapReason reason, Node* cond,
Node* WasmGraphBuilder::TrapIfFalse(wasm::TrapReason reason, Node* cond,
wasm::WasmCodePosition position) {
Builtins::Name trap_id = GetBuiltinIdForTrap(reason);
TrapId trap_id = GetTrapIdForTrap(reason);
Node* node = graph()->NewNode(mcgraph()->common()->TrapUnless(trap_id), cond,
Effect(), Control());
*control_ = node;
......
......@@ -33,6 +33,7 @@ class NodeOriginTable;
class Operator;
class SourcePositionTable;
class WasmDecorator;
enum class TrapId : uint32_t;
} // namespace compiler
namespace wasm {
......@@ -493,7 +494,7 @@ class WasmGraphBuilder {
Node* js_context,
Node* const* parameters,
int parameter_count);
Builtins::Name GetBuiltinIdForTrap(wasm::TrapReason reason);
TrapId GetTrapIdForTrap(wasm::TrapReason reason);
};
V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(
......
......@@ -267,21 +267,18 @@ class WasmOutOfLineTrap : public OutOfLineCode {
void Generate() override {
X64OperandConverter i(gen_, instr_);
Builtins::Name trap_id =
static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateWithTrapId(trap_id);
}
protected:
CodeGenerator* gen_;
void GenerateWithTrapId(Builtins::Name trap_id) {
GenerateCallToTrap(trap_id);
}
void GenerateWithTrapId(TrapId trap_id) { GenerateCallToTrap(trap_id); }
private:
void GenerateCallToTrap(Builtins::Name trap_id) {
void GenerateCallToTrap(TrapId trap_id) {
if (!gen_->wasm_runtime_exception_support()) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
......@@ -295,8 +292,9 @@ class WasmOutOfLineTrap : public OutOfLineCode {
__ Ret(static_cast<int>(pop_size), rcx);
} else {
gen_->AssembleSourcePosition(instr_);
__ Call(__ isolate()->builtins()->builtin_handle(trap_id),
RelocInfo::CODE_TARGET);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
__ near_call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
......@@ -315,8 +313,7 @@ class WasmProtectedInstructionTrap final : public WasmOutOfLineTrap {
void Generate() final {
gen_->AddProtectedInstructionLanding(pc_, __ pc_offset());
GenerateWithTrapId(Builtins::kThrowWasmTrapMemOutOfBounds);
GenerateWithTrapId(TrapId::kTrapMemOutOfBounds);
}
private:
......
......@@ -1562,6 +1562,7 @@ enum class PoisoningMitigationLevel {
kDontPoison,
kPoisonCriticalOnly
};
enum class LoadSensitivity {
kCritical, // Critical loads are poisoned whenever we can run untrusted
// code (i.e., when --untrusted-code-mitigations is on).
......@@ -1570,6 +1571,17 @@ enum class LoadSensitivity {
kSafe // Safe loads are never poisoned.
};
// The reason for a WebAssembly trap.
#define FOREACH_WASM_TRAPREASON(V) \
V(TrapUnreachable) \
V(TrapMemOutOfBounds) \
V(TrapDivByZero) \
V(TrapDivUnrepresentable) \
V(TrapRemByZero) \
V(TrapFloatUnrepresentable) \
V(TrapFuncInvalid) \
V(TrapFuncSigMismatch)
} // namespace internal
} // namespace v8
......
......@@ -473,7 +473,9 @@ void NativeModule::SetRuntimeStubs(Isolate* isolate) {
runtime_stub_table_[WasmCode::k##Name] = \
AddAnonymousCode(isolate->builtins()->builtin_handle(Builtins::k##Name), \
WasmCode::kRuntimeStub);
WASM_RUNTIME_STUB_LIST(COPY_BUILTIN);
#define COPY_BUILTIN_TRAP(Name) COPY_BUILTIN(ThrowWasm##Name)
WASM_RUNTIME_STUB_LIST(COPY_BUILTIN, COPY_BUILTIN_TRAP);
#undef COPY_BUILTIN_TRAP
#undef COPY_BUILTIN
}
......
......@@ -30,8 +30,11 @@ class NativeModule;
class WasmCodeManager;
struct WasmModule;
// Convenience macro listing all wasm runtime stubs.
#define WASM_RUNTIME_STUB_LIST(V) V(WasmStackGuard)
// Convenience macro listing all wasm runtime stubs. Note that the first few
// elements of the list coincide with {compiler::TrapId}, order matters.
#define WASM_RUNTIME_STUB_LIST(V, VTRAP) \
FOREACH_WASM_TRAPREASON(VTRAP) \
V(WasmStackGuard)
// Sorted, disjoint and non-overlapping memory ranges. A range is of the
// form [start, end). So there's no [start, end), [end, other_end),
......@@ -96,8 +99,10 @@ class V8_EXPORT_PRIVATE WasmCode final {
// Each runtime stub is identified by an id. This id is used to reference the
// stub via {RelocInfo::WASM_STUB_CALL} and gets resolved during relocation.
enum RuntimeStubId {
#define DEF_ENUM(Name, ...) k##Name,
WASM_RUNTIME_STUB_LIST(DEF_ENUM)
#define DEF_ENUM(Name) k##Name,
#define DEF_ENUM_TRAP(Name) kThrowWasm##Name,
WASM_RUNTIME_STUB_LIST(DEF_ENUM, DEF_ENUM_TRAP)
#undef DEF_ENUM_TRAP
#undef DEF_ENUM
kRuntimeStubCount
};
......
......@@ -562,17 +562,6 @@ enum WasmOpcode {
#undef DECLARE_PREFIX
};
// The reason for a trap.
#define FOREACH_WASM_TRAPREASON(V) \
V(TrapUnreachable) \
V(TrapMemOutOfBounds) \
V(TrapDivByZero) \
V(TrapDivUnrepresentable) \
V(TrapRemByZero) \
V(TrapFloatUnrepresentable) \
V(TrapFuncInvalid) \
V(TrapFuncSigMismatch)
enum TrapReason {
#define DECLARE_ENUM(name) k##name,
FOREACH_WASM_TRAPREASON(DECLARE_ENUM)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment