Commit 2c0edb48 authored by Ben L. Titzer's avatar Ben L. Titzer Committed by Commit Bot

[wasm] Rename XXXOperand to XXXImmediate

R=clemensh@chromium.org
CC=ahaas@chromium.org

Change-Id: Ibcbc5e43e7095d9783f49ad2c3f27338100c4fdf
Reviewed-on: https://chromium-review.googlesource.com/1039489
Commit-Queue: Ben Titzer <titzer@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52953}
parent 39496a95
...@@ -1089,21 +1089,20 @@ class LiftoffCompiler { ...@@ -1089,21 +1089,20 @@ class LiftoffCompiler {
} }
void GetLocal(Decoder* decoder, Value* result, void GetLocal(Decoder* decoder, Value* result,
const LocalIndexOperand<validate>& operand) { const LocalIndexImmediate<validate>& imm) {
auto& slot = __ cache_state()->stack_state[operand.index]; auto& slot = __ cache_state()->stack_state[imm.index];
DCHECK_EQ(slot.type(), operand.type); DCHECK_EQ(slot.type(), imm.type);
switch (slot.loc()) { switch (slot.loc()) {
case kRegister: case kRegister:
__ PushRegister(slot.type(), slot.reg()); __ PushRegister(slot.type(), slot.reg());
break; break;
case KIntConst: case KIntConst:
__ cache_state()->stack_state.emplace_back(operand.type, __ cache_state()->stack_state.emplace_back(imm.type, slot.i32_const());
slot.i32_const());
break; break;
case kStack: { case kStack: {
auto rc = reg_class_for(operand.type); auto rc = reg_class_for(imm.type);
LiftoffRegister reg = __ GetUnusedRegister(rc); LiftoffRegister reg = __ GetUnusedRegister(rc);
__ Fill(reg, operand.index, operand.type); __ Fill(reg, imm.index, imm.type);
__ PushRegister(slot.type(), reg); __ PushRegister(slot.type(), reg);
break; break;
} }
...@@ -1152,13 +1151,13 @@ class LiftoffCompiler { ...@@ -1152,13 +1151,13 @@ class LiftoffCompiler {
} }
void SetLocal(Decoder* decoder, const Value& value, void SetLocal(Decoder* decoder, const Value& value,
const LocalIndexOperand<validate>& operand) { const LocalIndexImmediate<validate>& imm) {
SetLocal(operand.index, false); SetLocal(imm.index, false);
} }
void TeeLocal(Decoder* decoder, const Value& value, Value* result, void TeeLocal(Decoder* decoder, const Value& value, Value* result,
const LocalIndexOperand<validate>& operand) { const LocalIndexImmediate<validate>& imm) {
SetLocal(operand.index, true); SetLocal(imm.index, true);
} }
LiftoffRegister GetGlobalBaseAndOffset(const WasmGlobal* global, LiftoffRegister GetGlobalBaseAndOffset(const WasmGlobal* global,
...@@ -1179,8 +1178,8 @@ class LiftoffCompiler { ...@@ -1179,8 +1178,8 @@ class LiftoffCompiler {
} }
void GetGlobal(Decoder* decoder, Value* result, void GetGlobal(Decoder* decoder, Value* result,
const GlobalIndexOperand<validate>& operand) { const GlobalIndexImmediate<validate>& imm) {
const auto* global = &env_->module->globals[operand.index]; const auto* global = &env_->module->globals[imm.index];
if (!CheckSupportedType(decoder, kTypes_ilfd, global->type, "global")) if (!CheckSupportedType(decoder, kTypes_ilfd, global->type, "global"))
return; return;
LiftoffRegList pinned; LiftoffRegList pinned;
...@@ -1194,8 +1193,8 @@ class LiftoffCompiler { ...@@ -1194,8 +1193,8 @@ class LiftoffCompiler {
} }
void SetGlobal(Decoder* decoder, const Value& value, void SetGlobal(Decoder* decoder, const Value& value,
const GlobalIndexOperand<validate>& operand) { const GlobalIndexImmediate<validate>& imm) {
auto* global = &env_->module->globals[operand.index]; auto* global = &env_->module->globals[imm.index];
if (!CheckSupportedType(decoder, kTypes_ilfd, global->type, "global")) if (!CheckSupportedType(decoder, kTypes_ilfd, global->type, "global"))
return; return;
LiftoffRegList pinned; LiftoffRegList pinned;
...@@ -1301,22 +1300,22 @@ class LiftoffCompiler { ...@@ -1301,22 +1300,22 @@ class LiftoffCompiler {
br_targets); br_targets);
} }
void BrTable(Decoder* decoder, const BranchTableOperand<validate>& operand, void BrTable(Decoder* decoder, const BranchTableImmediate<validate>& imm,
const Value& key) { const Value& key) {
LiftoffRegList pinned; LiftoffRegList pinned;
LiftoffRegister value = pinned.set(__ PopToRegister()); LiftoffRegister value = pinned.set(__ PopToRegister());
BranchTableIterator<validate> table_iterator(decoder, operand); BranchTableIterator<validate> table_iterator(decoder, imm);
std::map<uint32_t, MovableLabel> br_targets; std::map<uint32_t, MovableLabel> br_targets;
if (operand.table_count > 0) { if (imm.table_count > 0) {
LiftoffRegister tmp = __ GetUnusedRegister(kGpReg, pinned); LiftoffRegister tmp = __ GetUnusedRegister(kGpReg, pinned);
__ LoadConstant(tmp, WasmValue(uint32_t{operand.table_count})); __ LoadConstant(tmp, WasmValue(uint32_t{imm.table_count}));
Label case_default; Label case_default;
__ emit_cond_jump(kUnsignedGreaterEqual, &case_default, kWasmI32, __ emit_cond_jump(kUnsignedGreaterEqual, &case_default, kWasmI32,
value.gp(), tmp.gp()); value.gp(), tmp.gp());
GenerateBrTable(decoder, tmp, value, 0, operand.table_count, GenerateBrTable(decoder, tmp, value, 0, imm.table_count, table_iterator,
table_iterator, br_targets); br_targets);
__ bind(&case_default); __ bind(&case_default);
} }
...@@ -1467,13 +1466,13 @@ class LiftoffCompiler { ...@@ -1467,13 +1466,13 @@ class LiftoffCompiler {
} }
void LoadMem(Decoder* decoder, LoadType type, void LoadMem(Decoder* decoder, LoadType type,
const MemoryAccessOperand<validate>& operand, const MemoryAccessImmediate<validate>& imm,
const Value& index_val, Value* result) { const Value& index_val, Value* result) {
ValueType value_type = type.value_type(); ValueType value_type = type.value_type();
if (!CheckSupportedType(decoder, kTypes_ilfd, value_type, "load")) return; if (!CheckSupportedType(decoder, kTypes_ilfd, value_type, "load")) return;
LiftoffRegList pinned; LiftoffRegList pinned;
Register index = pinned.set(__ PopToRegister()).gp(); Register index = pinned.set(__ PopToRegister()).gp();
if (BoundsCheckMem(decoder, type.size(), operand.offset, index, pinned)) { if (BoundsCheckMem(decoder, type.size(), imm.offset, index, pinned)) {
return; return;
} }
LiftoffRegister addr = pinned.set(__ GetUnusedRegister(kGpReg, pinned)); LiftoffRegister addr = pinned.set(__ GetUnusedRegister(kGpReg, pinned));
...@@ -1481,7 +1480,7 @@ class LiftoffCompiler { ...@@ -1481,7 +1480,7 @@ class LiftoffCompiler {
RegClass rc = reg_class_for(value_type); RegClass rc = reg_class_for(value_type);
LiftoffRegister value = pinned.set(__ GetUnusedRegister(rc, pinned)); LiftoffRegister value = pinned.set(__ GetUnusedRegister(rc, pinned));
uint32_t protected_load_pc = 0; uint32_t protected_load_pc = 0;
__ Load(value, addr.gp(), index, operand.offset, type, pinned, __ Load(value, addr.gp(), index, imm.offset, type, pinned,
&protected_load_pc, true); &protected_load_pc, true);
if (env_->use_trap_handler) { if (env_->use_trap_handler) {
AddOutOfLineTrap(decoder->position(), AddOutOfLineTrap(decoder->position(),
...@@ -1492,25 +1491,25 @@ class LiftoffCompiler { ...@@ -1492,25 +1491,25 @@ class LiftoffCompiler {
if (FLAG_wasm_trace_memory) { if (FLAG_wasm_trace_memory) {
TraceMemoryOperation(false, type.mem_type().representation(), index, TraceMemoryOperation(false, type.mem_type().representation(), index,
operand.offset, decoder->position()); imm.offset, decoder->position());
} }
} }
void StoreMem(Decoder* decoder, StoreType type, void StoreMem(Decoder* decoder, StoreType type,
const MemoryAccessOperand<validate>& operand, const MemoryAccessImmediate<validate>& imm,
const Value& index_val, const Value& value_val) { const Value& index_val, const Value& value_val) {
ValueType value_type = type.value_type(); ValueType value_type = type.value_type();
if (!CheckSupportedType(decoder, kTypes_ilfd, value_type, "store")) return; if (!CheckSupportedType(decoder, kTypes_ilfd, value_type, "store")) return;
LiftoffRegList pinned; LiftoffRegList pinned;
LiftoffRegister value = pinned.set(__ PopToRegister()); LiftoffRegister value = pinned.set(__ PopToRegister());
Register index = pinned.set(__ PopToRegister(pinned)).gp(); Register index = pinned.set(__ PopToRegister(pinned)).gp();
if (BoundsCheckMem(decoder, type.size(), operand.offset, index, pinned)) { if (BoundsCheckMem(decoder, type.size(), imm.offset, index, pinned)) {
return; return;
} }
LiftoffRegister addr = pinned.set(__ GetUnusedRegister(kGpReg, pinned)); LiftoffRegister addr = pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LOAD_INSTANCE_FIELD(addr, MemoryStart, kPointerLoadType); LOAD_INSTANCE_FIELD(addr, MemoryStart, kPointerLoadType);
uint32_t protected_store_pc = 0; uint32_t protected_store_pc = 0;
__ Store(addr.gp(), index, operand.offset, value, type, pinned, __ Store(addr.gp(), index, imm.offset, value, type, pinned,
&protected_store_pc, true); &protected_store_pc, true);
if (env_->use_trap_handler) { if (env_->use_trap_handler) {
AddOutOfLineTrap(decoder->position(), AddOutOfLineTrap(decoder->position(),
...@@ -1518,7 +1517,7 @@ class LiftoffCompiler { ...@@ -1518,7 +1517,7 @@ class LiftoffCompiler {
protected_store_pc); protected_store_pc);
} }
if (FLAG_wasm_trace_memory) { if (FLAG_wasm_trace_memory) {
TraceMemoryOperation(true, type.mem_rep(), index, operand.offset, TraceMemoryOperation(true, type.mem_rep(), index, imm.offset,
decoder->position()); decoder->position());
} }
} }
...@@ -1540,22 +1539,21 @@ class LiftoffCompiler { ...@@ -1540,22 +1539,21 @@ class LiftoffCompiler {
unsupported(decoder, "grow_memory"); unsupported(decoder, "grow_memory");
} }
void CallDirect(Decoder* decoder, void CallDirect(Decoder* decoder, const CallFunctionImmediate<validate>& imm,
const CallFunctionOperand<validate>& operand,
const Value args[], Value returns[]) { const Value args[], Value returns[]) {
if (operand.sig->return_count() > 1) if (imm.sig->return_count() > 1)
return unsupported(decoder, "multi-return"); return unsupported(decoder, "multi-return");
if (operand.sig->return_count() == 1 && if (imm.sig->return_count() == 1 &&
!CheckSupportedType(decoder, kTypes_ilfd, operand.sig->GetReturn(0), !CheckSupportedType(decoder, kTypes_ilfd, imm.sig->GetReturn(0),
"return")) "return"))
return; return;
auto call_descriptor = auto call_descriptor =
compiler::GetWasmCallDescriptor(compilation_zone_, operand.sig); compiler::GetWasmCallDescriptor(compilation_zone_, imm.sig);
call_descriptor = call_descriptor =
GetLoweredCallDescriptor(compilation_zone_, call_descriptor); GetLoweredCallDescriptor(compilation_zone_, call_descriptor);
if (operand.index < env_->module->num_imported_functions) { if (imm.index < env_->module->num_imported_functions) {
// A direct call to an imported function. // A direct call to an imported function.
LiftoffRegList pinned; LiftoffRegList pinned;
LiftoffRegister tmp = pinned.set(__ GetUnusedRegister(kGpReg, pinned)); LiftoffRegister tmp = pinned.set(__ GetUnusedRegister(kGpReg, pinned));
...@@ -1565,55 +1563,54 @@ class LiftoffCompiler { ...@@ -1565,55 +1563,54 @@ class LiftoffCompiler {
LOAD_INSTANCE_FIELD(imported_targets, ImportedFunctionTargets, LOAD_INSTANCE_FIELD(imported_targets, ImportedFunctionTargets,
kPointerLoadType); kPointerLoadType);
__ Load(target, imported_targets.gp(), no_reg, __ Load(target, imported_targets.gp(), no_reg,
operand.index * sizeof(Address), kPointerLoadType, pinned); imm.index * sizeof(Address), kPointerLoadType, pinned);
LiftoffRegister imported_instances = tmp; LiftoffRegister imported_instances = tmp;
LOAD_INSTANCE_FIELD(imported_instances, ImportedFunctionInstances, LOAD_INSTANCE_FIELD(imported_instances, ImportedFunctionInstances,
kPointerLoadType); kPointerLoadType);
LiftoffRegister target_instance = tmp; LiftoffRegister target_instance = tmp;
__ Load(target_instance, imported_instances.gp(), no_reg, __ Load(target_instance, imported_instances.gp(), no_reg,
compiler::FixedArrayOffsetMinusTag(operand.index), compiler::FixedArrayOffsetMinusTag(imm.index), kPointerLoadType,
kPointerLoadType, pinned); pinned);
LiftoffRegister* explicit_instance = &target_instance; LiftoffRegister* explicit_instance = &target_instance;
Register target_reg = target.gp(); Register target_reg = target.gp();
__ PrepareCall(operand.sig, call_descriptor, &target_reg, __ PrepareCall(imm.sig, call_descriptor, &target_reg, explicit_instance);
explicit_instance);
source_position_table_builder_->AddPosition( source_position_table_builder_->AddPosition(
__ pc_offset(), SourcePosition(decoder->position()), false); __ pc_offset(), SourcePosition(decoder->position()), false);
__ CallIndirect(operand.sig, call_descriptor, target_reg); __ CallIndirect(imm.sig, call_descriptor, target_reg);
safepoint_table_builder_.DefineSafepoint(asm_, Safepoint::kSimple, 0, safepoint_table_builder_.DefineSafepoint(asm_, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
__ FinishCall(operand.sig, call_descriptor); __ FinishCall(imm.sig, call_descriptor);
} else { } else {
// A direct call within this module just gets the current instance. // A direct call within this module just gets the current instance.
__ PrepareCall(operand.sig, call_descriptor); __ PrepareCall(imm.sig, call_descriptor);
source_position_table_builder_->AddPosition( source_position_table_builder_->AddPosition(
__ pc_offset(), SourcePosition(decoder->position()), false); __ pc_offset(), SourcePosition(decoder->position()), false);
// Just encode the function index. This will be patched at instantiation. // Just encode the function index. This will be patched at instantiation.
Address addr = static_cast<Address>(operand.index); Address addr = static_cast<Address>(imm.index);
__ CallNativeWasmCode(addr); __ CallNativeWasmCode(addr);
safepoint_table_builder_.DefineSafepoint(asm_, Safepoint::kSimple, 0, safepoint_table_builder_.DefineSafepoint(asm_, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
__ FinishCall(operand.sig, call_descriptor); __ FinishCall(imm.sig, call_descriptor);
} }
} }
void CallIndirect(Decoder* decoder, const Value& index_val, void CallIndirect(Decoder* decoder, const Value& index_val,
const CallIndirectOperand<validate>& operand, const CallIndirectImmediate<validate>& imm,
const Value args[], Value returns[]) { const Value args[], Value returns[]) {
if (operand.sig->return_count() > 1) { if (imm.sig->return_count() > 1) {
return unsupported(decoder, "multi-return"); return unsupported(decoder, "multi-return");
} }
if (operand.sig->return_count() == 1 && if (imm.sig->return_count() == 1 &&
!CheckSupportedType(decoder, kTypes_ilfd, operand.sig->GetReturn(0), !CheckSupportedType(decoder, kTypes_ilfd, imm.sig->GetReturn(0),
"return")) { "return")) {
return; return;
} }
...@@ -1640,7 +1637,7 @@ class LiftoffCompiler { ...@@ -1640,7 +1637,7 @@ class LiftoffCompiler {
Label* invalid_func_label = AddOutOfLineTrap( Label* invalid_func_label = AddOutOfLineTrap(
decoder->position(), Builtins::kThrowWasmTrapFuncInvalid); decoder->position(), Builtins::kThrowWasmTrapFuncInvalid);
uint32_t canonical_sig_num = env_->module->signature_ids[operand.sig_index]; uint32_t canonical_sig_num = env_->module->signature_ids[imm.sig_index];
DCHECK_GE(canonical_sig_num, 0); DCHECK_GE(canonical_sig_num, 0);
DCHECK_GE(kMaxInt, canonical_sig_num); DCHECK_GE(kMaxInt, canonical_sig_num);
...@@ -1691,18 +1688,18 @@ class LiftoffCompiler { ...@@ -1691,18 +1688,18 @@ class LiftoffCompiler {
__ pc_offset(), SourcePosition(decoder->position()), false); __ pc_offset(), SourcePosition(decoder->position()), false);
auto call_descriptor = auto call_descriptor =
compiler::GetWasmCallDescriptor(compilation_zone_, operand.sig); compiler::GetWasmCallDescriptor(compilation_zone_, imm.sig);
call_descriptor = call_descriptor =
GetLoweredCallDescriptor(compilation_zone_, call_descriptor); GetLoweredCallDescriptor(compilation_zone_, call_descriptor);
Register target = scratch.gp(); Register target = scratch.gp();
__ PrepareCall(operand.sig, call_descriptor, &target, explicit_instance); __ PrepareCall(imm.sig, call_descriptor, &target, explicit_instance);
__ CallIndirect(operand.sig, call_descriptor, target); __ CallIndirect(imm.sig, call_descriptor, target);
safepoint_table_builder_.DefineSafepoint(asm_, Safepoint::kSimple, 0, safepoint_table_builder_.DefineSafepoint(asm_, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
__ FinishCall(operand.sig, call_descriptor); __ FinishCall(imm.sig, call_descriptor);
} }
void SimdOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args, void SimdOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args,
...@@ -1710,32 +1707,32 @@ class LiftoffCompiler { ...@@ -1710,32 +1707,32 @@ class LiftoffCompiler {
unsupported(decoder, "simd"); unsupported(decoder, "simd");
} }
void SimdLaneOp(Decoder* decoder, WasmOpcode opcode, void SimdLaneOp(Decoder* decoder, WasmOpcode opcode,
const SimdLaneOperand<validate>& operand, const SimdLaneImmediate<validate>& imm,
const Vector<Value> inputs, Value* result) { const Vector<Value> inputs, Value* result) {
unsupported(decoder, "simd"); unsupported(decoder, "simd");
} }
void SimdShiftOp(Decoder* decoder, WasmOpcode opcode, void SimdShiftOp(Decoder* decoder, WasmOpcode opcode,
const SimdShiftOperand<validate>& operand, const SimdShiftImmediate<validate>& imm, const Value& input,
const Value& input, Value* result) { Value* result) {
unsupported(decoder, "simd"); unsupported(decoder, "simd");
} }
void Simd8x16ShuffleOp(Decoder* decoder, void Simd8x16ShuffleOp(Decoder* decoder,
const Simd8x16ShuffleOperand<validate>& operand, const Simd8x16ShuffleImmediate<validate>& imm,
const Value& input0, const Value& input1, const Value& input0, const Value& input1,
Value* result) { Value* result) {
unsupported(decoder, "simd"); unsupported(decoder, "simd");
} }
void Throw(Decoder* decoder, const ExceptionIndexOperand<validate>&, void Throw(Decoder* decoder, const ExceptionIndexImmediate<validate>&,
Control* block, const Vector<Value>& args) { Control* block, const Vector<Value>& args) {
unsupported(decoder, "throw"); unsupported(decoder, "throw");
} }
void CatchException(Decoder* decoder, void CatchException(Decoder* decoder,
const ExceptionIndexOperand<validate>& operand, const ExceptionIndexImmediate<validate>& imm,
Control* block, Vector<Value> caught_values) { Control* block, Vector<Value> caught_values) {
unsupported(decoder, "catch"); unsupported(decoder, "catch");
} }
void AtomicOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args, void AtomicOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args,
const MemoryAccessOperand<validate>& operand, Value* result) { const MemoryAccessImmediate<validate>& imm, Value* result) {
unsupported(decoder, "atomicop"); unsupported(decoder, "atomicop");
} }
......
...@@ -126,53 +126,52 @@ Vector<T> vec2vec(std::vector<T, Allocator>& vec) { ...@@ -126,53 +126,52 @@ Vector<T> vec2vec(std::vector<T, Allocator>& vec) {
return Vector<T>(vec.data(), vec.size()); return Vector<T>(vec.data(), vec.size());
} }
// Helpers for decoding different kinds of immediates which follow bytecodes.
// Helpers for decoding different kinds of operands which follow bytecodes.
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct LocalIndexOperand { struct LocalIndexImmediate {
uint32_t index; uint32_t index;
ValueType type = kWasmStmt; ValueType type = kWasmStmt;
unsigned length; unsigned length;
inline LocalIndexOperand(Decoder* decoder, const byte* pc) { inline LocalIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "local index"); index = decoder->read_u32v<validate>(pc + 1, &length, "local index");
} }
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct ExceptionIndexOperand { struct ExceptionIndexImmediate {
uint32_t index; uint32_t index;
const WasmException* exception = nullptr; const WasmException* exception = nullptr;
unsigned length; unsigned length;
inline ExceptionIndexOperand(Decoder* decoder, const byte* pc) { inline ExceptionIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "exception index"); index = decoder->read_u32v<validate>(pc + 1, &length, "exception index");
} }
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct ImmI32Operand { struct ImmI32Immediate {
int32_t value; int32_t value;
unsigned length; unsigned length;
inline ImmI32Operand(Decoder* decoder, const byte* pc) { inline ImmI32Immediate(Decoder* decoder, const byte* pc) {
value = decoder->read_i32v<validate>(pc + 1, &length, "immi32"); value = decoder->read_i32v<validate>(pc + 1, &length, "immi32");
} }
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct ImmI64Operand { struct ImmI64Immediate {
int64_t value; int64_t value;
unsigned length; unsigned length;
inline ImmI64Operand(Decoder* decoder, const byte* pc) { inline ImmI64Immediate(Decoder* decoder, const byte* pc) {
value = decoder->read_i64v<validate>(pc + 1, &length, "immi64"); value = decoder->read_i64v<validate>(pc + 1, &length, "immi64");
} }
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct ImmF32Operand { struct ImmF32Immediate {
float value; float value;
unsigned length = 4; unsigned length = 4;
inline ImmF32Operand(Decoder* decoder, const byte* pc) { inline ImmF32Immediate(Decoder* decoder, const byte* pc) {
// Avoid bit_cast because it might not preserve the signalling bit of a NaN. // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
uint32_t tmp = decoder->read_u32<validate>(pc + 1, "immf32"); uint32_t tmp = decoder->read_u32<validate>(pc + 1, "immf32");
memcpy(&value, &tmp, sizeof(value)); memcpy(&value, &tmp, sizeof(value));
...@@ -180,10 +179,10 @@ struct ImmF32Operand { ...@@ -180,10 +179,10 @@ struct ImmF32Operand {
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct ImmF64Operand { struct ImmF64Immediate {
double value; double value;
unsigned length = 8; unsigned length = 8;
inline ImmF64Operand(Decoder* decoder, const byte* pc) { inline ImmF64Immediate(Decoder* decoder, const byte* pc) {
// Avoid bit_cast because it might not preserve the signalling bit of a NaN. // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
uint64_t tmp = decoder->read_u64<validate>(pc + 1, "immf64"); uint64_t tmp = decoder->read_u64<validate>(pc + 1, "immf64");
memcpy(&value, &tmp, sizeof(value)); memcpy(&value, &tmp, sizeof(value));
...@@ -191,25 +190,25 @@ struct ImmF64Operand { ...@@ -191,25 +190,25 @@ struct ImmF64Operand {
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct GlobalIndexOperand { struct GlobalIndexImmediate {
uint32_t index; uint32_t index;
ValueType type = kWasmStmt; ValueType type = kWasmStmt;
const WasmGlobal* global = nullptr; const WasmGlobal* global = nullptr;
unsigned length; unsigned length;
inline GlobalIndexOperand(Decoder* decoder, const byte* pc) { inline GlobalIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "global index"); index = decoder->read_u32v<validate>(pc + 1, &length, "global index");
} }
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct BlockTypeOperand { struct BlockTypeImmediate {
unsigned length = 1; unsigned length = 1;
ValueType type = kWasmStmt; ValueType type = kWasmStmt;
uint32_t sig_index = 0; uint32_t sig_index = 0;
FunctionSig* sig = nullptr; FunctionSig* sig = nullptr;
inline BlockTypeOperand(Decoder* decoder, const byte* pc) { inline BlockTypeImmediate(Decoder* decoder, const byte* pc) {
uint8_t val = decoder->read_u8<validate>(pc + 1, "block type"); uint8_t val = decoder->read_u8<validate>(pc + 1, "block type");
if (!decode_local_type(val, &type)) { if (!decode_local_type(val, &type)) {
// Handle multi-value blocks. // Handle multi-value blocks.
...@@ -280,21 +279,21 @@ struct BlockTypeOperand { ...@@ -280,21 +279,21 @@ struct BlockTypeOperand {
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct BreakDepthOperand { struct BreakDepthImmediate {
uint32_t depth; uint32_t depth;
unsigned length; unsigned length;
inline BreakDepthOperand(Decoder* decoder, const byte* pc) { inline BreakDepthImmediate(Decoder* decoder, const byte* pc) {
depth = decoder->read_u32v<validate>(pc + 1, &length, "break depth"); depth = decoder->read_u32v<validate>(pc + 1, &length, "break depth");
} }
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct CallIndirectOperand { struct CallIndirectImmediate {
uint32_t table_index; uint32_t table_index;
uint32_t sig_index; uint32_t sig_index;
FunctionSig* sig = nullptr; FunctionSig* sig = nullptr;
unsigned length = 0; unsigned length = 0;
inline CallIndirectOperand(Decoder* decoder, const byte* pc) { inline CallIndirectImmediate(Decoder* decoder, const byte* pc) {
unsigned len = 0; unsigned len = 0;
sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index"); sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index");
if (!VALIDATE(decoder->ok())) return; if (!VALIDATE(decoder->ok())) return;
...@@ -308,20 +307,20 @@ struct CallIndirectOperand { ...@@ -308,20 +307,20 @@ struct CallIndirectOperand {
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct CallFunctionOperand { struct CallFunctionImmediate {
uint32_t index; uint32_t index;
FunctionSig* sig = nullptr; FunctionSig* sig = nullptr;
unsigned length; unsigned length;
inline CallFunctionOperand(Decoder* decoder, const byte* pc) { inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc + 1, &length, "function index"); index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
} }
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct MemoryIndexOperand { struct MemoryIndexImmediate {
uint32_t index; uint32_t index;
unsigned length = 1; unsigned length = 1;
inline MemoryIndexOperand(Decoder* decoder, const byte* pc) { inline MemoryIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u8<validate>(pc + 1, "memory index"); index = decoder->read_u8<validate>(pc + 1, "memory index");
if (!VALIDATE(index == 0)) { if (!VALIDATE(index == 0)) {
decoder->errorf(pc + 1, "expected memory index 0, found %u", index); decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
...@@ -330,11 +329,11 @@ struct MemoryIndexOperand { ...@@ -330,11 +329,11 @@ struct MemoryIndexOperand {
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct BranchTableOperand { struct BranchTableImmediate {
uint32_t table_count; uint32_t table_count;
const byte* start; const byte* start;
const byte* table; const byte* table;
inline BranchTableOperand(Decoder* decoder, const byte* pc) { inline BranchTableImmediate(Decoder* decoder, const byte* pc) {
DCHECK_EQ(kExprBrTable, decoder->read_u8<validate>(pc, "opcode")); DCHECK_EQ(kExprBrTable, decoder->read_u8<validate>(pc, "opcode"));
start = pc + 1; start = pc + 1;
unsigned len = 0; unsigned len = 0;
...@@ -358,7 +357,7 @@ class BranchTableIterator { ...@@ -358,7 +357,7 @@ class BranchTableIterator {
pc_ += length; pc_ += length;
return result; return result;
} }
// length, including the length of the {BranchTableOperand}, but not the // length, including the length of the {BranchTableImmediate}, but not the
// opcode. // opcode.
unsigned length() { unsigned length() {
while (has_next()) next(); while (has_next()) next();
...@@ -367,12 +366,12 @@ class BranchTableIterator { ...@@ -367,12 +366,12 @@ class BranchTableIterator {
const byte* pc() { return pc_; } const byte* pc() { return pc_; }
BranchTableIterator(Decoder* decoder, BranchTableIterator(Decoder* decoder,
const BranchTableOperand<validate>& operand) const BranchTableImmediate<validate>& imm)
: decoder_(decoder), : decoder_(decoder),
start_(operand.start), start_(imm.start),
pc_(operand.table), pc_(imm.table),
index_(0), index_(0),
table_count_(operand.table_count) {} table_count_(imm.table_count) {}
private: private:
Decoder* decoder_; Decoder* decoder_;
...@@ -383,11 +382,11 @@ class BranchTableIterator { ...@@ -383,11 +382,11 @@ class BranchTableIterator {
}; };
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct MemoryAccessOperand { struct MemoryAccessImmediate {
uint32_t alignment; uint32_t alignment;
uint32_t offset; uint32_t offset;
unsigned length = 0; unsigned length = 0;
inline MemoryAccessOperand(Decoder* decoder, const byte* pc, inline MemoryAccessImmediate(Decoder* decoder, const byte* pc,
uint32_t max_alignment) { uint32_t max_alignment) {
unsigned alignment_length; unsigned alignment_length;
alignment = alignment =
...@@ -406,34 +405,34 @@ struct MemoryAccessOperand { ...@@ -406,34 +405,34 @@ struct MemoryAccessOperand {
} }
}; };
// Operand for SIMD lane operations. // Immediate for SIMD lane operations.
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct SimdLaneOperand { struct SimdLaneImmediate {
uint8_t lane; uint8_t lane;
unsigned length = 1; unsigned length = 1;
inline SimdLaneOperand(Decoder* decoder, const byte* pc) { inline SimdLaneImmediate(Decoder* decoder, const byte* pc) {
lane = decoder->read_u8<validate>(pc + 2, "lane"); lane = decoder->read_u8<validate>(pc + 2, "lane");
} }
}; };
// Operand for SIMD shift operations. // Immediate for SIMD shift operations.
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct SimdShiftOperand { struct SimdShiftImmediate {
uint8_t shift; uint8_t shift;
unsigned length = 1; unsigned length = 1;
inline SimdShiftOperand(Decoder* decoder, const byte* pc) { inline SimdShiftImmediate(Decoder* decoder, const byte* pc) {
shift = decoder->read_u8<validate>(pc + 2, "shift"); shift = decoder->read_u8<validate>(pc + 2, "shift");
} }
}; };
// Operand for SIMD S8x16 shuffle operations. // Immediate for SIMD S8x16 shuffle operations.
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct Simd8x16ShuffleOperand { struct Simd8x16ShuffleImmediate {
uint8_t shuffle[kSimd128Size] = {0}; uint8_t shuffle[kSimd128Size] = {0};
inline Simd8x16ShuffleOperand(Decoder* decoder, const byte* pc) { inline Simd8x16ShuffleImmediate(Decoder* decoder, const byte* pc) {
for (uint32_t i = 0; i < kSimd128Size; ++i) { for (uint32_t i = 0; i < kSimd128Size; ++i) {
shuffle[i] = decoder->read_u8<validate>(pc + 2 + i, "shuffle"); shuffle[i] = decoder->read_u8<validate>(pc + 2 + i, "shuffle");
if (!VALIDATE(decoder->ok())) return; if (!VALIDATE(decoder->ok())) return;
...@@ -616,46 +615,45 @@ struct ControlWithNamedConstructors : public ControlBase<Value> { ...@@ -616,46 +615,45 @@ struct ControlWithNamedConstructors : public ControlBase<Value> {
F(RefNull, Value* result) \ F(RefNull, Value* result) \
F(Drop, const Value& value) \ F(Drop, const Value& value) \
F(DoReturn, Vector<Value> values, bool implicit) \ F(DoReturn, Vector<Value> values, bool implicit) \
F(GetLocal, Value* result, const LocalIndexOperand<validate>& operand) \ F(GetLocal, Value* result, const LocalIndexImmediate<validate>& imm) \
F(SetLocal, const Value& value, const LocalIndexOperand<validate>& operand) \ F(SetLocal, const Value& value, const LocalIndexImmediate<validate>& imm) \
F(TeeLocal, const Value& value, Value* result, \ F(TeeLocal, const Value& value, Value* result, \
const LocalIndexOperand<validate>& operand) \ const LocalIndexImmediate<validate>& imm) \
F(GetGlobal, Value* result, const GlobalIndexOperand<validate>& operand) \ F(GetGlobal, Value* result, const GlobalIndexImmediate<validate>& imm) \
F(SetGlobal, const Value& value, \ F(SetGlobal, const Value& value, const GlobalIndexImmediate<validate>& imm) \
const GlobalIndexOperand<validate>& operand) \
F(Unreachable) \ F(Unreachable) \
F(Select, const Value& cond, const Value& fval, const Value& tval, \ F(Select, const Value& cond, const Value& fval, const Value& tval, \
Value* result) \ Value* result) \
F(Br, Control* target) \ F(Br, Control* target) \
F(BrIf, const Value& cond, Control* target) \ F(BrIf, const Value& cond, Control* target) \
F(BrTable, const BranchTableOperand<validate>& operand, const Value& key) \ F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \
F(Else, Control* if_block) \ F(Else, Control* if_block) \
F(LoadMem, LoadType type, const MemoryAccessOperand<validate>& operand, \ F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \
const Value& index, Value* result) \ const Value& index, Value* result) \
F(StoreMem, StoreType type, const MemoryAccessOperand<validate>& operand, \ F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \
const Value& index, const Value& value) \ const Value& index, const Value& value) \
F(CurrentMemoryPages, Value* result) \ F(CurrentMemoryPages, Value* result) \
F(GrowMemory, const Value& value, Value* result) \ F(GrowMemory, const Value& value, Value* result) \
F(CallDirect, const CallFunctionOperand<validate>& operand, \ F(CallDirect, const CallFunctionImmediate<validate>& imm, \
const Value args[], Value returns[]) \ const Value args[], Value returns[]) \
F(CallIndirect, const Value& index, \ F(CallIndirect, const Value& index, \
const CallIndirectOperand<validate>& operand, const Value args[], \ const CallIndirectImmediate<validate>& imm, const Value args[], \
Value returns[]) \ Value returns[]) \
F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result) \ F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result) \
F(SimdLaneOp, WasmOpcode opcode, const SimdLaneOperand<validate>& operand, \ F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
const Vector<Value> inputs, Value* result) \ const Vector<Value> inputs, Value* result) \
F(SimdShiftOp, WasmOpcode opcode, const SimdShiftOperand<validate>& operand, \ F(SimdShiftOp, WasmOpcode opcode, const SimdShiftImmediate<validate>& imm, \
const Value& input, Value* result) \ const Value& input, Value* result) \
F(Simd8x16ShuffleOp, const Simd8x16ShuffleOperand<validate>& operand, \ F(Simd8x16ShuffleOp, const Simd8x16ShuffleImmediate<validate>& imm, \
const Value& input0, const Value& input1, Value* result) \ const Value& input0, const Value& input1, Value* result) \
F(Throw, const ExceptionIndexOperand<validate>&, Control* block, \ F(Throw, const ExceptionIndexImmediate<validate>&, Control* block, \
const Vector<Value>& args) \ const Vector<Value>& args) \
F(CatchException, const ExceptionIndexOperand<validate>& operand, \ F(CatchException, const ExceptionIndexImmediate<validate>& imm, \
Control* block, Vector<Value> caught_values) \ Control* block, Vector<Value> caught_values) \
F(AtomicOp, WasmOpcode opcode, Vector<Value> args, \ F(AtomicOp, WasmOpcode opcode, Vector<Value> args, \
const MemoryAccessOperand<validate>& operand, Value* result) const MemoryAccessImmediate<validate>& imm, Value* result)
// Generic Wasm bytecode decoder with utilities for decoding operands, // Generic Wasm bytecode decoder with utilities for decoding immediates,
// lengths, etc. // lengths, etc.
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
class WasmDecoder : public Decoder { class WasmDecoder : public Decoder {
...@@ -762,13 +760,13 @@ class WasmDecoder : public Decoder { ...@@ -762,13 +760,13 @@ class WasmDecoder : public Decoder {
break; break;
case kExprSetLocal: // fallthru case kExprSetLocal: // fallthru
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand<Decoder::kValidate> operand(decoder, pc); LocalIndexImmediate<Decoder::kValidate> imm(decoder, pc);
if (assigned->length() > 0 && if (assigned->length() > 0 &&
operand.index < static_cast<uint32_t>(assigned->length())) { imm.index < static_cast<uint32_t>(assigned->length())) {
// Unverified code might have an out-of-bounds index. // Unverified code might have an out-of-bounds index.
assigned->Add(operand.index); assigned->Add(imm.index);
} }
length = 1 + operand.length; length = 1 + imm.length;
break; break;
} }
case kExprGrowMemory: case kExprGrowMemory:
...@@ -793,96 +791,94 @@ class WasmDecoder : public Decoder { ...@@ -793,96 +791,94 @@ class WasmDecoder : public Decoder {
} }
inline bool Validate(const byte* pc, inline bool Validate(const byte* pc,
LocalIndexOperand<Decoder::kValidate>& operand) { LocalIndexImmediate<Decoder::kValidate>& imm) {
if (!VALIDATE(operand.index < total_locals())) { if (!VALIDATE(imm.index < total_locals())) {
errorf(pc + 1, "invalid local index: %u", operand.index); errorf(pc + 1, "invalid local index: %u", imm.index);
return false; return false;
} }
operand.type = local_types_ ? local_types_->at(operand.index) : kWasmStmt; imm.type = local_types_ ? local_types_->at(imm.index) : kWasmStmt;
return true; return true;
} }
inline bool Validate(const byte* pc, inline bool Validate(const byte* pc, ExceptionIndexImmediate<validate>& imm) {
ExceptionIndexOperand<validate>& operand) {
if (!VALIDATE(module_ != nullptr && if (!VALIDATE(module_ != nullptr &&
operand.index < module_->exceptions.size())) { imm.index < module_->exceptions.size())) {
errorf(pc + 1, "Invalid exception index: %u", operand.index); errorf(pc + 1, "Invalid exception index: %u", imm.index);
return false; return false;
} }
operand.exception = &module_->exceptions[operand.index]; imm.exception = &module_->exceptions[imm.index];
return true; return true;
} }
inline bool Validate(const byte* pc, GlobalIndexOperand<validate>& operand) { inline bool Validate(const byte* pc, GlobalIndexImmediate<validate>& imm) {
if (!VALIDATE(module_ != nullptr && if (!VALIDATE(module_ != nullptr && imm.index < module_->globals.size())) {
operand.index < module_->globals.size())) { errorf(pc + 1, "invalid global index: %u", imm.index);
errorf(pc + 1, "invalid global index: %u", operand.index);
return false; return false;
} }
operand.global = &module_->globals[operand.index]; imm.global = &module_->globals[imm.index];
operand.type = operand.global->type; imm.type = imm.global->type;
return true; return true;
} }
inline bool Complete(const byte* pc, CallFunctionOperand<validate>& operand) { inline bool Complete(const byte* pc, CallFunctionImmediate<validate>& imm) {
if (!VALIDATE(module_ != nullptr && if (!VALIDATE(module_ != nullptr &&
operand.index < module_->functions.size())) { imm.index < module_->functions.size())) {
return false; return false;
} }
operand.sig = module_->functions[operand.index].sig; imm.sig = module_->functions[imm.index].sig;
return true; return true;
} }
inline bool Validate(const byte* pc, CallFunctionOperand<validate>& operand) { inline bool Validate(const byte* pc, CallFunctionImmediate<validate>& imm) {
if (Complete(pc, operand)) { if (Complete(pc, imm)) {
return true; return true;
} }
errorf(pc + 1, "invalid function index: %u", operand.index); errorf(pc + 1, "invalid function index: %u", imm.index);
return false; return false;
} }
inline bool Complete(const byte* pc, CallIndirectOperand<validate>& operand) { inline bool Complete(const byte* pc, CallIndirectImmediate<validate>& imm) {
if (!VALIDATE(module_ != nullptr && if (!VALIDATE(module_ != nullptr &&
operand.sig_index < module_->signatures.size())) { imm.sig_index < module_->signatures.size())) {
return false; return false;
} }
operand.sig = module_->signatures[operand.sig_index]; imm.sig = module_->signatures[imm.sig_index];
return true; return true;
} }
inline bool Validate(const byte* pc, CallIndirectOperand<validate>& operand) { inline bool Validate(const byte* pc, CallIndirectImmediate<validate>& imm) {
if (!VALIDATE(module_ != nullptr && !module_->function_tables.empty())) { if (!VALIDATE(module_ != nullptr && !module_->function_tables.empty())) {
error("function table has to exist to execute call_indirect"); error("function table has to exist to execute call_indirect");
return false; return false;
} }
if (!Complete(pc, operand)) { if (!Complete(pc, imm)) {
errorf(pc + 1, "invalid signature index: #%u", operand.sig_index); errorf(pc + 1, "invalid signature index: #%u", imm.sig_index);
return false; return false;
} }
return true; return true;
} }
inline bool Validate(const byte* pc, BreakDepthOperand<validate>& operand, inline bool Validate(const byte* pc, BreakDepthImmediate<validate>& imm,
size_t control_depth) { size_t control_depth) {
if (!VALIDATE(operand.depth < control_depth)) { if (!VALIDATE(imm.depth < control_depth)) {
errorf(pc + 1, "invalid break depth: %u", operand.depth); errorf(pc + 1, "invalid break depth: %u", imm.depth);
return false; return false;
} }
return true; return true;
} }
bool Validate(const byte* pc, BranchTableOperand<validate>& operand, bool Validate(const byte* pc, BranchTableImmediate<validate>& imm,
size_t block_depth) { size_t block_depth) {
if (!VALIDATE(operand.table_count < kV8MaxWasmFunctionSize)) { if (!VALIDATE(imm.table_count < kV8MaxWasmFunctionSize)) {
errorf(pc + 1, "invalid table count (> max function size): %u", errorf(pc + 1, "invalid table count (> max function size): %u",
operand.table_count); imm.table_count);
return false; return false;
} }
return checkAvailable(operand.table_count); return checkAvailable(imm.table_count);
} }
inline bool Validate(const byte* pc, WasmOpcode opcode, inline bool Validate(const byte* pc, WasmOpcode opcode,
SimdLaneOperand<validate>& operand) { SimdLaneImmediate<validate>& imm) {
uint8_t num_lanes = 0; uint8_t num_lanes = 0;
switch (opcode) { switch (opcode) {
case kExprF32x4ExtractLane: case kExprF32x4ExtractLane:
...@@ -903,7 +899,7 @@ class WasmDecoder : public Decoder { ...@@ -903,7 +899,7 @@ class WasmDecoder : public Decoder {
UNREACHABLE(); UNREACHABLE();
break; break;
} }
if (!VALIDATE(operand.lane >= 0 && operand.lane < num_lanes)) { if (!VALIDATE(imm.lane >= 0 && imm.lane < num_lanes)) {
error(pc_ + 2, "invalid lane index"); error(pc_ + 2, "invalid lane index");
return false; return false;
} else { } else {
...@@ -912,7 +908,7 @@ class WasmDecoder : public Decoder { ...@@ -912,7 +908,7 @@ class WasmDecoder : public Decoder {
} }
inline bool Validate(const byte* pc, WasmOpcode opcode, inline bool Validate(const byte* pc, WasmOpcode opcode,
SimdShiftOperand<validate>& operand) { SimdShiftImmediate<validate>& imm) {
uint8_t max_shift = 0; uint8_t max_shift = 0;
switch (opcode) { switch (opcode) {
case kExprI32x4Shl: case kExprI32x4Shl:
...@@ -934,7 +930,7 @@ class WasmDecoder : public Decoder { ...@@ -934,7 +930,7 @@ class WasmDecoder : public Decoder {
UNREACHABLE(); UNREACHABLE();
break; break;
} }
if (!VALIDATE(operand.shift >= 0 && operand.shift < max_shift)) { if (!VALIDATE(imm.shift >= 0 && imm.shift < max_shift)) {
error(pc_ + 2, "invalid shift amount"); error(pc_ + 2, "invalid shift amount");
return false; return false;
} else { } else {
...@@ -943,10 +939,10 @@ class WasmDecoder : public Decoder { ...@@ -943,10 +939,10 @@ class WasmDecoder : public Decoder {
} }
inline bool Validate(const byte* pc, inline bool Validate(const byte* pc,
Simd8x16ShuffleOperand<validate>& operand) { Simd8x16ShuffleImmediate<validate>& imm) {
uint8_t max_lane = 0; uint8_t max_lane = 0;
for (uint32_t i = 0; i < kSimd128Size; ++i) for (uint32_t i = 0; i < kSimd128Size; ++i)
max_lane = std::max(max_lane, operand.shuffle[i]); max_lane = std::max(max_lane, imm.shuffle[i]);
// Shuffle indices must be in [0..31] for a 16 lane shuffle. // Shuffle indices must be in [0..31] for a 16 lane shuffle.
if (!VALIDATE(max_lane <= 2 * kSimd128Size)) { if (!VALIDATE(max_lane <= 2 * kSimd128Size)) {
error(pc_ + 2, "invalid shuffle mask"); error(pc_ + 2, "invalid shuffle mask");
...@@ -963,69 +959,69 @@ class WasmDecoder : public Decoder { ...@@ -963,69 +959,69 @@ class WasmDecoder : public Decoder {
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE #undef DECLARE_OPCODE_CASE
{ {
MemoryAccessOperand<validate> operand(decoder, pc, UINT32_MAX); MemoryAccessImmediate<validate> imm(decoder, pc, UINT32_MAX);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprBr: case kExprBr:
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand<validate> operand(decoder, pc); BreakDepthImmediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprSetGlobal: case kExprSetGlobal:
case kExprGetGlobal: { case kExprGetGlobal: {
GlobalIndexOperand<validate> operand(decoder, pc); GlobalIndexImmediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand<validate> operand(decoder, pc); CallFunctionImmediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand<validate> operand(decoder, pc); CallIndirectImmediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprTry: case kExprTry:
case kExprIf: // fall through case kExprIf: // fall through
case kExprLoop: case kExprLoop:
case kExprBlock: { case kExprBlock: {
BlockTypeOperand<validate> operand(decoder, pc); BlockTypeImmediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprThrow: case kExprThrow:
case kExprCatch: { case kExprCatch: {
ExceptionIndexOperand<validate> operand(decoder, pc); ExceptionIndexImmediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprSetLocal: case kExprSetLocal:
case kExprTeeLocal: case kExprTeeLocal:
case kExprGetLocal: { case kExprGetLocal: {
LocalIndexOperand<Decoder::kValidate> operand(decoder, pc); LocalIndexImmediate<Decoder::kValidate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand<validate> operand(decoder, pc); BranchTableImmediate<validate> imm(decoder, pc);
BranchTableIterator<validate> iterator(decoder, operand); BranchTableIterator<validate> iterator(decoder, imm);
return 1 + iterator.length(); return 1 + iterator.length();
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand<validate> operand(decoder, pc); ImmI32Immediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprI64Const: { case kExprI64Const: {
ImmI64Operand<validate> operand(decoder, pc); ImmI64Immediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprRefNull: { case kExprRefNull: {
return 1; return 1;
} }
case kExprGrowMemory: case kExprGrowMemory:
case kExprMemorySize: { case kExprMemorySize: {
MemoryIndexOperand<validate> operand(decoder, pc); MemoryIndexImmediate<validate> imm(decoder, pc);
return 1 + operand.length; return 1 + imm.length;
} }
case kExprF32Const: case kExprF32Const:
return 5; return 5;
...@@ -1050,8 +1046,8 @@ class WasmDecoder : public Decoder { ...@@ -1050,8 +1046,8 @@ class WasmDecoder : public Decoder {
FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE) FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE #undef DECLARE_OPCODE_CASE
{ {
MemoryAccessOperand<validate> operand(decoder, pc + 1, UINT32_MAX); MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
return 2 + operand.length; return 2 + imm.length;
} }
// Shuffles require a byte per lane, or 16 immediate bytes. // Shuffles require a byte per lane, or 16 immediate bytes.
case kExprS8x16Shuffle: case kExprS8x16Shuffle:
...@@ -1070,8 +1066,8 @@ class WasmDecoder : public Decoder { ...@@ -1070,8 +1066,8 @@ class WasmDecoder : public Decoder {
FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE) FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE #undef DECLARE_OPCODE_CASE
{ {
MemoryAccessOperand<validate> operand(decoder, pc + 1, UINT32_MAX); MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
return 2 + operand.length; return 2 + imm.length;
} }
default: default:
decoder->error(pc, "invalid Atomics opcode"); decoder->error(pc, "invalid Atomics opcode");
...@@ -1118,16 +1114,16 @@ class WasmDecoder : public Decoder { ...@@ -1118,16 +1114,16 @@ class WasmDecoder : public Decoder {
case kExprMemorySize: case kExprMemorySize:
return {0, 1}; return {0, 1};
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand<validate> operand(this, pc); CallFunctionImmediate<validate> imm(this, pc);
CHECK(Complete(pc, operand)); CHECK(Complete(pc, imm));
return {operand.sig->parameter_count(), operand.sig->return_count()}; return {imm.sig->parameter_count(), imm.sig->return_count()};
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand<validate> operand(this, pc); CallIndirectImmediate<validate> imm(this, pc);
CHECK(Complete(pc, operand)); CHECK(Complete(pc, imm));
// Indirect calls pop an additional argument for the table index. // Indirect calls pop an additional argument for the table index.
return {operand.sig->parameter_count() + 1, return {imm.sig->parameter_count() + 1,
operand.sig->return_count()}; imm.sig->return_count()};
} }
case kExprBr: case kExprBr:
case kExprBlock: case kExprBlock:
...@@ -1413,14 +1409,14 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1413,14 +1409,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
case kExprNop: case kExprNop:
break; break;
case kExprBlock: { case kExprBlock: {
BlockTypeOperand<validate> operand(this, this->pc_); BlockTypeImmediate<validate> imm(this, this->pc_);
if (!LookupBlockType(&operand)) break; if (!LookupBlockType(&imm)) break;
PopArgs(operand.sig); PopArgs(imm.sig);
auto* block = PushBlock(); auto* block = PushBlock();
SetBlockType(block, operand); SetBlockType(block, imm);
CALL_INTERFACE_IF_REACHABLE(Block, block); CALL_INTERFACE_IF_REACHABLE(Block, block);
PushMergeValues(block, &block->start_merge); PushMergeValues(block, &block->start_merge);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprRethrow: { case kExprRethrow: {
...@@ -1431,23 +1427,23 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1431,23 +1427,23 @@ class WasmFullDecoder : public WasmDecoder<validate> {
} }
case kExprThrow: { case kExprThrow: {
CHECK_PROTOTYPE_OPCODE(eh); CHECK_PROTOTYPE_OPCODE(eh);
ExceptionIndexOperand<Decoder::kValidate> operand(this, this->pc_); ExceptionIndexImmediate<Decoder::kValidate> imm(this, this->pc_);
len = 1 + operand.length; len = 1 + imm.length;
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
PopArgs(operand.exception->ToFunctionSig()); PopArgs(imm.exception->ToFunctionSig());
CALL_INTERFACE_IF_REACHABLE(Throw, operand, &control_.back(), CALL_INTERFACE_IF_REACHABLE(Throw, imm, &control_.back(),
vec2vec(args_)); vec2vec(args_));
EndControl(); EndControl();
break; break;
} }
case kExprTry: { case kExprTry: {
CHECK_PROTOTYPE_OPCODE(eh); CHECK_PROTOTYPE_OPCODE(eh);
BlockTypeOperand<validate> operand(this, this->pc_); BlockTypeImmediate<validate> imm(this, this->pc_);
if (!LookupBlockType(&operand)) break; if (!LookupBlockType(&imm)) break;
PopArgs(operand.sig); PopArgs(imm.sig);
auto* try_block = PushTry(); auto* try_block = PushTry();
SetBlockType(try_block, operand); SetBlockType(try_block, imm);
len = 1 + operand.length; len = 1 + imm.length;
CALL_INTERFACE_IF_REACHABLE(Try, try_block); CALL_INTERFACE_IF_REACHABLE(Try, try_block);
PushMergeValues(try_block, &try_block->start_merge); PushMergeValues(try_block, &try_block->start_merge);
break; break;
...@@ -1455,10 +1451,10 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1455,10 +1451,10 @@ class WasmFullDecoder : public WasmDecoder<validate> {
case kExprCatch: { case kExprCatch: {
// TODO(kschimpf): Fix to use type signature of exception. // TODO(kschimpf): Fix to use type signature of exception.
CHECK_PROTOTYPE_OPCODE(eh); CHECK_PROTOTYPE_OPCODE(eh);
ExceptionIndexOperand<Decoder::kValidate> operand(this, this->pc_); ExceptionIndexImmediate<Decoder::kValidate> imm(this, this->pc_);
len = 1 + operand.length; len = 1 + imm.length;
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
if (!VALIDATE(!control_.empty())) { if (!VALIDATE(!control_.empty())) {
this->error("catch does not match any try"); this->error("catch does not match any try");
...@@ -1478,14 +1474,13 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1478,14 +1474,13 @@ class WasmFullDecoder : public WasmDecoder<validate> {
c->kind = kControlTryCatch; c->kind = kControlTryCatch;
FallThruTo(c); FallThruTo(c);
stack_.resize(c->stack_depth); stack_.resize(c->stack_depth);
const WasmExceptionSig* sig = operand.exception->sig; const WasmExceptionSig* sig = imm.exception->sig;
for (size_t i = 0, e = sig->parameter_count(); i < e; ++i) { for (size_t i = 0, e = sig->parameter_count(); i < e; ++i) {
Push(sig->GetParam(i)); Push(sig->GetParam(i));
} }
Vector<Value> values(stack_.data() + c->stack_depth, Vector<Value> values(stack_.data() + c->stack_depth,
sig->parameter_count()); sig->parameter_count());
CALL_INTERFACE_IF_PARENT_REACHABLE(CatchException, operand, c, CALL_INTERFACE_IF_PARENT_REACHABLE(CatchException, imm, c, values);
values);
c->reachability = control_at(1)->innerReachability(); c->reachability = control_at(1)->innerReachability();
break; break;
} }
...@@ -1496,26 +1491,26 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1496,26 +1491,26 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break; break;
} }
case kExprLoop: { case kExprLoop: {
BlockTypeOperand<validate> operand(this, this->pc_); BlockTypeImmediate<validate> imm(this, this->pc_);
if (!LookupBlockType(&operand)) break; if (!LookupBlockType(&imm)) break;
PopArgs(operand.sig); PopArgs(imm.sig);
auto* block = PushLoop(); auto* block = PushLoop();
SetBlockType(&control_.back(), operand); SetBlockType(&control_.back(), imm);
len = 1 + operand.length; len = 1 + imm.length;
CALL_INTERFACE_IF_REACHABLE(Loop, block); CALL_INTERFACE_IF_REACHABLE(Loop, block);
PushMergeValues(block, &block->start_merge); PushMergeValues(block, &block->start_merge);
break; break;
} }
case kExprIf: { case kExprIf: {
BlockTypeOperand<validate> operand(this, this->pc_); BlockTypeImmediate<validate> imm(this, this->pc_);
if (!LookupBlockType(&operand)) break; if (!LookupBlockType(&imm)) break;
auto cond = Pop(0, kWasmI32); auto cond = Pop(0, kWasmI32);
PopArgs(operand.sig); PopArgs(imm.sig);
if (!this->ok()) break; if (!this->ok()) break;
auto* if_block = PushIf(); auto* if_block = PushIf();
SetBlockType(if_block, operand); SetBlockType(if_block, imm);
CALL_INTERFACE_IF_REACHABLE(If, cond, if_block); CALL_INTERFACE_IF_REACHABLE(If, cond, if_block);
len = 1 + operand.length; len = 1 + imm.length;
PushMergeValues(if_block, &if_block->start_merge); PushMergeValues(if_block, &if_block->start_merge);
break; break;
} }
...@@ -1588,38 +1583,38 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1588,38 +1583,38 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break; break;
} }
case kExprBr: { case kExprBr: {
BreakDepthOperand<validate> operand(this, this->pc_); BreakDepthImmediate<validate> imm(this, this->pc_);
if (!this->Validate(this->pc_, operand, control_.size())) break; if (!this->Validate(this->pc_, imm, control_.size())) break;
Control* c = control_at(operand.depth); Control* c = control_at(imm.depth);
if (!TypeCheckBreak(c)) break; if (!TypeCheckBreak(c)) break;
if (control_.back().reachable()) { if (control_.back().reachable()) {
CALL_INTERFACE(Br, c); CALL_INTERFACE(Br, c);
c->br_merge()->reached = true; c->br_merge()->reached = true;
} }
len = 1 + operand.length; len = 1 + imm.length;
EndControl(); EndControl();
break; break;
} }
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand<validate> operand(this, this->pc_); BreakDepthImmediate<validate> imm(this, this->pc_);
auto cond = Pop(0, kWasmI32); auto cond = Pop(0, kWasmI32);
if (this->failed()) break; if (this->failed()) break;
if (!this->Validate(this->pc_, operand, control_.size())) break; if (!this->Validate(this->pc_, imm, control_.size())) break;
Control* c = control_at(operand.depth); Control* c = control_at(imm.depth);
if (!TypeCheckBreak(c)) break; if (!TypeCheckBreak(c)) break;
if (control_.back().reachable()) { if (control_.back().reachable()) {
CALL_INTERFACE(BrIf, cond, c); CALL_INTERFACE(BrIf, cond, c);
c->br_merge()->reached = true; c->br_merge()->reached = true;
} }
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand<validate> operand(this, this->pc_); BranchTableImmediate<validate> imm(this, this->pc_);
BranchTableIterator<validate> iterator(this, operand); BranchTableIterator<validate> iterator(this, imm);
auto key = Pop(0, kWasmI32); auto key = Pop(0, kWasmI32);
if (this->failed()) break; if (this->failed()) break;
if (!this->Validate(this->pc_, operand, control_.size())) break; if (!this->Validate(this->pc_, imm, control_.size())) break;
uint32_t br_arity = 0; uint32_t br_arity = 0;
std::vector<bool> br_targets(control_.size()); std::vector<bool> br_targets(control_.size());
while (iterator.has_next()) { while (iterator.has_next()) {
...@@ -1651,7 +1646,7 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1651,7 +1646,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (this->failed()) break; if (this->failed()) break;
if (control_.back().reachable()) { if (control_.back().reachable()) {
CALL_INTERFACE(BrTable, operand, key); CALL_INTERFACE(BrTable, imm, key);
for (uint32_t depth = control_depth(); depth-- > 0;) { for (uint32_t depth = control_depth(); depth-- > 0;) {
if (!br_targets[depth]) continue; if (!br_targets[depth]) continue;
...@@ -1673,31 +1668,31 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1673,31 +1668,31 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break; break;
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand<validate> operand(this, this->pc_); ImmI32Immediate<validate> imm(this, this->pc_);
auto* value = Push(kWasmI32); auto* value = Push(kWasmI32);
CALL_INTERFACE_IF_REACHABLE(I32Const, value, operand.value); CALL_INTERFACE_IF_REACHABLE(I32Const, value, imm.value);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprI64Const: { case kExprI64Const: {
ImmI64Operand<validate> operand(this, this->pc_); ImmI64Immediate<validate> imm(this, this->pc_);
auto* value = Push(kWasmI64); auto* value = Push(kWasmI64);
CALL_INTERFACE_IF_REACHABLE(I64Const, value, operand.value); CALL_INTERFACE_IF_REACHABLE(I64Const, value, imm.value);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprF32Const: { case kExprF32Const: {
ImmF32Operand<validate> operand(this, this->pc_); ImmF32Immediate<validate> imm(this, this->pc_);
auto* value = Push(kWasmF32); auto* value = Push(kWasmF32);
CALL_INTERFACE_IF_REACHABLE(F32Const, value, operand.value); CALL_INTERFACE_IF_REACHABLE(F32Const, value, imm.value);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprF64Const: { case kExprF64Const: {
ImmF64Operand<validate> operand(this, this->pc_); ImmF64Immediate<validate> imm(this, this->pc_);
auto* value = Push(kWasmF64); auto* value = Push(kWasmF64);
CALL_INTERFACE_IF_REACHABLE(F64Const, value, operand.value); CALL_INTERFACE_IF_REACHABLE(F64Const, value, imm.value);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprRefNull: { case kExprRefNull: {
...@@ -1708,28 +1703,28 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1708,28 +1703,28 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break; break;
} }
case kExprGetLocal: { case kExprGetLocal: {
LocalIndexOperand<Decoder::kValidate> operand(this, this->pc_); LocalIndexImmediate<Decoder::kValidate> imm(this, this->pc_);
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
auto* value = Push(operand.type); auto* value = Push(imm.type);
CALL_INTERFACE_IF_REACHABLE(GetLocal, value, operand); CALL_INTERFACE_IF_REACHABLE(GetLocal, value, imm);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprSetLocal: { case kExprSetLocal: {
LocalIndexOperand<Decoder::kValidate> operand(this, this->pc_); LocalIndexImmediate<Decoder::kValidate> imm(this, this->pc_);
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
auto value = Pop(0, local_type_vec_[operand.index]); auto value = Pop(0, local_type_vec_[imm.index]);
CALL_INTERFACE_IF_REACHABLE(SetLocal, value, operand); CALL_INTERFACE_IF_REACHABLE(SetLocal, value, imm);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand<Decoder::kValidate> operand(this, this->pc_); LocalIndexImmediate<Decoder::kValidate> imm(this, this->pc_);
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
auto value = Pop(0, local_type_vec_[operand.index]); auto value = Pop(0, local_type_vec_[imm.index]);
auto* result = Push(value.type); auto* result = Push(value.type);
CALL_INTERFACE_IF_REACHABLE(TeeLocal, value, result, operand); CALL_INTERFACE_IF_REACHABLE(TeeLocal, value, result, imm);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprDrop: { case kExprDrop: {
...@@ -1738,24 +1733,24 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1738,24 +1733,24 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break; break;
} }
case kExprGetGlobal: { case kExprGetGlobal: {
GlobalIndexOperand<validate> operand(this, this->pc_); GlobalIndexImmediate<validate> imm(this, this->pc_);
len = 1 + operand.length; len = 1 + imm.length;
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
auto* result = Push(operand.type); auto* result = Push(imm.type);
CALL_INTERFACE_IF_REACHABLE(GetGlobal, result, operand); CALL_INTERFACE_IF_REACHABLE(GetGlobal, result, imm);
break; break;
} }
case kExprSetGlobal: { case kExprSetGlobal: {
GlobalIndexOperand<validate> operand(this, this->pc_); GlobalIndexImmediate<validate> imm(this, this->pc_);
len = 1 + operand.length; len = 1 + imm.length;
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
if (!VALIDATE(operand.global->mutability)) { if (!VALIDATE(imm.global->mutability)) {
this->errorf(this->pc_, "immutable global #%u cannot be assigned", this->errorf(this->pc_, "immutable global #%u cannot be assigned",
operand.index); imm.index);
break; break;
} }
auto value = Pop(0, operand.type); auto value = Pop(0, imm.type);
CALL_INTERFACE_IF_REACHABLE(SetGlobal, value, operand); CALL_INTERFACE_IF_REACHABLE(SetGlobal, value, imm);
break; break;
} }
case kExprI32LoadMem8S: case kExprI32LoadMem8S:
...@@ -1829,8 +1824,8 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1829,8 +1824,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break; break;
case kExprGrowMemory: { case kExprGrowMemory: {
if (!CheckHasMemory()) break; if (!CheckHasMemory()) break;
MemoryIndexOperand<validate> operand(this, this->pc_); MemoryIndexImmediate<validate> imm(this, this->pc_);
len = 1 + operand.length; len = 1 + imm.length;
DCHECK_NOT_NULL(this->module_); DCHECK_NOT_NULL(this->module_);
if (!VALIDATE(this->module_->is_wasm())) { if (!VALIDATE(this->module_->is_wasm())) {
this->error("grow_memory is not supported for asmjs modules"); this->error("grow_memory is not supported for asmjs modules");
...@@ -1843,32 +1838,31 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1843,32 +1838,31 @@ class WasmFullDecoder : public WasmDecoder<validate> {
} }
case kExprMemorySize: { case kExprMemorySize: {
if (!CheckHasMemory()) break; if (!CheckHasMemory()) break;
MemoryIndexOperand<validate> operand(this, this->pc_); MemoryIndexImmediate<validate> imm(this, this->pc_);
auto* result = Push(kWasmI32); auto* result = Push(kWasmI32);
len = 1 + operand.length; len = 1 + imm.length;
CALL_INTERFACE_IF_REACHABLE(CurrentMemoryPages, result); CALL_INTERFACE_IF_REACHABLE(CurrentMemoryPages, result);
break; break;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand<validate> operand(this, this->pc_); CallFunctionImmediate<validate> imm(this, this->pc_);
len = 1 + operand.length; len = 1 + imm.length;
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
// TODO(clemensh): Better memory management. // TODO(clemensh): Better memory management.
PopArgs(operand.sig); PopArgs(imm.sig);
auto* returns = PushReturns(operand.sig); auto* returns = PushReturns(imm.sig);
CALL_INTERFACE_IF_REACHABLE(CallDirect, operand, args_.data(), CALL_INTERFACE_IF_REACHABLE(CallDirect, imm, args_.data(), returns);
returns);
break; break;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand<validate> operand(this, this->pc_); CallIndirectImmediate<validate> imm(this, this->pc_);
len = 1 + operand.length; len = 1 + imm.length;
if (!this->Validate(this->pc_, operand)) break; if (!this->Validate(this->pc_, imm)) break;
auto index = Pop(0, kWasmI32); auto index = Pop(0, kWasmI32);
PopArgs(operand.sig); PopArgs(imm.sig);
auto* returns = PushReturns(operand.sig); auto* returns = PushReturns(imm.sig);
CALL_INTERFACE_IF_REACHABLE(CallIndirect, index, operand, CALL_INTERFACE_IF_REACHABLE(CallIndirect, index, imm, args_.data(),
args_.data(), returns); returns);
break; break;
} }
case kNumericPrefix: { case kNumericPrefix: {
...@@ -1960,26 +1954,26 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1960,26 +1954,26 @@ class WasmFullDecoder : public WasmDecoder<validate> {
TRACE_PART(" %c@%d:%s", ValueTypes::ShortNameOf(val.type), TRACE_PART(" %c@%d:%s", ValueTypes::ShortNameOf(val.type),
static_cast<int>(val.pc - this->start_), static_cast<int>(val.pc - this->start_),
WasmOpcodes::OpcodeName(opcode)); WasmOpcodes::OpcodeName(opcode));
// If the decoder failed, don't try to decode the operands, as this // If the decoder failed, don't try to decode the immediates, as this
// can trigger a DCHECK failure. // can trigger a DCHECK failure.
if (this->failed()) continue; if (this->failed()) continue;
switch (opcode) { switch (opcode) {
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand<Decoder::kNoValidate> operand(this, val.pc); ImmI32Immediate<Decoder::kNoValidate> imm(this, val.pc);
TRACE_PART("[%d]", operand.value); TRACE_PART("[%d]", imm.value);
break; break;
} }
case kExprGetLocal: case kExprGetLocal:
case kExprSetLocal: case kExprSetLocal:
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand<Decoder::kNoValidate> operand(this, val.pc); LocalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
TRACE_PART("[%u]", operand.index); TRACE_PART("[%u]", imm.index);
break; break;
} }
case kExprGetGlobal: case kExprGetGlobal:
case kExprSetGlobal: { case kExprSetGlobal: {
GlobalIndexOperand<Decoder::kNoValidate> operand(this, val.pc); GlobalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
TRACE_PART("[%u]", operand.index); TRACE_PART("[%u]", imm.index);
break; break;
} }
default: default:
...@@ -2001,18 +1995,18 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2001,18 +1995,18 @@ class WasmFullDecoder : public WasmDecoder<validate> {
current->reachability = kUnreachable; current->reachability = kUnreachable;
} }
bool LookupBlockType(BlockTypeOperand<validate>* operand) { bool LookupBlockType(BlockTypeImmediate<validate>* imm) {
if (operand->type == kWasmVar) { if (imm->type == kWasmVar) {
if (!VALIDATE(this->module_ && if (!VALIDATE(this->module_ &&
operand->sig_index < this->module_->signatures.size())) { imm->sig_index < this->module_->signatures.size())) {
this->errorf( this->errorf(
this->pc_, "block type index %u out of bounds (%d signatures)", this->pc_, "block type index %u out of bounds (%d signatures)",
operand->sig_index, imm->sig_index,
static_cast<int>(this->module_ static_cast<int>(this->module_ ? this->module_->signatures.size()
? this->module_->signatures.size() : 0)); : 0));
return false; return false;
} }
operand->sig = this->module_->signatures[operand->sig_index]; imm->sig = this->module_->signatures[imm->sig_index];
} }
return true; return true;
} }
...@@ -2030,14 +2024,14 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2030,14 +2024,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
} }
} }
void SetBlockType(Control* c, BlockTypeOperand<validate>& operand) { void SetBlockType(Control* c, BlockTypeImmediate<validate>& imm) {
DCHECK_EQ(operand.in_arity(), this->args_.size()); DCHECK_EQ(imm.in_arity(), this->args_.size());
const byte* pc = this->pc_; const byte* pc = this->pc_;
Value* args = this->args_.data(); Value* args = this->args_.data();
InitMerge(&c->end_merge, operand.out_arity(), [pc, &operand](uint32_t i) { InitMerge(&c->end_merge, imm.out_arity(), [pc, &imm](uint32_t i) {
return Value::New(pc, operand.out_type(i)); return Value::New(pc, imm.out_type(i));
}); });
InitMerge(&c->start_merge, operand.in_arity(), InitMerge(&c->start_merge, imm.in_arity(),
[args](uint32_t i) { return args[i]; }); [args](uint32_t i) { return args[i]; });
} }
...@@ -2093,65 +2087,65 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2093,65 +2087,65 @@ class WasmFullDecoder : public WasmDecoder<validate> {
int DecodeLoadMem(LoadType type, int prefix_len = 0) { int DecodeLoadMem(LoadType type, int prefix_len = 0) {
if (!CheckHasMemory()) return 0; if (!CheckHasMemory()) return 0;
MemoryAccessOperand<validate> operand(this, this->pc_ + prefix_len, MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
type.size_log_2()); type.size_log_2());
auto index = Pop(0, kWasmI32); auto index = Pop(0, kWasmI32);
auto* result = Push(type.value_type()); auto* result = Push(type.value_type());
CALL_INTERFACE_IF_REACHABLE(LoadMem, type, operand, index, result); CALL_INTERFACE_IF_REACHABLE(LoadMem, type, imm, index, result);
return operand.length; return imm.length;
} }
int DecodeStoreMem(StoreType store, int prefix_len = 0) { int DecodeStoreMem(StoreType store, int prefix_len = 0) {
if (!CheckHasMemory()) return 0; if (!CheckHasMemory()) return 0;
MemoryAccessOperand<validate> operand(this, this->pc_ + prefix_len, MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
store.size_log_2()); store.size_log_2());
auto value = Pop(1, store.value_type()); auto value = Pop(1, store.value_type());
auto index = Pop(0, kWasmI32); auto index = Pop(0, kWasmI32);
CALL_INTERFACE_IF_REACHABLE(StoreMem, store, operand, index, value); CALL_INTERFACE_IF_REACHABLE(StoreMem, store, imm, index, value);
return operand.length; return imm.length;
} }
unsigned SimdExtractLane(WasmOpcode opcode, ValueType type) { unsigned SimdExtractLane(WasmOpcode opcode, ValueType type) {
SimdLaneOperand<validate> operand(this, this->pc_); SimdLaneImmediate<validate> imm(this, this->pc_);
if (this->Validate(this->pc_, opcode, operand)) { if (this->Validate(this->pc_, opcode, imm)) {
Value inputs[] = {Pop(0, ValueType::kSimd128)}; Value inputs[] = {Pop(0, ValueType::kSimd128)};
auto* result = Push(type); auto* result = Push(type);
CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, operand, CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
ArrayVector(inputs), result); result);
} }
return operand.length; return imm.length;
} }
unsigned SimdReplaceLane(WasmOpcode opcode, ValueType type) { unsigned SimdReplaceLane(WasmOpcode opcode, ValueType type) {
SimdLaneOperand<validate> operand(this, this->pc_); SimdLaneImmediate<validate> imm(this, this->pc_);
if (this->Validate(this->pc_, opcode, operand)) { if (this->Validate(this->pc_, opcode, imm)) {
Value inputs[2]; Value inputs[2];
inputs[1] = Pop(1, type); inputs[1] = Pop(1, type);
inputs[0] = Pop(0, ValueType::kSimd128); inputs[0] = Pop(0, ValueType::kSimd128);
auto* result = Push(ValueType::kSimd128); auto* result = Push(ValueType::kSimd128);
CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, operand, CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
ArrayVector(inputs), result); result);
} }
return operand.length; return imm.length;
} }
unsigned SimdShiftOp(WasmOpcode opcode) { unsigned SimdShiftOp(WasmOpcode opcode) {
SimdShiftOperand<validate> operand(this, this->pc_); SimdShiftImmediate<validate> imm(this, this->pc_);
if (this->Validate(this->pc_, opcode, operand)) { if (this->Validate(this->pc_, opcode, imm)) {
auto input = Pop(0, ValueType::kSimd128); auto input = Pop(0, ValueType::kSimd128);
auto* result = Push(ValueType::kSimd128); auto* result = Push(ValueType::kSimd128);
CALL_INTERFACE_IF_REACHABLE(SimdShiftOp, opcode, operand, input, result); CALL_INTERFACE_IF_REACHABLE(SimdShiftOp, opcode, imm, input, result);
} }
return operand.length; return imm.length;
} }
unsigned Simd8x16ShuffleOp() { unsigned Simd8x16ShuffleOp() {
Simd8x16ShuffleOperand<validate> operand(this, this->pc_); Simd8x16ShuffleImmediate<validate> imm(this, this->pc_);
if (this->Validate(this->pc_, operand)) { if (this->Validate(this->pc_, imm)) {
auto input1 = Pop(1, ValueType::kSimd128); auto input1 = Pop(1, ValueType::kSimd128);
auto input0 = Pop(0, ValueType::kSimd128); auto input0 = Pop(0, ValueType::kSimd128);
auto* result = Push(ValueType::kSimd128); auto* result = Push(ValueType::kSimd128);
CALL_INTERFACE_IF_REACHABLE(Simd8x16ShuffleOp, operand, input0, input1, CALL_INTERFACE_IF_REACHABLE(Simd8x16ShuffleOp, imm, input0, input1,
result); result);
} }
return 16; return 16;
...@@ -2244,14 +2238,14 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2244,14 +2238,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
this->error("invalid atomic opcode"); this->error("invalid atomic opcode");
return 0; return 0;
} }
MemoryAccessOperand<validate> operand( MemoryAccessImmediate<validate> imm(
this, this->pc_ + 1, ElementSizeLog2Of(memtype.representation())); this, this->pc_ + 1, ElementSizeLog2Of(memtype.representation()));
len += operand.length; len += imm.length;
PopArgs(sig); PopArgs(sig);
auto result = ret_type == MachineRepresentation::kNone auto result = ret_type == MachineRepresentation::kNone
? nullptr ? nullptr
: Push(GetReturnType(sig)); : Push(GetReturnType(sig));
CALL_INTERFACE_IF_REACHABLE(AtomicOp, opcode, vec2vec(args_), operand, CALL_INTERFACE_IF_REACHABLE(AtomicOp, opcode, vec2vec(args_), imm,
result); result);
} else { } else {
this->error("invalid atomic opcode"); this->error("invalid atomic opcode");
......
...@@ -251,32 +251,32 @@ class WasmGraphBuildingInterface { ...@@ -251,32 +251,32 @@ class WasmGraphBuildingInterface {
} }
void GetLocal(Decoder* decoder, Value* result, void GetLocal(Decoder* decoder, Value* result,
const LocalIndexOperand<validate>& operand) { const LocalIndexImmediate<validate>& imm) {
if (!ssa_env_->locals) return; // unreachable if (!ssa_env_->locals) return; // unreachable
result->node = ssa_env_->locals[operand.index]; result->node = ssa_env_->locals[imm.index];
} }
void SetLocal(Decoder* decoder, const Value& value, void SetLocal(Decoder* decoder, const Value& value,
const LocalIndexOperand<validate>& operand) { const LocalIndexImmediate<validate>& imm) {
if (!ssa_env_->locals) return; // unreachable if (!ssa_env_->locals) return; // unreachable
ssa_env_->locals[operand.index] = value.node; ssa_env_->locals[imm.index] = value.node;
} }
void TeeLocal(Decoder* decoder, const Value& value, Value* result, void TeeLocal(Decoder* decoder, const Value& value, Value* result,
const LocalIndexOperand<validate>& operand) { const LocalIndexImmediate<validate>& imm) {
result->node = value.node; result->node = value.node;
if (!ssa_env_->locals) return; // unreachable if (!ssa_env_->locals) return; // unreachable
ssa_env_->locals[operand.index] = value.node; ssa_env_->locals[imm.index] = value.node;
} }
void GetGlobal(Decoder* decoder, Value* result, void GetGlobal(Decoder* decoder, Value* result,
const GlobalIndexOperand<validate>& operand) { const GlobalIndexImmediate<validate>& imm) {
result->node = BUILD(GetGlobal, operand.index); result->node = BUILD(GetGlobal, imm.index);
} }
void SetGlobal(Decoder* decoder, const Value& value, void SetGlobal(Decoder* decoder, const Value& value,
const GlobalIndexOperand<validate>& operand) { const GlobalIndexImmediate<validate>& imm) {
BUILD(SetGlobal, operand.index, value.node); BUILD(SetGlobal, imm.index, value.node);
} }
void Unreachable(Decoder* decoder) { void Unreachable(Decoder* decoder) {
...@@ -308,28 +308,28 @@ class WasmGraphBuildingInterface { ...@@ -308,28 +308,28 @@ class WasmGraphBuildingInterface {
ssa_env_ = fenv; ssa_env_ = fenv;
} }
void BrTable(Decoder* decoder, const BranchTableOperand<validate>& operand, void BrTable(Decoder* decoder, const BranchTableImmediate<validate>& imm,
const Value& key) { const Value& key) {
if (operand.table_count == 0) { if (imm.table_count == 0) {
// Only a default target. Do the equivalent of br. // Only a default target. Do the equivalent of br.
uint32_t target = BranchTableIterator<validate>(decoder, operand).next(); uint32_t target = BranchTableIterator<validate>(decoder, imm).next();
Br(decoder, decoder->control_at(target)); Br(decoder, decoder->control_at(target));
return; return;
} }
SsaEnv* break_env = ssa_env_; SsaEnv* break_env = ssa_env_;
// Build branches to the various blocks based on the table. // Build branches to the various blocks based on the table.
TFNode* sw = BUILD(Switch, operand.table_count + 1, key.node); TFNode* sw = BUILD(Switch, imm.table_count + 1, key.node);
SsaEnv* copy = Steal(decoder->zone(), break_env); SsaEnv* copy = Steal(decoder->zone(), break_env);
ssa_env_ = copy; ssa_env_ = copy;
BranchTableIterator<validate> iterator(decoder, operand); BranchTableIterator<validate> iterator(decoder, imm);
while (iterator.has_next()) { while (iterator.has_next()) {
uint32_t i = iterator.cur_index(); uint32_t i = iterator.cur_index();
uint32_t target = iterator.next(); uint32_t target = iterator.next();
ssa_env_ = Split(decoder, copy); ssa_env_ = Split(decoder, copy);
ssa_env_->control = (i == operand.table_count) ? BUILD(IfDefault, sw) ssa_env_->control =
: BUILD(IfValue, i, sw); (i == imm.table_count) ? BUILD(IfDefault, sw) : BUILD(IfValue, i, sw);
Br(decoder, decoder->control_at(target)); Br(decoder, decoder->control_at(target));
} }
DCHECK(decoder->ok()); DCHECK(decoder->ok());
...@@ -341,19 +341,18 @@ class WasmGraphBuildingInterface { ...@@ -341,19 +341,18 @@ class WasmGraphBuildingInterface {
} }
void LoadMem(Decoder* decoder, LoadType type, void LoadMem(Decoder* decoder, LoadType type,
const MemoryAccessOperand<validate>& operand, const Value& index, const MemoryAccessImmediate<validate>& imm, const Value& index,
Value* result) { Value* result) {
result->node = result->node =
BUILD(LoadMem, type.value_type(), type.mem_type(), index.node, BUILD(LoadMem, type.value_type(), type.mem_type(), index.node,
operand.offset, operand.alignment, decoder->position()); imm.offset, imm.alignment, decoder->position());
} }
void StoreMem(Decoder* decoder, StoreType type, void StoreMem(Decoder* decoder, StoreType type,
const MemoryAccessOperand<validate>& operand, const MemoryAccessImmediate<validate>& imm, const Value& index,
const Value& index, const Value& value) { const Value& value) {
BUILD(StoreMem, type.mem_rep(), index.node, operand.offset, BUILD(StoreMem, type.mem_rep(), index.node, imm.offset, imm.alignment,
operand.alignment, value.node, decoder->position(), value.node, decoder->position(), type.value_type());
type.value_type());
} }
void CurrentMemoryPages(Decoder* decoder, Value* result) { void CurrentMemoryPages(Decoder* decoder, Value* result) {
...@@ -366,16 +365,15 @@ class WasmGraphBuildingInterface { ...@@ -366,16 +365,15 @@ class WasmGraphBuildingInterface {
LoadContextIntoSsa(ssa_env_); LoadContextIntoSsa(ssa_env_);
} }
void CallDirect(Decoder* decoder, void CallDirect(Decoder* decoder, const CallFunctionImmediate<validate>& imm,
const CallFunctionOperand<validate>& operand,
const Value args[], Value returns[]) { const Value args[], Value returns[]) {
DoCall(decoder, nullptr, operand.sig, operand.index, args, returns); DoCall(decoder, nullptr, imm.sig, imm.index, args, returns);
} }
void CallIndirect(Decoder* decoder, const Value& index, void CallIndirect(Decoder* decoder, const Value& index,
const CallIndirectOperand<validate>& operand, const CallIndirectImmediate<validate>& imm,
const Value args[], Value returns[]) { const Value args[], Value returns[]) {
DoCall(decoder, index.node, operand.sig, operand.sig_index, args, returns); DoCall(decoder, index.node, imm.sig, imm.sig_index, args, returns);
} }
void SimdOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args, void SimdOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args,
...@@ -386,48 +384,48 @@ class WasmGraphBuildingInterface { ...@@ -386,48 +384,48 @@ class WasmGraphBuildingInterface {
} }
void SimdLaneOp(Decoder* decoder, WasmOpcode opcode, void SimdLaneOp(Decoder* decoder, WasmOpcode opcode,
const SimdLaneOperand<validate> operand, Vector<Value> inputs, const SimdLaneImmediate<validate> imm, Vector<Value> inputs,
Value* result) { Value* result) {
TFNode** nodes = GetNodes(inputs); TFNode** nodes = GetNodes(inputs);
result->node = BUILD(SimdLaneOp, opcode, operand.lane, nodes); result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes);
} }
void SimdShiftOp(Decoder* decoder, WasmOpcode opcode, void SimdShiftOp(Decoder* decoder, WasmOpcode opcode,
const SimdShiftOperand<validate> operand, const Value& input, const SimdShiftImmediate<validate> imm, const Value& input,
Value* result) { Value* result) {
TFNode* inputs[] = {input.node}; TFNode* inputs[] = {input.node};
result->node = BUILD(SimdShiftOp, opcode, operand.shift, inputs); result->node = BUILD(SimdShiftOp, opcode, imm.shift, inputs);
} }
void Simd8x16ShuffleOp(Decoder* decoder, void Simd8x16ShuffleOp(Decoder* decoder,
const Simd8x16ShuffleOperand<validate>& operand, const Simd8x16ShuffleImmediate<validate>& imm,
const Value& input0, const Value& input1, const Value& input0, const Value& input1,
Value* result) { Value* result) {
TFNode* input_nodes[] = {input0.node, input1.node}; TFNode* input_nodes[] = {input0.node, input1.node};
result->node = BUILD(Simd8x16ShuffleOp, operand.shuffle, input_nodes); result->node = BUILD(Simd8x16ShuffleOp, imm.shuffle, input_nodes);
} }
TFNode* GetExceptionTag(Decoder* decoder, TFNode* GetExceptionTag(Decoder* decoder,
const ExceptionIndexOperand<validate>& operand) { const ExceptionIndexImmediate<validate>& imm) {
// TODO(kschimpf): Need to get runtime exception tag values. This // TODO(kschimpf): Need to get runtime exception tag values. This
// code only handles non-imported/exported exceptions. // code only handles non-imported/exported exceptions.
return BUILD(Int32Constant, operand.index); return BUILD(Int32Constant, imm.index);
} }
void Throw(Decoder* decoder, const ExceptionIndexOperand<validate>& operand, void Throw(Decoder* decoder, const ExceptionIndexImmediate<validate>& imm,
Control* block, const Vector<Value>& value_args) { Control* block, const Vector<Value>& value_args) {
int count = value_args.length(); int count = value_args.length();
ZoneVector<TFNode*> args(count, decoder->zone()); ZoneVector<TFNode*> args(count, decoder->zone());
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
args[i] = value_args[i].node; args[i] = value_args[i].node;
} }
BUILD(Throw, operand.index, operand.exception, vec2vec(args)); BUILD(Throw, imm.index, imm.exception, vec2vec(args));
Unreachable(decoder); Unreachable(decoder);
EndControl(decoder, block); EndControl(decoder, block);
} }
void CatchException(Decoder* decoder, void CatchException(Decoder* decoder,
const ExceptionIndexOperand<validate>& operand, const ExceptionIndexImmediate<validate>& imm,
Control* block, Vector<Value> values) { Control* block, Vector<Value> values) {
DCHECK(block->is_try_catch()); DCHECK(block->is_try_catch());
current_catch_ = block->previous_catch; current_catch_ = block->previous_catch;
...@@ -447,8 +445,7 @@ class WasmGraphBuildingInterface { ...@@ -447,8 +445,7 @@ class WasmGraphBuildingInterface {
} else { } else {
// Get the exception and see if wanted exception. // Get the exception and see if wanted exception.
TFNode* caught_tag = BUILD(GetExceptionRuntimeId); TFNode* caught_tag = BUILD(GetExceptionRuntimeId);
TFNode* exception_tag = TFNode* exception_tag = BUILD(ConvertExceptionTagToRuntimeId, imm.index);
BUILD(ConvertExceptionTagToRuntimeId, operand.index);
compare_i32 = BUILD(Binop, kExprI32Eq, caught_tag, exception_tag); compare_i32 = BUILD(Binop, kExprI32Eq, caught_tag, exception_tag);
} }
...@@ -479,7 +476,7 @@ class WasmGraphBuildingInterface { ...@@ -479,7 +476,7 @@ class WasmGraphBuildingInterface {
} else { } else {
// TODO(kschimpf): Can't use BUILD() here, GetExceptionValues() returns // TODO(kschimpf): Can't use BUILD() here, GetExceptionValues() returns
// TFNode** rather than TFNode*. Fix to add landing pads. // TFNode** rather than TFNode*. Fix to add landing pads.
TFNode** caught_values = builder_->GetExceptionValues(operand.exception); TFNode** caught_values = builder_->GetExceptionValues(imm.exception);
for (size_t i = 0, e = values.size(); i < e; ++i) { for (size_t i = 0, e = values.size(); i < e; ++i) {
values[i].node = caught_values[i]; values[i].node = caught_values[i];
} }
...@@ -487,10 +484,10 @@ class WasmGraphBuildingInterface { ...@@ -487,10 +484,10 @@ class WasmGraphBuildingInterface {
} }
void AtomicOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args, void AtomicOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args,
const MemoryAccessOperand<validate>& operand, Value* result) { const MemoryAccessImmediate<validate>& imm, Value* result) {
TFNode** inputs = GetNodes(args); TFNode** inputs = GetNodes(args);
TFNode* node = BUILD(AtomicOp, opcode, inputs, operand.alignment, TFNode* node = BUILD(AtomicOp, opcode, inputs, imm.alignment, imm.offset,
operand.offset, decoder->position()); decoder->position());
if (result) result->node = node; if (result) result->node = node;
} }
...@@ -996,10 +993,10 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, ...@@ -996,10 +993,10 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
case kExprIf: case kExprIf:
case kExprBlock: case kExprBlock:
case kExprTry: { case kExprTry: {
BlockTypeOperand<Decoder::kNoValidate> operand(&i, i.pc()); BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << " // @" << i.pc_offset(); os << " // @" << i.pc_offset();
for (unsigned i = 0; i < operand.out_arity(); i++) { for (unsigned i = 0; i < imm.out_arity(); i++) {
os << " " << ValueTypes::TypeName(operand.out_type(i)); os << " " << ValueTypes::TypeName(imm.out_type(i));
} }
control_depth++; control_depth++;
break; break;
...@@ -1009,33 +1006,33 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, ...@@ -1009,33 +1006,33 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
control_depth--; control_depth--;
break; break;
case kExprBr: { case kExprBr: {
BreakDepthOperand<Decoder::kNoValidate> operand(&i, i.pc()); BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << " // depth=" << operand.depth; os << " // depth=" << imm.depth;
break; break;
} }
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand<Decoder::kNoValidate> operand(&i, i.pc()); BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << " // depth=" << operand.depth; os << " // depth=" << imm.depth;
break; break;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand<Decoder::kNoValidate> operand(&i, i.pc()); BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << " // entries=" << operand.table_count; os << " // entries=" << imm.table_count;
break; break;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand<Decoder::kNoValidate> operand(&i, i.pc()); CallIndirectImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << " // sig #" << operand.sig_index; os << " // sig #" << imm.sig_index;
if (decoder.Complete(i.pc(), operand)) { if (decoder.Complete(i.pc(), imm)) {
os << ": " << *operand.sig; os << ": " << *imm.sig;
} }
break; break;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand<Decoder::kNoValidate> operand(&i, i.pc()); CallFunctionImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << " // function #" << operand.index; os << " // function #" << imm.index;
if (decoder.Complete(i.pc(), operand)) { if (decoder.Complete(i.pc(), imm)) {
os << ": " << *operand.sig; os << ": " << *imm.sig;
} }
break; break;
} }
......
...@@ -1159,14 +1159,14 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1159,14 +1159,14 @@ class ModuleDecoderImpl : public Decoder {
unsigned len = 0; unsigned len = 0;
switch (opcode) { switch (opcode) {
case kExprGetGlobal: { case kExprGetGlobal: {
GlobalIndexOperand<Decoder::kValidate> operand(this, pc() - 1); GlobalIndexImmediate<Decoder::kValidate> imm(this, pc() - 1);
if (module->globals.size() <= operand.index) { if (module->globals.size() <= imm.index) {
error("global index is out of bounds"); error("global index is out of bounds");
expr.kind = WasmInitExpr::kNone; expr.kind = WasmInitExpr::kNone;
expr.val.i32_const = 0; expr.val.i32_const = 0;
break; break;
} }
WasmGlobal* global = &module->globals[operand.index]; WasmGlobal* global = &module->globals[imm.index];
if (global->mutability || !global->imported) { if (global->mutability || !global->imported) {
error( error(
"only immutable imported globals can be used in initializer " "only immutable imported globals can be used in initializer "
...@@ -1176,36 +1176,36 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1176,36 +1176,36 @@ class ModuleDecoderImpl : public Decoder {
break; break;
} }
expr.kind = WasmInitExpr::kGlobalIndex; expr.kind = WasmInitExpr::kGlobalIndex;
expr.val.global_index = operand.index; expr.val.global_index = imm.index;
len = operand.length; len = imm.length;
break; break;
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand<Decoder::kValidate> operand(this, pc() - 1); ImmI32Immediate<Decoder::kValidate> imm(this, pc() - 1);
expr.kind = WasmInitExpr::kI32Const; expr.kind = WasmInitExpr::kI32Const;
expr.val.i32_const = operand.value; expr.val.i32_const = imm.value;
len = operand.length; len = imm.length;
break; break;
} }
case kExprF32Const: { case kExprF32Const: {
ImmF32Operand<Decoder::kValidate> operand(this, pc() - 1); ImmF32Immediate<Decoder::kValidate> imm(this, pc() - 1);
expr.kind = WasmInitExpr::kF32Const; expr.kind = WasmInitExpr::kF32Const;
expr.val.f32_const = operand.value; expr.val.f32_const = imm.value;
len = operand.length; len = imm.length;
break; break;
} }
case kExprI64Const: { case kExprI64Const: {
ImmI64Operand<Decoder::kValidate> operand(this, pc() - 1); ImmI64Immediate<Decoder::kValidate> imm(this, pc() - 1);
expr.kind = WasmInitExpr::kI64Const; expr.kind = WasmInitExpr::kI64Const;
expr.val.i64_const = operand.value; expr.val.i64_const = imm.value;
len = operand.length; len = imm.length;
break; break;
} }
case kExprF64Const: { case kExprF64Const: {
ImmF64Operand<Decoder::kValidate> operand(this, pc() - 1); ImmF64Immediate<Decoder::kValidate> imm(this, pc() - 1);
expr.kind = WasmInitExpr::kF64Const; expr.kind = WasmInitExpr::kF64Const;
expr.val.f64_const = operand.value; expr.val.f64_const = imm.value;
len = operand.length; len = imm.length;
break; break;
} }
case kExprRefNull: { case kExprRefNull: {
......
...@@ -787,35 +787,33 @@ class SideTable : public ZoneObject { ...@@ -787,35 +787,33 @@ class SideTable : public ZoneObject {
case kExprBlock: case kExprBlock:
case kExprLoop: { case kExprLoop: {
bool is_loop = opcode == kExprLoop; bool is_loop = opcode == kExprLoop;
BlockTypeOperand<Decoder::kNoValidate> operand(&i, i.pc()); BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
if (operand.type == kWasmVar) { if (imm.type == kWasmVar) {
operand.sig = module->signatures[operand.sig_index]; imm.sig = module->signatures[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", is_loop ? "Loop" : "Block", imm.in_arity(), imm.out_arity());
operand.in_arity(), operand.out_arity()); CLabel* label =
CLabel* label = CLabel::New(&control_transfer_zone, stack_height, CLabel::New(&control_transfer_zone, stack_height,
is_loop ? operand.in_arity() is_loop ? imm.in_arity() : imm.out_arity());
: operand.out_arity()); control_stack.emplace_back(i.pc(), label, imm.out_arity());
control_stack.emplace_back(i.pc(), label, operand.out_arity());
copy_unreachable(); copy_unreachable();
if (is_loop) label->Bind(i.pc()); if (is_loop) label->Bind(i.pc());
break; break;
} }
case kExprIf: { case kExprIf: {
BlockTypeOperand<Decoder::kNoValidate> operand(&i, i.pc()); BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
if (operand.type == kWasmVar) { if (imm.type == kWasmVar) {
operand.sig = module->signatures[operand.sig_index]; imm.sig = module->signatures[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(),
operand.in_arity(), operand.out_arity()); imm.in_arity(), imm.out_arity());
CLabel* end_label = CLabel* end_label = CLabel::New(&control_transfer_zone, stack_height,
CLabel::New(&control_transfer_zone, stack_height, imm.out_arity());
operand.out_arity());
CLabel* else_label = CLabel* else_label =
CLabel::New(&control_transfer_zone, stack_height, 0); CLabel::New(&control_transfer_zone, stack_height, 0);
control_stack.emplace_back(i.pc(), end_label, else_label, control_stack.emplace_back(i.pc(), end_label, else_label,
operand.out_arity()); imm.out_arity());
copy_unreachable(); copy_unreachable();
if (!unreachable) else_label->Ref(i.pc(), stack_height); if (!unreachable) else_label->Ref(i.pc(), stack_height);
break; break;
...@@ -851,24 +849,24 @@ class SideTable : public ZoneObject { ...@@ -851,24 +849,24 @@ class SideTable : public ZoneObject {
break; break;
} }
case kExprBr: { case kExprBr: {
BreakDepthOperand<Decoder::kNoValidate> operand(&i, i.pc()); BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), operand.depth); TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), imm.depth);
Control* c = &control_stack[control_stack.size() - operand.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: {
BreakDepthOperand<Decoder::kNoValidate> operand(&i, i.pc()); BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), operand.depth); TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), imm.depth);
Control* c = &control_stack[control_stack.size() - operand.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: {
BranchTableOperand<Decoder::kNoValidate> operand(&i, i.pc()); BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc());
BranchTableIterator<Decoder::kNoValidate> iterator(&i, operand); BranchTableIterator<Decoder::kNoValidate> iterator(&i, imm);
TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(), TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
operand.table_count); imm.table_count);
if (!unreachable) { if (!unreachable) {
while (iterator.has_next()) { while (iterator.has_next()) {
uint32_t j = iterator.cur_index(); uint32_t j = iterator.cur_index();
...@@ -1332,14 +1330,12 @@ class ThreadImpl { ...@@ -1332,14 +1330,12 @@ class ThreadImpl {
pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) { pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) {
switch (code->orig_start[pc]) { switch (code->orig_start[pc]) {
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand<Decoder::kNoValidate> operand(decoder, CallFunctionImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
code->at(pc)); return pc + 1 + imm.length;
return pc + 1 + operand.length;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand<Decoder::kNoValidate> operand(decoder, CallIndirectImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
code->at(pc)); return pc + 1 + imm.length;
return pc + 1 + operand.length;
} }
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -1413,10 +1409,10 @@ class ThreadImpl { ...@@ -1413,10 +1409,10 @@ class ThreadImpl {
template <typename ctype, typename mtype> template <typename ctype, typename mtype>
bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len, bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len,
MachineRepresentation rep) { MachineRepresentation rep) {
MemoryAccessOperand<Decoder::kNoValidate> operand(decoder, code->at(pc), MemoryAccessImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc),
sizeof(ctype)); sizeof(ctype));
uint32_t index = Pop().to<uint32_t>(); uint32_t index = Pop().to<uint32_t>();
Address addr = BoundsCheckMem<mtype>(operand.offset, index); Address addr = BoundsCheckMem<mtype>(imm.offset, index);
if (!addr) { if (!addr) {
DoTrap(kTrapMemOutOfBounds, pc); DoTrap(kTrapMemOutOfBounds, pc);
return false; return false;
...@@ -1425,10 +1421,10 @@ class ThreadImpl { ...@@ -1425,10 +1421,10 @@ class ThreadImpl {
converter<ctype, mtype>{}(ReadLittleEndianValue<mtype>(addr))); converter<ctype, mtype>{}(ReadLittleEndianValue<mtype>(addr)));
Push(result); Push(result);
len = 1 + operand.length; len = 1 + imm.length;
if (FLAG_wasm_trace_memory) { if (FLAG_wasm_trace_memory) {
wasm::MemoryTracingInfo info(operand.offset + index, false, rep); wasm::MemoryTracingInfo info(imm.offset + index, false, rep);
TraceMemoryOperation(ExecutionEngine::kInterpreter, &info, TraceMemoryOperation(ExecutionEngine::kInterpreter, &info,
code->function->func_index, static_cast<int>(pc), code->function->func_index, static_cast<int>(pc),
instance_object_->memory_start()); instance_object_->memory_start());
...@@ -1440,21 +1436,21 @@ class ThreadImpl { ...@@ -1440,21 +1436,21 @@ class ThreadImpl {
template <typename ctype, typename mtype> template <typename ctype, typename mtype>
bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len, bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len,
MachineRepresentation rep) { MachineRepresentation rep) {
MemoryAccessOperand<Decoder::kNoValidate> operand(decoder, code->at(pc), MemoryAccessImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc),
sizeof(ctype)); sizeof(ctype));
ctype val = Pop().to<ctype>(); ctype val = Pop().to<ctype>();
uint32_t index = Pop().to<uint32_t>(); uint32_t index = Pop().to<uint32_t>();
Address addr = BoundsCheckMem<mtype>(operand.offset, index); Address addr = BoundsCheckMem<mtype>(imm.offset, index);
if (!addr) { if (!addr) {
DoTrap(kTrapMemOutOfBounds, pc); DoTrap(kTrapMemOutOfBounds, pc);
return false; return false;
} }
WriteLittleEndianValue<mtype>(addr, converter<mtype, ctype>{}(val)); WriteLittleEndianValue<mtype>(addr, converter<mtype, ctype>{}(val));
len = 1 + operand.length; len = 1 + imm.length;
if (FLAG_wasm_trace_memory) { if (FLAG_wasm_trace_memory) {
wasm::MemoryTracingInfo info(operand.offset + index, true, rep); wasm::MemoryTracingInfo info(imm.offset + index, true, rep);
TraceMemoryOperation(ExecutionEngine::kInterpreter, &info, TraceMemoryOperation(ExecutionEngine::kInterpreter, &info,
code->function->func_index, static_cast<int>(pc), code->function->func_index, static_cast<int>(pc),
instance_object_->memory_start()); instance_object_->memory_start());
...@@ -1467,17 +1463,17 @@ class ThreadImpl { ...@@ -1467,17 +1463,17 @@ class ThreadImpl {
bool ExtractAtomicOpParams(Decoder* decoder, InterpreterCode* code, bool ExtractAtomicOpParams(Decoder* decoder, InterpreterCode* code,
Address& address, pc_t pc, int& len, Address& address, pc_t pc, int& len,
type* val = nullptr, type* val2 = nullptr) { type* val = nullptr, type* val2 = nullptr) {
MemoryAccessOperand<Decoder::kNoValidate> operand(decoder, code->at(pc + 1), MemoryAccessImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + 1),
sizeof(type)); sizeof(type));
if (val2) *val2 = Pop().to<uint32_t>(); if (val2) *val2 = Pop().to<uint32_t>();
if (val) *val = Pop().to<uint32_t>(); if (val) *val = Pop().to<uint32_t>();
uint32_t index = Pop().to<uint32_t>(); uint32_t index = Pop().to<uint32_t>();
address = BoundsCheckMem<type>(operand.offset, index); address = BoundsCheckMem<type>(imm.offset, index);
if (!address) { if (!address) {
DoTrap(kTrapMemOutOfBounds, pc); DoTrap(kTrapMemOutOfBounds, pc);
return false; return false;
} }
len = 2 + operand.length; len = 2 + imm.length;
return true; return true;
} }
...@@ -1727,25 +1723,22 @@ class ThreadImpl { ...@@ -1727,25 +1723,22 @@ class ThreadImpl {
case kExprNop: case kExprNop:
break; break;
case kExprBlock: { case kExprBlock: {
BlockTypeOperand<Decoder::kNoValidate> operand(&decoder, BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
code->at(pc)); len = 1 + imm.length;
len = 1 + operand.length;
break; break;
} }
case kExprLoop: { case kExprLoop: {
BlockTypeOperand<Decoder::kNoValidate> operand(&decoder, BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
code->at(pc)); len = 1 + imm.length;
len = 1 + operand.length;
break; break;
} }
case kExprIf: { case kExprIf: {
BlockTypeOperand<Decoder::kNoValidate> operand(&decoder, BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
code->at(pc));
WasmValue cond = Pop(); WasmValue cond = Pop();
bool is_true = cond.to<uint32_t>() != 0; bool is_true = cond.to<uint32_t>() != 0;
if (is_true) { if (is_true) {
// fall through to the true block. // fall through to the true block.
len = 1 + operand.length; len = 1 + imm.length;
TRACE(" true => fallthrough\n"); TRACE(" true => fallthrough\n");
} else { } else {
len = LookupTargetDelta(code, pc); len = LookupTargetDelta(code, pc);
...@@ -1766,33 +1759,31 @@ class ThreadImpl { ...@@ -1766,33 +1759,31 @@ class ThreadImpl {
break; break;
} }
case kExprBr: { case kExprBr: {
BreakDepthOperand<Decoder::kNoValidate> operand(&decoder, BreakDepthImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
code->at(pc)); len = DoBreak(code, pc, imm.depth);
len = DoBreak(code, pc, operand.depth);
TRACE(" br => @%zu\n", pc + len); TRACE(" br => @%zu\n", pc + len);
break; break;
} }
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand<Decoder::kNoValidate> operand(&decoder, BreakDepthImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
code->at(pc));
WasmValue cond = Pop(); WasmValue cond = Pop();
bool is_true = cond.to<uint32_t>() != 0; bool is_true = cond.to<uint32_t>() != 0;
if (is_true) { if (is_true) {
len = DoBreak(code, pc, operand.depth); len = DoBreak(code, pc, imm.depth);
TRACE(" br_if => @%zu\n", pc + len); TRACE(" br_if => @%zu\n", pc + len);
} else { } else {
TRACE(" false => fallthrough\n"); TRACE(" false => fallthrough\n");
len = 1 + operand.length; len = 1 + imm.length;
} }
break; break;
} }
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand<Decoder::kNoValidate> operand(&decoder, BranchTableImmediate<Decoder::kNoValidate> imm(&decoder,
code->at(pc)); code->at(pc));
BranchTableIterator<Decoder::kNoValidate> iterator(&decoder, operand); BranchTableIterator<Decoder::kNoValidate> iterator(&decoder, imm);
uint32_t key = Pop().to<uint32_t>(); uint32_t key = Pop().to<uint32_t>();
uint32_t depth = 0; uint32_t depth = 0;
if (key >= operand.table_count) key = operand.table_count; if (key >= imm.table_count) key = imm.table_count;
for (uint32_t i = 0; i <= key; i++) { for (uint32_t i = 0; i <= key; i++) {
DCHECK(iterator.has_next()); DCHECK(iterator.has_next());
depth = iterator.next(); depth = iterator.next();
...@@ -1814,51 +1805,48 @@ class ThreadImpl { ...@@ -1814,51 +1805,48 @@ class ThreadImpl {
break; break;
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand<Decoder::kNoValidate> operand(&decoder, code->at(pc)); ImmI32Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
Push(WasmValue(operand.value)); Push(WasmValue(imm.value));
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprI64Const: { case kExprI64Const: {
ImmI64Operand<Decoder::kNoValidate> operand(&decoder, code->at(pc)); ImmI64Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
Push(WasmValue(operand.value)); Push(WasmValue(imm.value));
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprF32Const: { case kExprF32Const: {
ImmF32Operand<Decoder::kNoValidate> operand(&decoder, code->at(pc)); ImmF32Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
Push(WasmValue(operand.value)); Push(WasmValue(imm.value));
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprF64Const: { case kExprF64Const: {
ImmF64Operand<Decoder::kNoValidate> operand(&decoder, code->at(pc)); ImmF64Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
Push(WasmValue(operand.value)); Push(WasmValue(imm.value));
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprGetLocal: { case kExprGetLocal: {
LocalIndexOperand<Decoder::kNoValidate> operand(&decoder, LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
code->at(pc)); Push(GetStackValue(frames_.back().sp + imm.index));
Push(GetStackValue(frames_.back().sp + operand.index)); len = 1 + imm.length;
len = 1 + operand.length;
break; break;
} }
case kExprSetLocal: { case kExprSetLocal: {
LocalIndexOperand<Decoder::kNoValidate> operand(&decoder, LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
code->at(pc));
WasmValue val = Pop(); WasmValue val = Pop();
SetStackValue(frames_.back().sp + operand.index, val); SetStackValue(frames_.back().sp + imm.index, val);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand<Decoder::kNoValidate> operand(&decoder, LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
code->at(pc));
WasmValue val = Pop(); WasmValue val = Pop();
SetStackValue(frames_.back().sp + operand.index, val); SetStackValue(frames_.back().sp + imm.index, val);
Push(val); Push(val);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprDrop: { case kExprDrop: {
...@@ -1866,9 +1854,9 @@ class ThreadImpl { ...@@ -1866,9 +1854,9 @@ class ThreadImpl {
break; break;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand<Decoder::kNoValidate> operand(&decoder, CallFunctionImmediate<Decoder::kNoValidate> imm(&decoder,
code->at(pc)); code->at(pc));
InterpreterCode* target = codemap()->GetCode(operand.index); InterpreterCode* target = codemap()->GetCode(imm.index);
if (target->function->imported) { if (target->function->imported) {
CommitPc(pc); CommitPc(pc);
ExternalCallResult result = ExternalCallResult result =
...@@ -1885,7 +1873,7 @@ class ThreadImpl { ...@@ -1885,7 +1873,7 @@ class ThreadImpl {
UNREACHABLE(); UNREACHABLE();
case ExternalCallResult::EXTERNAL_RETURNED: case ExternalCallResult::EXTERNAL_RETURNED:
PAUSE_IF_BREAK_FLAG(AfterCall); PAUSE_IF_BREAK_FLAG(AfterCall);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
case ExternalCallResult::EXTERNAL_UNWOUND: case ExternalCallResult::EXTERNAL_UNWOUND:
return; return;
...@@ -1899,13 +1887,13 @@ class ThreadImpl { ...@@ -1899,13 +1887,13 @@ class ThreadImpl {
continue; // don't bump pc continue; // don't bump pc
} break; } break;
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand<Decoder::kNoValidate> operand(&decoder, CallIndirectImmediate<Decoder::kNoValidate> imm(&decoder,
code->at(pc)); code->at(pc));
uint32_t entry_index = Pop().to<uint32_t>(); uint32_t entry_index = Pop().to<uint32_t>();
// Assume only one table for now. // Assume only one table for now.
DCHECK_LE(module()->function_tables.size(), 1u); DCHECK_LE(module()->function_tables.size(), 1u);
ExternalCallResult result = ExternalCallResult result =
CallIndirectFunction(0, entry_index, operand.sig_index); CallIndirectFunction(0, entry_index, imm.sig_index);
switch (result.type) { switch (result.type) {
case ExternalCallResult::INTERNAL: case ExternalCallResult::INTERNAL:
// The import is a function of this instance. Call it directly. // The import is a function of this instance. Call it directly.
...@@ -1920,16 +1908,16 @@ class ThreadImpl { ...@@ -1920,16 +1908,16 @@ class ThreadImpl {
return DoTrap(kTrapFuncSigMismatch, pc); return DoTrap(kTrapFuncSigMismatch, pc);
case ExternalCallResult::EXTERNAL_RETURNED: case ExternalCallResult::EXTERNAL_RETURNED:
PAUSE_IF_BREAK_FLAG(AfterCall); PAUSE_IF_BREAK_FLAG(AfterCall);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
case ExternalCallResult::EXTERNAL_UNWOUND: case ExternalCallResult::EXTERNAL_UNWOUND:
return; return;
} }
} break; } break;
case kExprGetGlobal: { case kExprGetGlobal: {
GlobalIndexOperand<Decoder::kNoValidate> operand(&decoder, GlobalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
code->at(pc)); code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index]; const WasmGlobal* global = &module()->globals[imm.index];
byte* ptr = GetGlobalPtr(global); byte* ptr = GetGlobalPtr(global);
WasmValue val; WasmValue val;
switch (global->type) { switch (global->type) {
...@@ -1943,13 +1931,13 @@ class ThreadImpl { ...@@ -1943,13 +1931,13 @@ class ThreadImpl {
UNREACHABLE(); UNREACHABLE();
} }
Push(val); Push(val);
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
case kExprSetGlobal: { case kExprSetGlobal: {
GlobalIndexOperand<Decoder::kNoValidate> operand(&decoder, GlobalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
code->at(pc)); code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index]; const WasmGlobal* global = &module()->globals[imm.index];
byte* ptr = GetGlobalPtr(global); byte* ptr = GetGlobalPtr(global);
WasmValue val = Pop(); WasmValue val = Pop();
switch (global->type) { switch (global->type) {
...@@ -1962,7 +1950,7 @@ class ThreadImpl { ...@@ -1962,7 +1950,7 @@ class ThreadImpl {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
...@@ -2053,25 +2041,25 @@ class ThreadImpl { ...@@ -2053,25 +2041,25 @@ class ThreadImpl {
ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double); ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double);
#undef ASMJS_STORE_CASE #undef ASMJS_STORE_CASE
case kExprGrowMemory: { case kExprGrowMemory: {
MemoryIndexOperand<Decoder::kNoValidate> operand(&decoder, MemoryIndexImmediate<Decoder::kNoValidate> imm(&decoder,
code->at(pc)); code->at(pc));
uint32_t delta_pages = Pop().to<uint32_t>(); uint32_t delta_pages = Pop().to<uint32_t>();
Handle<WasmMemoryObject> memory(instance_object_->memory_object()); Handle<WasmMemoryObject> memory(instance_object_->memory_object());
Isolate* isolate = memory->GetIsolate(); Isolate* isolate = memory->GetIsolate();
int32_t result = WasmMemoryObject::Grow(isolate, memory, delta_pages); int32_t result = WasmMemoryObject::Grow(isolate, memory, delta_pages);
Push(WasmValue(result)); Push(WasmValue(result));
len = 1 + operand.length; len = 1 + imm.length;
// Treat one grow_memory instruction like 1000 other instructions, // Treat one grow_memory instruction like 1000 other instructions,
// because it is a really expensive operation. // because it is a really expensive operation.
if (max > 0) max = std::max(0, max - 1000); if (max > 0) max = std::max(0, max - 1000);
break; break;
} }
case kExprMemorySize: { case kExprMemorySize: {
MemoryIndexOperand<Decoder::kNoValidate> operand(&decoder, MemoryIndexImmediate<Decoder::kNoValidate> imm(&decoder,
code->at(pc)); code->at(pc));
Push(WasmValue(static_cast<uint32_t>(instance_object_->memory_size() / Push(WasmValue(static_cast<uint32_t>(instance_object_->memory_size() /
kWasmPageSize))); kWasmPageSize)));
len = 1 + operand.length; len = 1 + imm.length;
break; break;
} }
// We need to treat kExprI32ReinterpretF32 and kExprI64ReinterpretF64 // We need to treat kExprI32ReinterpretF32 and kExprI64ReinterpretF64
......
...@@ -100,20 +100,20 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes, ...@@ -100,20 +100,20 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
case kExprIf: case kExprIf:
case kExprBlock: case kExprBlock:
case kExprTry: { case kExprTry: {
BlockTypeOperand<Decoder::kNoValidate> operand(&i, i.pc()); BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode); os << WasmOpcodes::OpcodeName(opcode);
if (operand.type == kWasmVar) { if (imm.type == kWasmVar) {
os << " (type " << operand.sig_index << ")"; os << " (type " << imm.sig_index << ")";
} else if (operand.out_arity() > 0) { } else if (imm.out_arity() > 0) {
os << " " << ValueTypes::TypeName(operand.out_type(0)); os << " " << ValueTypes::TypeName(imm.out_type(0));
} }
control_depth++; control_depth++;
break; break;
} }
case kExprBr: case kExprBr:
case kExprBrIf: { case kExprBrIf: {
BreakDepthOperand<Decoder::kNoValidate> operand(&i, i.pc()); BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.depth; os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.depth;
break; break;
} }
case kExprElse: case kExprElse:
...@@ -124,46 +124,46 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes, ...@@ -124,46 +124,46 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
os << "end"; os << "end";
break; break;
case kExprBrTable: { case kExprBrTable: {
BranchTableOperand<Decoder::kNoValidate> operand(&i, i.pc()); BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc());
BranchTableIterator<Decoder::kNoValidate> iterator(&i, operand); BranchTableIterator<Decoder::kNoValidate> iterator(&i, imm);
os << "br_table"; os << "br_table";
while (iterator.has_next()) os << ' ' << iterator.next(); while (iterator.has_next()) os << ' ' << iterator.next();
break; break;
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand<Decoder::kNoValidate> operand(&i, i.pc()); CallIndirectImmediate<Decoder::kNoValidate> imm(&i, i.pc());
DCHECK_EQ(0, operand.table_index); DCHECK_EQ(0, imm.table_index);
os << "call_indirect " << operand.sig_index; os << "call_indirect " << imm.sig_index;
break; break;
} }
case kExprCallFunction: { case kExprCallFunction: {
CallFunctionOperand<Decoder::kNoValidate> operand(&i, i.pc()); CallFunctionImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << "call " << operand.index; os << "call " << imm.index;
break; break;
} }
case kExprGetLocal: case kExprGetLocal:
case kExprSetLocal: case kExprSetLocal:
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand<Decoder::kNoValidate> operand(&i, i.pc()); LocalIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index; os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
break; break;
} }
case kExprThrow: case kExprThrow:
case kExprCatch: { case kExprCatch: {
ExceptionIndexOperand<Decoder::kNoValidate> operand(&i, i.pc()); ExceptionIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index; os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
break; break;
} }
case kExprGetGlobal: case kExprGetGlobal:
case kExprSetGlobal: { case kExprSetGlobal: {
GlobalIndexOperand<Decoder::kNoValidate> operand(&i, i.pc()); GlobalIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index; os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
break; break;
} }
#define CASE_CONST(type, str, cast_type) \ #define CASE_CONST(type, str, cast_type) \
case kExpr##type##Const: { \ case kExpr##type##Const: { \
Imm##type##Operand<Decoder::kNoValidate> operand(&i, i.pc()); \ Imm##type##Immediate<Decoder::kNoValidate> imm(&i, i.pc()); \
os << #str ".const " << static_cast<cast_type>(operand.value); \ os << #str ".const " << static_cast<cast_type>(imm.value); \
break; \ break; \
} }
CASE_CONST(I32, i32, int32_t) CASE_CONST(I32, i32, int32_t)
...@@ -175,10 +175,10 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes, ...@@ -175,10 +175,10 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
#define CASE_OPCODE(opcode, _, __) case kExpr##opcode: #define CASE_OPCODE(opcode, _, __) case kExpr##opcode:
FOREACH_LOAD_MEM_OPCODE(CASE_OPCODE) FOREACH_LOAD_MEM_OPCODE(CASE_OPCODE)
FOREACH_STORE_MEM_OPCODE(CASE_OPCODE) { FOREACH_STORE_MEM_OPCODE(CASE_OPCODE) {
MemoryAccessOperand<Decoder::kNoValidate> operand(&i, i.pc(), MemoryAccessImmediate<Decoder::kNoValidate> imm(&i, i.pc(),
kMaxUInt32); kMaxUInt32);
os << WasmOpcodes::OpcodeName(opcode) << " offset=" << operand.offset os << WasmOpcodes::OpcodeName(opcode) << " offset=" << imm.offset
<< " align=" << (1ULL << operand.alignment); << " align=" << (1ULL << imm.alignment);
break; break;
} }
...@@ -196,11 +196,11 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes, ...@@ -196,11 +196,11 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
WasmOpcode atomic_opcode = i.prefixed_opcode(); WasmOpcode atomic_opcode = i.prefixed_opcode();
switch (atomic_opcode) { switch (atomic_opcode) {
FOREACH_ATOMIC_OPCODE(CASE_OPCODE) { FOREACH_ATOMIC_OPCODE(CASE_OPCODE) {
MemoryAccessOperand<Decoder::kNoValidate> operand(&i, i.pc(), MemoryAccessImmediate<Decoder::kNoValidate> imm(&i, i.pc(),
kMaxUInt32); kMaxUInt32);
os << WasmOpcodes::OpcodeName(atomic_opcode) os << WasmOpcodes::OpcodeName(atomic_opcode)
<< " offset=" << operand.offset << " offset=" << imm.offset
<< " align=" << (1ULL << operand.alignment); << " align=" << (1ULL << imm.alignment);
break; break;
} }
default: default:
......
...@@ -2692,14 +2692,14 @@ class BranchTableIteratorTest : public TestWithZone { ...@@ -2692,14 +2692,14 @@ class BranchTableIteratorTest : public TestWithZone {
BranchTableIteratorTest() : TestWithZone() {} BranchTableIteratorTest() : TestWithZone() {}
void CheckBrTableSize(const byte* start, const byte* end) { void CheckBrTableSize(const byte* start, const byte* end) {
Decoder decoder(start, end); Decoder decoder(start, end);
BranchTableOperand<Decoder::kValidate> operand(&decoder, start); BranchTableImmediate<Decoder::kValidate> operand(&decoder, start);
BranchTableIterator<Decoder::kValidate> iterator(&decoder, operand); BranchTableIterator<Decoder::kValidate> iterator(&decoder, operand);
EXPECT_EQ(end - start - 1u, iterator.length()); EXPECT_EQ(end - start - 1u, iterator.length());
EXPECT_TRUE(decoder.ok()); EXPECT_TRUE(decoder.ok());
} }
void CheckBrTableError(const byte* start, const byte* end) { void CheckBrTableError(const byte* start, const byte* end) {
Decoder decoder(start, end); Decoder decoder(start, end);
BranchTableOperand<Decoder::kValidate> operand(&decoder, start); BranchTableImmediate<Decoder::kValidate> operand(&decoder, start);
BranchTableIterator<Decoder::kValidate> iterator(&decoder, operand); BranchTableIterator<Decoder::kValidate> iterator(&decoder, operand);
iterator.length(); iterator.length();
EXPECT_FALSE(decoder.ok()); EXPECT_FALSE(decoder.ok());
......
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