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