[wasm] Provide a signature for every block
This removes a few dynamic checks whether a block type immediate is using the MVP syntax with 0-1 return types, or has a full signature (for multi-return). We now always provide a signature, using another field in the {BlockTypeImmediate} as storage for MVP types. This makes {BlockTypeImmediate} slightly bigger, which should not be a problem as there is always only one of them alive, and it's stored on the stack. R=jkummerow@chromium.org Change-Id: Ie36b73f7213826f32cd349c33f23d834c9de0a50 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3991249 Commit-Queue: Clemens Backes <clemensb@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/main@{#84168}
This commit is contained in:
parent
d7f28a4369
commit
6f5f7b807b
@ -561,9 +561,19 @@ struct SelectTypeImmediate {
|
||||
|
||||
struct BlockTypeImmediate {
|
||||
uint32_t length = 1;
|
||||
ValueType type = kWasmVoid;
|
||||
uint32_t sig_index = 0;
|
||||
const FunctionSig* sig = nullptr;
|
||||
// After decoding, either {sig_index} is set XOR {sig} points to
|
||||
// {single_return_sig_storage}.
|
||||
uint32_t sig_index;
|
||||
FunctionSig sig{0, 0, single_return_sig_storage};
|
||||
// Internal field, potentially pointed to by {sig}. Do not access directly.
|
||||
ValueType single_return_sig_storage[1];
|
||||
|
||||
// Do not copy or move, as {sig} might point to {single_return_sig_storage} so
|
||||
// this cannot trivially be copied. If needed, define those operators later.
|
||||
BlockTypeImmediate(const BlockTypeImmediate&) = delete;
|
||||
BlockTypeImmediate(BlockTypeImmediate&&) = delete;
|
||||
BlockTypeImmediate& operator=(const BlockTypeImmediate&) = delete;
|
||||
BlockTypeImmediate& operator=(BlockTypeImmediate&&) = delete;
|
||||
|
||||
template <typename ValidationTag>
|
||||
BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
|
||||
@ -579,34 +589,26 @@ struct BlockTypeImmediate {
|
||||
block_type);
|
||||
return;
|
||||
}
|
||||
if (static_cast<ValueTypeCode>(block_type & 0x7F) == kVoidCode) return;
|
||||
type = value_type_reader::read_value_type<ValidationTag>(
|
||||
decoder, pc, &length, enabled);
|
||||
if (static_cast<ValueTypeCode>(block_type & 0x7F) != kVoidCode) {
|
||||
sig = FunctionSig{1, 0, single_return_sig_storage};
|
||||
single_return_sig_storage[0] =
|
||||
value_type_reader::read_value_type<ValidationTag>(decoder, pc,
|
||||
&length, enabled);
|
||||
}
|
||||
} else {
|
||||
type = kWasmBottom;
|
||||
sig = FunctionSig{0, 0, nullptr};
|
||||
sig_index = static_cast<uint32_t>(block_type);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t in_arity() const {
|
||||
if (type != kWasmBottom) return 0;
|
||||
return static_cast<uint32_t>(sig->parameter_count());
|
||||
return static_cast<uint32_t>(sig.parameter_count());
|
||||
}
|
||||
uint32_t out_arity() const {
|
||||
if (type == kWasmVoid) return 0;
|
||||
if (type != kWasmBottom) return 1;
|
||||
return static_cast<uint32_t>(sig->return_count());
|
||||
}
|
||||
ValueType in_type(uint32_t index) {
|
||||
DCHECK_EQ(kWasmBottom, type);
|
||||
return sig->GetParam(index);
|
||||
}
|
||||
ValueType out_type(uint32_t index) {
|
||||
if (type == kWasmBottom) return sig->GetReturn(index);
|
||||
DCHECK_NE(kWasmVoid, type);
|
||||
DCHECK_EQ(0, index);
|
||||
return type;
|
||||
return static_cast<uint32_t>(sig.return_count());
|
||||
}
|
||||
ValueType in_type(uint32_t index) { return sig.GetParam(index); }
|
||||
ValueType out_type(uint32_t index) { return sig.GetReturn(index); }
|
||||
};
|
||||
|
||||
struct BranchDepthImmediate {
|
||||
@ -1653,14 +1655,21 @@ class WasmDecoder : public Decoder {
|
||||
}
|
||||
|
||||
bool Validate(const byte* pc, BlockTypeImmediate& imm) {
|
||||
if (!ValidateValueType(pc, imm.type)) return false;
|
||||
if (imm.type == kWasmBottom) {
|
||||
if (imm.sig.all().begin() == nullptr) {
|
||||
// Then use {sig_index} to initialize the signature.
|
||||
if (!VALIDATE(module_->has_signature(imm.sig_index))) {
|
||||
DecodeError(pc, "block type index %u is not a signature definition",
|
||||
imm.sig_index);
|
||||
return false;
|
||||
}
|
||||
imm.sig = module_->signature(imm.sig_index);
|
||||
imm.sig = *module_->signature(imm.sig_index);
|
||||
} else {
|
||||
// Then it's an MVP immediate with 0 parameters and 0-1 returns.
|
||||
DCHECK_EQ(0, imm.sig.parameter_count());
|
||||
DCHECK_GE(1, imm.sig.return_count());
|
||||
if (imm.sig.return_count()) {
|
||||
if (!ValidateValueType(pc, imm.sig.GetReturn(0))) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -3000,11 +3009,11 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
||||
DECODE(Block) {
|
||||
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
ArgVector args = PeekArgs(imm.sig);
|
||||
ArgVector args = PeekArgs(&imm.sig);
|
||||
Control* block = PushControl(kControlBlock, args.length());
|
||||
SetBlockType(block, imm, args.begin());
|
||||
CALL_INTERFACE_IF_OK_AND_REACHABLE(Block, block);
|
||||
DropArgs(imm.sig);
|
||||
DropArgs(&imm.sig);
|
||||
PushMergeValues(block, &block->start_merge);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
@ -3038,13 +3047,13 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
||||
this->detected_->Add(kFeature_eh);
|
||||
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
ArgVector args = PeekArgs(imm.sig);
|
||||
ArgVector args = PeekArgs(&imm.sig);
|
||||
Control* try_block = PushControl(kControlTry, args.length());
|
||||
SetBlockType(try_block, imm, args.begin());
|
||||
try_block->previous_catch = current_catch_;
|
||||
current_catch_ = static_cast<int>(control_depth() - 1);
|
||||
CALL_INTERFACE_IF_OK_AND_REACHABLE(Try, try_block);
|
||||
DropArgs(imm.sig);
|
||||
DropArgs(&imm.sig);
|
||||
PushMergeValues(try_block, &try_block->start_merge);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
@ -3225,11 +3234,11 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
||||
DECODE(Loop) {
|
||||
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
ArgVector args = PeekArgs(imm.sig);
|
||||
ArgVector args = PeekArgs(&imm.sig);
|
||||
Control* block = PushControl(kControlLoop, args.length());
|
||||
SetBlockType(&control_.back(), imm, args.begin());
|
||||
CALL_INTERFACE_IF_OK_AND_REACHABLE(Loop, block);
|
||||
DropArgs(imm.sig);
|
||||
DropArgs(&imm.sig);
|
||||
PushMergeValues(block, &block->start_merge);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
@ -3238,13 +3247,13 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
||||
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
Value cond = Peek(0, 0, kWasmI32);
|
||||
ArgVector args = PeekArgs(imm.sig, 1);
|
||||
ArgVector args = PeekArgs(&imm.sig, 1);
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
Control* if_block = PushControl(kControlIf, 1 + args.length());
|
||||
SetBlockType(if_block, imm, args.begin());
|
||||
CALL_INTERFACE_IF_OK_AND_REACHABLE(If, cond, if_block);
|
||||
Drop(cond);
|
||||
DropArgs(imm.sig); // Drop {args}.
|
||||
DropArgs(&imm.sig);
|
||||
PushMergeValues(if_block, &if_block->start_merge);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
@ -4033,7 +4042,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
||||
|
||||
// Peeks arguments as required by signature.
|
||||
V8_INLINE ArgVector PeekArgs(const FunctionSig* sig, int depth = 0) {
|
||||
int count = sig ? static_cast<int>(sig->parameter_count()) : 0;
|
||||
int count = static_cast<int>(sig->parameter_count());
|
||||
if (count == 0) return {};
|
||||
EnsureStackArguments(depth + count);
|
||||
ArgVector args(stack_value(depth + count), count);
|
||||
@ -4045,7 +4054,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
||||
// Drops a number of stack elements equal to the {sig}'s parameter count (0 if
|
||||
// {sig} is null), or all of them if less are present.
|
||||
V8_INLINE void DropArgs(const FunctionSig* sig) {
|
||||
int count = sig ? static_cast<int>(sig->parameter_count()) : 0;
|
||||
int count = static_cast<int>(sig->parameter_count());
|
||||
Drop(count);
|
||||
}
|
||||
|
||||
|
@ -12,21 +12,11 @@ namespace wasm {
|
||||
|
||||
base::Optional<wasm::ValueKind> WasmReturnTypeFromSignature(
|
||||
const FunctionSig* wasm_signature) {
|
||||
if (wasm_signature->return_count() == 0) {
|
||||
return {};
|
||||
} else {
|
||||
DCHECK_EQ(wasm_signature->return_count(), 1);
|
||||
ValueType return_type = wasm_signature->GetReturn(0);
|
||||
switch (return_type.kind()) {
|
||||
case kI32:
|
||||
case kI64:
|
||||
case kF32:
|
||||
case kF64:
|
||||
return {return_type.kind()};
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
if (wasm_signature->return_count() == 0) return {};
|
||||
|
||||
DCHECK_EQ(wasm_signature->return_count(), 1);
|
||||
ValueType return_type = wasm_signature->GetReturn(0);
|
||||
return {return_type.kind()};
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
@ -310,16 +310,7 @@ class ImmediatesPrinter {
|
||||
}
|
||||
|
||||
void BlockType(BlockTypeImmediate& imm) {
|
||||
if (imm.type == kWasmBottom) {
|
||||
const FunctionSig* sig = owner_->module_->signature(imm.sig_index);
|
||||
PrintSignatureOneLine(out_, sig, 0 /* ignored */, names(), false);
|
||||
} else if (imm.type == kWasmVoid) {
|
||||
// Just be silent.
|
||||
} else {
|
||||
out_ << " (result ";
|
||||
names()->PrintValueType(out_, imm.type);
|
||||
out_ << ")";
|
||||
}
|
||||
PrintSignatureOneLine(out_, &imm.sig, 0 /* ignored */, names(), false);
|
||||
}
|
||||
|
||||
void HeapType(HeapTypeImmediate& imm) {
|
||||
|
@ -751,6 +751,14 @@ class SideTable : public ZoneObject {
|
||||
max_exception_arity, static_cast<int>(tag.sig->parameter_count()));
|
||||
}
|
||||
}
|
||||
WasmFeatures unused_detected_features;
|
||||
WasmDecoder<Decoder::NoValidationTag> decoder{zone,
|
||||
module,
|
||||
WasmFeatures::All(),
|
||||
&unused_detected_features,
|
||||
code->function->sig,
|
||||
code->start,
|
||||
code->end};
|
||||
for (BytecodeIterator i(code->start, code->end, &code->locals, zone);
|
||||
i.has_next(); i.next()) {
|
||||
WasmOpcode opcode = i.current();
|
||||
@ -794,11 +802,9 @@ class SideTable : public ZoneObject {
|
||||
case kExprBlock:
|
||||
case kExprLoop: {
|
||||
bool is_loop = opcode == kExprLoop;
|
||||
BlockTypeImmediate imm(WasmFeatures::All(), &i, i.pc() + 1,
|
||||
BlockTypeImmediate imm(WasmFeatures::All(), &decoder, i.pc() + 1,
|
||||
kNoValidate);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
CHECK(decoder.Validate(i.pc() + 1, imm));
|
||||
TRACE("control @%u: %s, arity %d->%d\n", i.pc_offset(),
|
||||
is_loop ? "Loop" : "Block", imm.in_arity(), imm.out_arity());
|
||||
DCHECK_IMPLIES(!unreachable,
|
||||
@ -816,11 +822,9 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprIf: {
|
||||
BlockTypeImmediate imm(WasmFeatures::All(), &i, i.pc() + 1,
|
||||
BlockTypeImmediate imm(WasmFeatures::All(), &decoder, i.pc() + 1,
|
||||
kNoValidate);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
CHECK(decoder.Validate(i.pc() + 1, imm));
|
||||
TRACE("control @%u: If, arity %d->%d\n", i.pc_offset(),
|
||||
imm.in_arity(), imm.out_arity());
|
||||
DCHECK_IMPLIES(!unreachable,
|
||||
@ -877,11 +881,9 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprTry: {
|
||||
BlockTypeImmediate imm(WasmFeatures::All(), &i, i.pc() + 1,
|
||||
BlockTypeImmediate imm(WasmFeatures::All(), &decoder, i.pc() + 1,
|
||||
kNoValidate);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
CHECK(decoder.Validate(i.pc() + 1, imm));
|
||||
TRACE("control @%u: Try, arity %d->%d\n", i.pc_offset(),
|
||||
imm.in_arity(), imm.out_arity());
|
||||
int target_stack_height = stack_height - imm.in_arity();
|
||||
@ -901,7 +903,7 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprRethrow: {
|
||||
BranchDepthImmediate imm(&i, i.pc() + 1, kNoValidate);
|
||||
BranchDepthImmediate imm(&decoder, i.pc() + 1, kNoValidate);
|
||||
int index = static_cast<int>(control_stack.size()) - 1 - imm.depth;
|
||||
rethrow_map_.emplace(i.pc() - i.start(), index);
|
||||
break;
|
||||
@ -912,7 +914,7 @@ class SideTable : public ZoneObject {
|
||||
// Only pop the exception stack once when we enter the first catch.
|
||||
exception_stack.pop_back();
|
||||
}
|
||||
TagIndexImmediate imm(&i, i.pc() + 1, kNoValidate);
|
||||
TagIndexImmediate imm(&decoder, i.pc() + 1, kNoValidate);
|
||||
Control* c = &control_stack.back();
|
||||
copy_unreachable();
|
||||
TRACE("control @%u: Catch\n", i.pc_offset());
|
||||
@ -980,7 +982,7 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprDelegate: {
|
||||
BranchDepthImmediate imm(&i, i.pc() + 1, kNoValidate);
|
||||
BranchDepthImmediate imm(&decoder, i.pc() + 1, kNoValidate);
|
||||
TRACE("control @%u: Delegate[depth=%u]\n", i.pc_offset(), imm.depth);
|
||||
Control* c = &control_stack.back();
|
||||
const size_t new_stack_size = control_stack.size() - 1;
|
||||
@ -1018,21 +1020,21 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprBr: {
|
||||
BranchDepthImmediate imm(&i, i.pc() + 1, kNoValidate);
|
||||
BranchDepthImmediate imm(&decoder, i.pc() + 1, kNoValidate);
|
||||
TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), imm.depth);
|
||||
Control* c = &control_stack[control_stack.size() - imm.depth - 1];
|
||||
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
|
||||
break;
|
||||
}
|
||||
case kExprBrIf: {
|
||||
BranchDepthImmediate imm(&i, i.pc() + 1, kNoValidate);
|
||||
BranchDepthImmediate imm(&decoder, i.pc() + 1, kNoValidate);
|
||||
TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), imm.depth);
|
||||
Control* c = &control_stack[control_stack.size() - imm.depth - 1];
|
||||
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
|
||||
break;
|
||||
}
|
||||
case kExprBrTable: {
|
||||
BranchTableImmediate imm(&i, i.pc() + 1, kNoValidate);
|
||||
BranchTableImmediate imm(&decoder, i.pc() + 1, kNoValidate);
|
||||
BranchTableIterator<Decoder::NoValidationTag> iterator(&i, imm);
|
||||
TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
|
||||
imm.table_count);
|
||||
|
Loading…
Reference in New Issue
Block a user