[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 {
|
struct BlockTypeImmediate {
|
||||||
uint32_t length = 1;
|
uint32_t length = 1;
|
||||||
ValueType type = kWasmVoid;
|
// After decoding, either {sig_index} is set XOR {sig} points to
|
||||||
uint32_t sig_index = 0;
|
// {single_return_sig_storage}.
|
||||||
const FunctionSig* sig = nullptr;
|
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>
|
template <typename ValidationTag>
|
||||||
BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
|
BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
|
||||||
@ -579,34 +589,26 @@ struct BlockTypeImmediate {
|
|||||||
block_type);
|
block_type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (static_cast<ValueTypeCode>(block_type & 0x7F) == kVoidCode) return;
|
if (static_cast<ValueTypeCode>(block_type & 0x7F) != kVoidCode) {
|
||||||
type = value_type_reader::read_value_type<ValidationTag>(
|
sig = FunctionSig{1, 0, single_return_sig_storage};
|
||||||
decoder, pc, &length, enabled);
|
single_return_sig_storage[0] =
|
||||||
|
value_type_reader::read_value_type<ValidationTag>(decoder, pc,
|
||||||
|
&length, enabled);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
type = kWasmBottom;
|
sig = FunctionSig{0, 0, nullptr};
|
||||||
sig_index = static_cast<uint32_t>(block_type);
|
sig_index = static_cast<uint32_t>(block_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t in_arity() const {
|
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 {
|
uint32_t out_arity() const {
|
||||||
if (type == kWasmVoid) return 0;
|
return static_cast<uint32_t>(sig.return_count());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
ValueType in_type(uint32_t index) { return sig.GetParam(index); }
|
||||||
|
ValueType out_type(uint32_t index) { return sig.GetReturn(index); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BranchDepthImmediate {
|
struct BranchDepthImmediate {
|
||||||
@ -1653,14 +1655,21 @@ class WasmDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Validate(const byte* pc, BlockTypeImmediate& imm) {
|
bool Validate(const byte* pc, BlockTypeImmediate& imm) {
|
||||||
if (!ValidateValueType(pc, imm.type)) return false;
|
if (imm.sig.all().begin() == nullptr) {
|
||||||
if (imm.type == kWasmBottom) {
|
// Then use {sig_index} to initialize the signature.
|
||||||
if (!VALIDATE(module_->has_signature(imm.sig_index))) {
|
if (!VALIDATE(module_->has_signature(imm.sig_index))) {
|
||||||
DecodeError(pc, "block type index %u is not a signature definition",
|
DecodeError(pc, "block type index %u is not a signature definition",
|
||||||
imm.sig_index);
|
imm.sig_index);
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3000,11 +3009,11 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
|||||||
DECODE(Block) {
|
DECODE(Block) {
|
||||||
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
||||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
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());
|
Control* block = PushControl(kControlBlock, args.length());
|
||||||
SetBlockType(block, imm, args.begin());
|
SetBlockType(block, imm, args.begin());
|
||||||
CALL_INTERFACE_IF_OK_AND_REACHABLE(Block, block);
|
CALL_INTERFACE_IF_OK_AND_REACHABLE(Block, block);
|
||||||
DropArgs(imm.sig);
|
DropArgs(&imm.sig);
|
||||||
PushMergeValues(block, &block->start_merge);
|
PushMergeValues(block, &block->start_merge);
|
||||||
return 1 + imm.length;
|
return 1 + imm.length;
|
||||||
}
|
}
|
||||||
@ -3038,13 +3047,13 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
|||||||
this->detected_->Add(kFeature_eh);
|
this->detected_->Add(kFeature_eh);
|
||||||
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
||||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
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());
|
Control* try_block = PushControl(kControlTry, args.length());
|
||||||
SetBlockType(try_block, imm, args.begin());
|
SetBlockType(try_block, imm, args.begin());
|
||||||
try_block->previous_catch = current_catch_;
|
try_block->previous_catch = current_catch_;
|
||||||
current_catch_ = static_cast<int>(control_depth() - 1);
|
current_catch_ = static_cast<int>(control_depth() - 1);
|
||||||
CALL_INTERFACE_IF_OK_AND_REACHABLE(Try, try_block);
|
CALL_INTERFACE_IF_OK_AND_REACHABLE(Try, try_block);
|
||||||
DropArgs(imm.sig);
|
DropArgs(&imm.sig);
|
||||||
PushMergeValues(try_block, &try_block->start_merge);
|
PushMergeValues(try_block, &try_block->start_merge);
|
||||||
return 1 + imm.length;
|
return 1 + imm.length;
|
||||||
}
|
}
|
||||||
@ -3225,11 +3234,11 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
|||||||
DECODE(Loop) {
|
DECODE(Loop) {
|
||||||
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
||||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
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());
|
Control* block = PushControl(kControlLoop, args.length());
|
||||||
SetBlockType(&control_.back(), imm, args.begin());
|
SetBlockType(&control_.back(), imm, args.begin());
|
||||||
CALL_INTERFACE_IF_OK_AND_REACHABLE(Loop, block);
|
CALL_INTERFACE_IF_OK_AND_REACHABLE(Loop, block);
|
||||||
DropArgs(imm.sig);
|
DropArgs(&imm.sig);
|
||||||
PushMergeValues(block, &block->start_merge);
|
PushMergeValues(block, &block->start_merge);
|
||||||
return 1 + imm.length;
|
return 1 + imm.length;
|
||||||
}
|
}
|
||||||
@ -3238,13 +3247,13 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
|||||||
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
BlockTypeImmediate imm(this->enabled_, this, this->pc_ + 1, validate);
|
||||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||||
Value cond = Peek(0, 0, kWasmI32);
|
Value cond = Peek(0, 0, kWasmI32);
|
||||||
ArgVector args = PeekArgs(imm.sig, 1);
|
ArgVector args = PeekArgs(&imm.sig, 1);
|
||||||
if (!VALIDATE(this->ok())) return 0;
|
if (!VALIDATE(this->ok())) return 0;
|
||||||
Control* if_block = PushControl(kControlIf, 1 + args.length());
|
Control* if_block = PushControl(kControlIf, 1 + args.length());
|
||||||
SetBlockType(if_block, imm, args.begin());
|
SetBlockType(if_block, imm, args.begin());
|
||||||
CALL_INTERFACE_IF_OK_AND_REACHABLE(If, cond, if_block);
|
CALL_INTERFACE_IF_OK_AND_REACHABLE(If, cond, if_block);
|
||||||
Drop(cond);
|
Drop(cond);
|
||||||
DropArgs(imm.sig); // Drop {args}.
|
DropArgs(&imm.sig);
|
||||||
PushMergeValues(if_block, &if_block->start_merge);
|
PushMergeValues(if_block, &if_block->start_merge);
|
||||||
return 1 + imm.length;
|
return 1 + imm.length;
|
||||||
}
|
}
|
||||||
@ -4033,7 +4042,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
|
|||||||
|
|
||||||
// Peeks arguments as required by signature.
|
// Peeks arguments as required by signature.
|
||||||
V8_INLINE ArgVector PeekArgs(const FunctionSig* sig, int depth = 0) {
|
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 {};
|
if (count == 0) return {};
|
||||||
EnsureStackArguments(depth + count);
|
EnsureStackArguments(depth + count);
|
||||||
ArgVector args(stack_value(depth + count), 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
|
// 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.
|
// {sig} is null), or all of them if less are present.
|
||||||
V8_INLINE void DropArgs(const FunctionSig* sig) {
|
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);
|
Drop(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,21 +12,11 @@ namespace wasm {
|
|||||||
|
|
||||||
base::Optional<wasm::ValueKind> WasmReturnTypeFromSignature(
|
base::Optional<wasm::ValueKind> WasmReturnTypeFromSignature(
|
||||||
const FunctionSig* wasm_signature) {
|
const FunctionSig* wasm_signature) {
|
||||||
if (wasm_signature->return_count() == 0) {
|
if (wasm_signature->return_count() == 0) return {};
|
||||||
return {};
|
|
||||||
} else {
|
DCHECK_EQ(wasm_signature->return_count(), 1);
|
||||||
DCHECK_EQ(wasm_signature->return_count(), 1);
|
ValueType return_type = wasm_signature->GetReturn(0);
|
||||||
ValueType return_type = wasm_signature->GetReturn(0);
|
return {return_type.kind()};
|
||||||
switch (return_type.kind()) {
|
|
||||||
case kI32:
|
|
||||||
case kI64:
|
|
||||||
case kF32:
|
|
||||||
case kF64:
|
|
||||||
return {return_type.kind()};
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -310,16 +310,7 @@ class ImmediatesPrinter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BlockType(BlockTypeImmediate& imm) {
|
void BlockType(BlockTypeImmediate& imm) {
|
||||||
if (imm.type == kWasmBottom) {
|
PrintSignatureOneLine(out_, &imm.sig, 0 /* ignored */, names(), false);
|
||||||
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_ << ")";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeapType(HeapTypeImmediate& imm) {
|
void HeapType(HeapTypeImmediate& imm) {
|
||||||
|
@ -751,6 +751,14 @@ class SideTable : public ZoneObject {
|
|||||||
max_exception_arity, static_cast<int>(tag.sig->parameter_count()));
|
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);
|
for (BytecodeIterator i(code->start, code->end, &code->locals, zone);
|
||||||
i.has_next(); i.next()) {
|
i.has_next(); i.next()) {
|
||||||
WasmOpcode opcode = i.current();
|
WasmOpcode opcode = i.current();
|
||||||
@ -794,11 +802,9 @@ class SideTable : public ZoneObject {
|
|||||||
case kExprBlock:
|
case kExprBlock:
|
||||||
case kExprLoop: {
|
case kExprLoop: {
|
||||||
bool is_loop = opcode == kExprLoop;
|
bool is_loop = opcode == kExprLoop;
|
||||||
BlockTypeImmediate imm(WasmFeatures::All(), &i, i.pc() + 1,
|
BlockTypeImmediate imm(WasmFeatures::All(), &decoder, i.pc() + 1,
|
||||||
kNoValidate);
|
kNoValidate);
|
||||||
if (imm.type == kWasmBottom) {
|
CHECK(decoder.Validate(i.pc() + 1, imm));
|
||||||
imm.sig = module->signature(imm.sig_index);
|
|
||||||
}
|
|
||||||
TRACE("control @%u: %s, arity %d->%d\n", i.pc_offset(),
|
TRACE("control @%u: %s, arity %d->%d\n", i.pc_offset(),
|
||||||
is_loop ? "Loop" : "Block", imm.in_arity(), imm.out_arity());
|
is_loop ? "Loop" : "Block", imm.in_arity(), imm.out_arity());
|
||||||
DCHECK_IMPLIES(!unreachable,
|
DCHECK_IMPLIES(!unreachable,
|
||||||
@ -816,11 +822,9 @@ class SideTable : public ZoneObject {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprIf: {
|
case kExprIf: {
|
||||||
BlockTypeImmediate imm(WasmFeatures::All(), &i, i.pc() + 1,
|
BlockTypeImmediate imm(WasmFeatures::All(), &decoder, i.pc() + 1,
|
||||||
kNoValidate);
|
kNoValidate);
|
||||||
if (imm.type == kWasmBottom) {
|
CHECK(decoder.Validate(i.pc() + 1, imm));
|
||||||
imm.sig = module->signature(imm.sig_index);
|
|
||||||
}
|
|
||||||
TRACE("control @%u: If, arity %d->%d\n", i.pc_offset(),
|
TRACE("control @%u: If, arity %d->%d\n", i.pc_offset(),
|
||||||
imm.in_arity(), imm.out_arity());
|
imm.in_arity(), imm.out_arity());
|
||||||
DCHECK_IMPLIES(!unreachable,
|
DCHECK_IMPLIES(!unreachable,
|
||||||
@ -877,11 +881,9 @@ class SideTable : public ZoneObject {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprTry: {
|
case kExprTry: {
|
||||||
BlockTypeImmediate imm(WasmFeatures::All(), &i, i.pc() + 1,
|
BlockTypeImmediate imm(WasmFeatures::All(), &decoder, i.pc() + 1,
|
||||||
kNoValidate);
|
kNoValidate);
|
||||||
if (imm.type == kWasmBottom) {
|
CHECK(decoder.Validate(i.pc() + 1, imm));
|
||||||
imm.sig = module->signature(imm.sig_index);
|
|
||||||
}
|
|
||||||
TRACE("control @%u: Try, arity %d->%d\n", i.pc_offset(),
|
TRACE("control @%u: Try, arity %d->%d\n", i.pc_offset(),
|
||||||
imm.in_arity(), imm.out_arity());
|
imm.in_arity(), imm.out_arity());
|
||||||
int target_stack_height = stack_height - imm.in_arity();
|
int target_stack_height = stack_height - imm.in_arity();
|
||||||
@ -901,7 +903,7 @@ class SideTable : public ZoneObject {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprRethrow: {
|
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;
|
int index = static_cast<int>(control_stack.size()) - 1 - imm.depth;
|
||||||
rethrow_map_.emplace(i.pc() - i.start(), index);
|
rethrow_map_.emplace(i.pc() - i.start(), index);
|
||||||
break;
|
break;
|
||||||
@ -912,7 +914,7 @@ class SideTable : public ZoneObject {
|
|||||||
// Only pop the exception stack once when we enter the first catch.
|
// Only pop the exception stack once when we enter the first catch.
|
||||||
exception_stack.pop_back();
|
exception_stack.pop_back();
|
||||||
}
|
}
|
||||||
TagIndexImmediate imm(&i, i.pc() + 1, kNoValidate);
|
TagIndexImmediate imm(&decoder, i.pc() + 1, kNoValidate);
|
||||||
Control* c = &control_stack.back();
|
Control* c = &control_stack.back();
|
||||||
copy_unreachable();
|
copy_unreachable();
|
||||||
TRACE("control @%u: Catch\n", i.pc_offset());
|
TRACE("control @%u: Catch\n", i.pc_offset());
|
||||||
@ -980,7 +982,7 @@ class SideTable : public ZoneObject {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprDelegate: {
|
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);
|
TRACE("control @%u: Delegate[depth=%u]\n", i.pc_offset(), imm.depth);
|
||||||
Control* c = &control_stack.back();
|
Control* c = &control_stack.back();
|
||||||
const size_t new_stack_size = control_stack.size() - 1;
|
const size_t new_stack_size = control_stack.size() - 1;
|
||||||
@ -1018,21 +1020,21 @@ class SideTable : public ZoneObject {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprBr: {
|
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);
|
TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), imm.depth);
|
||||||
Control* c = &control_stack[control_stack.size() - imm.depth - 1];
|
Control* c = &control_stack[control_stack.size() - imm.depth - 1];
|
||||||
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
|
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprBrIf: {
|
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);
|
TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), imm.depth);
|
||||||
Control* c = &control_stack[control_stack.size() - imm.depth - 1];
|
Control* c = &control_stack[control_stack.size() - imm.depth - 1];
|
||||||
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
|
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprBrTable: {
|
case kExprBrTable: {
|
||||||
BranchTableImmediate imm(&i, i.pc() + 1, kNoValidate);
|
BranchTableImmediate imm(&decoder, i.pc() + 1, kNoValidate);
|
||||||
BranchTableIterator<Decoder::NoValidationTag> iterator(&i, imm);
|
BranchTableIterator<Decoder::NoValidationTag> iterator(&i, imm);
|
||||||
TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
|
TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
|
||||||
imm.table_count);
|
imm.table_count);
|
||||||
|
Loading…
Reference in New Issue
Block a user