[wasm][liftoff][eh] Implement catch with immediate
Only support empty exceptions for now. Unpacking i32s, and eventually arbitrary types, will be done in separate CLs. R=clemensb@chromium.org Bug: v8:11453 Change-Id: Ic3233e0bbdaad8b710cd836be9aef647d3131c9d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2739590 Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Reviewed-by: Clemens Backes <clemensb@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#73402}
This commit is contained in:
parent
7a8da348a7
commit
3e689a7da6
@ -716,6 +716,14 @@ void LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr,
|
||||
offset_imm, LoadType::kI32Load, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::LoadFullPointer(Register dst, Register src_addr,
|
||||
int32_t offset_imm) {
|
||||
UseScratchRegisterScope temps(this);
|
||||
MemOperand src_op =
|
||||
liftoff::GetMemOp(this, &temps, src_addr, no_reg, offset_imm);
|
||||
ldr(dst, src_op);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::StoreTaggedPointer(Register dst_addr,
|
||||
Register offset_reg,
|
||||
int32_t offset_imm,
|
||||
|
@ -444,6 +444,14 @@ void LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr,
|
||||
LoadTaggedPointerField(dst, src_op);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::LoadFullPointer(Register dst, Register src_addr,
|
||||
int32_t offset_imm) {
|
||||
UseScratchRegisterScope temps(this);
|
||||
MemOperand src_op =
|
||||
liftoff::GetMemOp(this, &temps, src_addr, no_reg, offset_imm);
|
||||
Ldr(dst.X(), src_op);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::StoreTaggedPointer(Register dst_addr,
|
||||
Register offset_reg,
|
||||
int32_t offset_imm,
|
||||
|
@ -342,6 +342,11 @@ void LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr,
|
||||
static_cast<uint32_t>(offset_imm), LoadType::kI32Load, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::LoadFullPointer(Register dst, Register src_addr,
|
||||
int32_t offset_imm) {
|
||||
mov(dst, Operand(src_addr, offset_imm));
|
||||
}
|
||||
|
||||
void LiftoffAssembler::StoreTaggedPointer(Register dst_addr,
|
||||
Register offset_reg,
|
||||
int32_t offset_imm,
|
||||
|
@ -633,6 +633,8 @@ class LiftoffAssembler : public TurboAssembler {
|
||||
inline void LoadTaggedPointer(Register dst, Register src_addr,
|
||||
Register offset_reg, int32_t offset_imm,
|
||||
LiftoffRegList pinned);
|
||||
inline void LoadFullPointer(Register dst, Register src_addr,
|
||||
int32_t offset_imm);
|
||||
enum SkipWriteBarrier : bool {
|
||||
kSkipWriteBarrier = true,
|
||||
kNoSkipWriteBarrier = false
|
||||
|
@ -368,6 +368,7 @@ class LiftoffCompiler {
|
||||
LiftoffAssembler::CacheState catch_state;
|
||||
Label catch_label;
|
||||
bool catch_reached = false;
|
||||
bool in_handler = false;
|
||||
int32_t previous_catch = -1;
|
||||
};
|
||||
|
||||
@ -1069,10 +1070,85 @@ class LiftoffCompiler {
|
||||
PushControl(block);
|
||||
}
|
||||
|
||||
// Load the exception tag in {kReturnRegister0}.
|
||||
void GetExceptionTag(LiftoffAssembler::VarState& exception) {
|
||||
LiftoffRegList pinned;
|
||||
LiftoffRegister tag_symbol_reg =
|
||||
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
LoadExceptionTagSymbol(tag_symbol_reg.gp(), pinned);
|
||||
LiftoffRegister context_reg =
|
||||
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
LOAD_TAGGED_PTR_INSTANCE_FIELD(context_reg.gp(), NativeContext, pinned);
|
||||
|
||||
auto sig = MakeSig()
|
||||
.Returns(kPointerKind)
|
||||
.Params(kPointerKind, kPointerKind, kPointerKind);
|
||||
LiftoffAssembler::VarState tag_symbol(kPointerKind, tag_symbol_reg, 0);
|
||||
LiftoffAssembler::VarState context(kPointerKind, context_reg, 0);
|
||||
|
||||
compiler::CallDescriptor* call_descriptor =
|
||||
GetBuiltinCallDescriptor<WasmGetOwnPropertyDescriptor>(
|
||||
compilation_zone_);
|
||||
__ PrepareBuiltinCall(&sig, call_descriptor,
|
||||
{exception, tag_symbol, context});
|
||||
DEBUG_CODE_COMMENT("Call builtin");
|
||||
__ CallRuntimeStub(WasmCode::RuntimeStubId::kWasmGetOwnProperty);
|
||||
DefineSafepoint();
|
||||
}
|
||||
|
||||
void CatchException(FullDecoder* decoder,
|
||||
const ExceptionIndexImmediate<validate>& imm,
|
||||
Control* block, Vector<Value> values) {
|
||||
unsupported(decoder, kExceptionHandling, "catch");
|
||||
DCHECK(block->is_try_catch());
|
||||
current_catch_ = block->try_info->previous_catch; // Pop try scope.
|
||||
__ emit_jump(block->label.get());
|
||||
|
||||
// The catch block is unreachable if no possible throws in the try block
|
||||
// exist. We only build a landing pad if some node in the try block can
|
||||
// (possibly) throw. Otherwise the catch environments remain empty.
|
||||
if (!block->try_info->catch_reached) {
|
||||
block->reachability = kSpecOnlyReachable;
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the last use of this label. Re-use the field for the label of the
|
||||
// next catch block, and jump there if the tag does not match.
|
||||
__ bind(&block->try_info->catch_label);
|
||||
new (&block->try_info->catch_label) Label();
|
||||
|
||||
__ cache_state()->Split(block->try_info->catch_state);
|
||||
|
||||
DEBUG_CODE_COMMENT("load caught exception tag");
|
||||
DCHECK_EQ(__ cache_state()->stack_state.back().kind(), kRef);
|
||||
GetExceptionTag(__ cache_state()->stack_state.back());
|
||||
LiftoffRegList pinned;
|
||||
LiftoffRegister caught_tag(kReturnRegister0);
|
||||
pinned.set(caught_tag);
|
||||
|
||||
DEBUG_CODE_COMMENT("load expected exception tag");
|
||||
Register imm_tag = pinned.set(__ GetUnusedRegister(kGpReg, pinned)).gp();
|
||||
LOAD_TAGGED_PTR_INSTANCE_FIELD(imm_tag, ExceptionsTable, pinned);
|
||||
__ LoadTaggedPointer(
|
||||
imm_tag, imm_tag, no_reg,
|
||||
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(imm.index), {});
|
||||
|
||||
DEBUG_CODE_COMMENT("compare tags");
|
||||
Label caught;
|
||||
__ emit_cond_jump(kEqual, &caught, kI32, imm_tag, kReturnRegister0);
|
||||
// The tags don't match, merge the current state into the catch state and
|
||||
// jump to the next handler.
|
||||
__ MergeFullStackWith(block->try_info->catch_state, *__ cache_state());
|
||||
__ emit_jump(&block->try_info->catch_label);
|
||||
|
||||
__ bind(&caught);
|
||||
if (!block->try_info->in_handler) {
|
||||
block->try_info->in_handler = true;
|
||||
num_exceptions_++;
|
||||
}
|
||||
if (env_->module->exceptions[imm.index].sig->parameter_count() > 0) {
|
||||
// TODO(thibaudm): Unpack exception.
|
||||
unsupported(decoder, kExceptionHandling, "exception with parameters");
|
||||
}
|
||||
}
|
||||
|
||||
void Rethrow(FullDecoder* decoder,
|
||||
@ -1140,7 +1216,8 @@ class LiftoffCompiler {
|
||||
|
||||
__ bind(&block->try_info->catch_label);
|
||||
__ cache_state()->Steal(block->try_info->catch_state);
|
||||
if (!block->is_try_unwind()) {
|
||||
if (!block->try_info->in_handler) {
|
||||
block->try_info->in_handler = true;
|
||||
num_exceptions_++;
|
||||
}
|
||||
}
|
||||
@ -1168,7 +1245,16 @@ class LiftoffCompiler {
|
||||
c->end_merge.arity,
|
||||
c->stack_depth + c->num_exceptions);
|
||||
}
|
||||
__ MergeFullStackWith(c->label_state, *__ cache_state());
|
||||
DCHECK(!c->is_try_catchall());
|
||||
if (c->is_try_catch()) {
|
||||
// Drop the implicit exception ref.
|
||||
DCHECK_EQ(c->label_state.stack_height() + 1,
|
||||
__ cache_state()->stack_height());
|
||||
__ MergeStackWith(c->label_state, c->br_merge()->arity,
|
||||
LiftoffAssembler::kForwardJump);
|
||||
} else {
|
||||
__ MergeFullStackWith(c->label_state, *__ cache_state());
|
||||
}
|
||||
__ emit_jump(c->label.get());
|
||||
TraceCacheState(decoder);
|
||||
}
|
||||
@ -1207,8 +1293,8 @@ class LiftoffCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
void FinishTryCatch(FullDecoder* decoder, Control* c) {
|
||||
DCHECK(c->is_try_catch() || c->is_try_catchall());
|
||||
void FinishTry(FullDecoder* decoder, Control* c) {
|
||||
DCHECK(c->is_try_catch() || c->is_try_catchall() || c->is_try_unwind());
|
||||
if (!c->end_merge.reached) {
|
||||
if (c->try_info->catch_reached) {
|
||||
// Drop the implicit exception ref.
|
||||
@ -1232,8 +1318,9 @@ class LiftoffCompiler {
|
||||
if (c->is_onearmed_if()) {
|
||||
// Special handling for one-armed ifs.
|
||||
FinishOneArmedIf(decoder, c);
|
||||
} else if (c->is_try_catch() || c->is_try_catchall()) {
|
||||
FinishTryCatch(decoder, c);
|
||||
} else if (c->is_try_catch() || c->is_try_catchall() ||
|
||||
c->is_try_unwind()) {
|
||||
FinishTry(decoder, c);
|
||||
} else if (c->end_merge.reached) {
|
||||
// There is a merge already. Merge our state into that, then continue with
|
||||
// that state.
|
||||
@ -3846,11 +3933,11 @@ class LiftoffCompiler {
|
||||
|
||||
// Load the exception tag.
|
||||
DEBUG_CODE_COMMENT("load exception tag");
|
||||
Register exception_tag =
|
||||
pinned.set(__ GetUnusedRegister(kGpReg, pinned)).gp();
|
||||
LOAD_TAGGED_PTR_INSTANCE_FIELD(exception_tag, ExceptionsTable, pinned);
|
||||
LiftoffRegister exception_tag =
|
||||
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
LOAD_TAGGED_PTR_INSTANCE_FIELD(exception_tag.gp(), ExceptionsTable, pinned);
|
||||
__ LoadTaggedPointer(
|
||||
exception_tag, exception_tag, no_reg,
|
||||
exception_tag.gp(), exception_tag.gp(), no_reg,
|
||||
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(imm.index), {});
|
||||
|
||||
// Finally, call WasmThrow.
|
||||
@ -3862,8 +3949,7 @@ class LiftoffCompiler {
|
||||
|
||||
__ PrepareBuiltinCall(
|
||||
&throw_sig, throw_descriptor,
|
||||
{LiftoffAssembler::VarState{kPointerKind,
|
||||
LiftoffRegister{exception_tag}, 0},
|
||||
{LiftoffAssembler::VarState{kPointerKind, exception_tag, 0},
|
||||
LiftoffAssembler::VarState{kPointerKind, values_array, 0}});
|
||||
source_position_table_builder_.AddPosition(
|
||||
__ pc_offset(), SourcePosition(decoder->position()), true);
|
||||
@ -5630,6 +5716,13 @@ class LiftoffCompiler {
|
||||
pinned);
|
||||
}
|
||||
|
||||
void LoadExceptionTagSymbol(Register dst, LiftoffRegList pinned) {
|
||||
LOAD_INSTANCE_FIELD(dst, IsolateRoot, kSystemPointerSize, pinned);
|
||||
uint32_t offset_imm =
|
||||
IsolateData::root_slot_offset(RootIndex::kwasm_exception_tag_symbol);
|
||||
__ LoadFullPointer(dst, dst, offset_imm);
|
||||
}
|
||||
|
||||
void MaybeEmitNullCheck(FullDecoder* decoder, Register object,
|
||||
LiftoffRegList pinned, ValueType type) {
|
||||
if (!type.is_nullable()) return;
|
||||
|
@ -332,6 +332,13 @@ void LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr,
|
||||
LoadTaggedPointerField(dst, src_op);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::LoadFullPointer(Register dst, Register src_addr,
|
||||
int32_t offset_imm) {
|
||||
Operand src_op = liftoff::GetMemOp(this, src_addr, no_reg,
|
||||
static_cast<uint32_t>(offset_imm));
|
||||
movq(dst, src_op);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::StoreTaggedPointer(Register dst_addr,
|
||||
Register offset_reg,
|
||||
int32_t offset_imm,
|
||||
|
@ -2537,8 +2537,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
this->DecodeError("catch after unwind for try");
|
||||
return 0;
|
||||
}
|
||||
c->kind = kControlTryCatch;
|
||||
FallThruTo(c);
|
||||
c->kind = kControlTryCatch;
|
||||
// TODO(jkummerow): Consider moving the stack manipulation after the
|
||||
// INTERFACE call for consistency.
|
||||
DCHECK_LE(stack_ + c->stack_depth, stack_end_);
|
||||
|
@ -63,6 +63,7 @@ struct WasmModule;
|
||||
V(WasmI32AtomicWait64) \
|
||||
V(WasmI64AtomicWait32) \
|
||||
V(WasmI64AtomicWait64) \
|
||||
V(WasmGetOwnProperty) \
|
||||
V(WasmRefFunc) \
|
||||
V(WasmMemoryGrow) \
|
||||
V(WasmTableInit) \
|
||||
|
Loading…
Reference in New Issue
Block a user