11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#if !V8_ENABLE_WEBASSEMBLY 61cb0ef41Sopenharmony_ci#error This header should only be included if WebAssembly is enabled. 71cb0ef41Sopenharmony_ci#endif // !V8_ENABLE_WEBASSEMBLY 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#ifndef V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_ 101cb0ef41Sopenharmony_ci#define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_ 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci// Do only include this header for implementing new Interface of the 131cb0ef41Sopenharmony_ci// WasmFullDecoder. 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci#include <inttypes.h> 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci#include "src/base/platform/elapsed-timer.h" 181cb0ef41Sopenharmony_ci#include "src/base/platform/wrappers.h" 191cb0ef41Sopenharmony_ci#include "src/base/small-vector.h" 201cb0ef41Sopenharmony_ci#include "src/base/strings.h" 211cb0ef41Sopenharmony_ci#include "src/utils/bit-vector.h" 221cb0ef41Sopenharmony_ci#include "src/wasm/decoder.h" 231cb0ef41Sopenharmony_ci#include "src/wasm/function-body-decoder.h" 241cb0ef41Sopenharmony_ci#include "src/wasm/value-type.h" 251cb0ef41Sopenharmony_ci#include "src/wasm/wasm-features.h" 261cb0ef41Sopenharmony_ci#include "src/wasm/wasm-limits.h" 271cb0ef41Sopenharmony_ci#include "src/wasm/wasm-module.h" 281cb0ef41Sopenharmony_ci#include "src/wasm/wasm-opcodes.h" 291cb0ef41Sopenharmony_ci#include "src/wasm/wasm-subtyping.h" 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_cinamespace v8 { 321cb0ef41Sopenharmony_cinamespace internal { 331cb0ef41Sopenharmony_cinamespace wasm { 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_cistruct WasmGlobal; 361cb0ef41Sopenharmony_cistruct WasmTag; 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci#define TRACE(...) \ 391cb0ef41Sopenharmony_ci do { \ 401cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 411cb0ef41Sopenharmony_ci } while (false) 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci#define TRACE_INST_FORMAT " @%-8d #%-30s|" 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci// Return the evaluation of `condition` if validate==true, DCHECK that it's 461cb0ef41Sopenharmony_ci// true and always return true otherwise. 471cb0ef41Sopenharmony_ci#define VALIDATE(condition) \ 481cb0ef41Sopenharmony_ci (validate ? V8_LIKELY(condition) : [&] { \ 491cb0ef41Sopenharmony_ci DCHECK(condition); \ 501cb0ef41Sopenharmony_ci return true; \ 511cb0ef41Sopenharmony_ci }()) 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci#define CHECK_PROTOTYPE_OPCODE(feat) \ 541cb0ef41Sopenharmony_ci DCHECK(this->module_->origin == kWasmOrigin); \ 551cb0ef41Sopenharmony_ci if (!VALIDATE(this->enabled_.has_##feat())) { \ 561cb0ef41Sopenharmony_ci this->DecodeError( \ 571cb0ef41Sopenharmony_ci "Invalid opcode 0x%02x (enable with --experimental-wasm-" #feat ")", \ 581cb0ef41Sopenharmony_ci opcode); \ 591cb0ef41Sopenharmony_ci return 0; \ 601cb0ef41Sopenharmony_ci } \ 611cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_##feat); 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci#define ATOMIC_OP_LIST(V) \ 641cb0ef41Sopenharmony_ci V(AtomicNotify, Uint32) \ 651cb0ef41Sopenharmony_ci V(I32AtomicWait, Uint32) \ 661cb0ef41Sopenharmony_ci V(I64AtomicWait, Uint64) \ 671cb0ef41Sopenharmony_ci V(I32AtomicLoad, Uint32) \ 681cb0ef41Sopenharmony_ci V(I64AtomicLoad, Uint64) \ 691cb0ef41Sopenharmony_ci V(I32AtomicLoad8U, Uint8) \ 701cb0ef41Sopenharmony_ci V(I32AtomicLoad16U, Uint16) \ 711cb0ef41Sopenharmony_ci V(I64AtomicLoad8U, Uint8) \ 721cb0ef41Sopenharmony_ci V(I64AtomicLoad16U, Uint16) \ 731cb0ef41Sopenharmony_ci V(I64AtomicLoad32U, Uint32) \ 741cb0ef41Sopenharmony_ci V(I32AtomicAdd, Uint32) \ 751cb0ef41Sopenharmony_ci V(I32AtomicAdd8U, Uint8) \ 761cb0ef41Sopenharmony_ci V(I32AtomicAdd16U, Uint16) \ 771cb0ef41Sopenharmony_ci V(I64AtomicAdd, Uint64) \ 781cb0ef41Sopenharmony_ci V(I64AtomicAdd8U, Uint8) \ 791cb0ef41Sopenharmony_ci V(I64AtomicAdd16U, Uint16) \ 801cb0ef41Sopenharmony_ci V(I64AtomicAdd32U, Uint32) \ 811cb0ef41Sopenharmony_ci V(I32AtomicSub, Uint32) \ 821cb0ef41Sopenharmony_ci V(I64AtomicSub, Uint64) \ 831cb0ef41Sopenharmony_ci V(I32AtomicSub8U, Uint8) \ 841cb0ef41Sopenharmony_ci V(I32AtomicSub16U, Uint16) \ 851cb0ef41Sopenharmony_ci V(I64AtomicSub8U, Uint8) \ 861cb0ef41Sopenharmony_ci V(I64AtomicSub16U, Uint16) \ 871cb0ef41Sopenharmony_ci V(I64AtomicSub32U, Uint32) \ 881cb0ef41Sopenharmony_ci V(I32AtomicAnd, Uint32) \ 891cb0ef41Sopenharmony_ci V(I64AtomicAnd, Uint64) \ 901cb0ef41Sopenharmony_ci V(I32AtomicAnd8U, Uint8) \ 911cb0ef41Sopenharmony_ci V(I32AtomicAnd16U, Uint16) \ 921cb0ef41Sopenharmony_ci V(I64AtomicAnd8U, Uint8) \ 931cb0ef41Sopenharmony_ci V(I64AtomicAnd16U, Uint16) \ 941cb0ef41Sopenharmony_ci V(I64AtomicAnd32U, Uint32) \ 951cb0ef41Sopenharmony_ci V(I32AtomicOr, Uint32) \ 961cb0ef41Sopenharmony_ci V(I64AtomicOr, Uint64) \ 971cb0ef41Sopenharmony_ci V(I32AtomicOr8U, Uint8) \ 981cb0ef41Sopenharmony_ci V(I32AtomicOr16U, Uint16) \ 991cb0ef41Sopenharmony_ci V(I64AtomicOr8U, Uint8) \ 1001cb0ef41Sopenharmony_ci V(I64AtomicOr16U, Uint16) \ 1011cb0ef41Sopenharmony_ci V(I64AtomicOr32U, Uint32) \ 1021cb0ef41Sopenharmony_ci V(I32AtomicXor, Uint32) \ 1031cb0ef41Sopenharmony_ci V(I64AtomicXor, Uint64) \ 1041cb0ef41Sopenharmony_ci V(I32AtomicXor8U, Uint8) \ 1051cb0ef41Sopenharmony_ci V(I32AtomicXor16U, Uint16) \ 1061cb0ef41Sopenharmony_ci V(I64AtomicXor8U, Uint8) \ 1071cb0ef41Sopenharmony_ci V(I64AtomicXor16U, Uint16) \ 1081cb0ef41Sopenharmony_ci V(I64AtomicXor32U, Uint32) \ 1091cb0ef41Sopenharmony_ci V(I32AtomicExchange, Uint32) \ 1101cb0ef41Sopenharmony_ci V(I64AtomicExchange, Uint64) \ 1111cb0ef41Sopenharmony_ci V(I32AtomicExchange8U, Uint8) \ 1121cb0ef41Sopenharmony_ci V(I32AtomicExchange16U, Uint16) \ 1131cb0ef41Sopenharmony_ci V(I64AtomicExchange8U, Uint8) \ 1141cb0ef41Sopenharmony_ci V(I64AtomicExchange16U, Uint16) \ 1151cb0ef41Sopenharmony_ci V(I64AtomicExchange32U, Uint32) \ 1161cb0ef41Sopenharmony_ci V(I32AtomicCompareExchange, Uint32) \ 1171cb0ef41Sopenharmony_ci V(I64AtomicCompareExchange, Uint64) \ 1181cb0ef41Sopenharmony_ci V(I32AtomicCompareExchange8U, Uint8) \ 1191cb0ef41Sopenharmony_ci V(I32AtomicCompareExchange16U, Uint16) \ 1201cb0ef41Sopenharmony_ci V(I64AtomicCompareExchange8U, Uint8) \ 1211cb0ef41Sopenharmony_ci V(I64AtomicCompareExchange16U, Uint16) \ 1221cb0ef41Sopenharmony_ci V(I64AtomicCompareExchange32U, Uint32) 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci#define ATOMIC_STORE_OP_LIST(V) \ 1251cb0ef41Sopenharmony_ci V(I32AtomicStore, Uint32) \ 1261cb0ef41Sopenharmony_ci V(I64AtomicStore, Uint64) \ 1271cb0ef41Sopenharmony_ci V(I32AtomicStore8U, Uint8) \ 1281cb0ef41Sopenharmony_ci V(I32AtomicStore16U, Uint16) \ 1291cb0ef41Sopenharmony_ci V(I64AtomicStore8U, Uint8) \ 1301cb0ef41Sopenharmony_ci V(I64AtomicStore16U, Uint16) \ 1311cb0ef41Sopenharmony_ci V(I64AtomicStore32U, Uint32) 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci// Decoder error with explicit PC and format arguments. 1341cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate, typename... Args> 1351cb0ef41Sopenharmony_civoid DecodeError(Decoder* decoder, const byte* pc, const char* str, 1361cb0ef41Sopenharmony_ci Args&&... args) { 1371cb0ef41Sopenharmony_ci CHECK(validate == Decoder::kFullValidation || 1381cb0ef41Sopenharmony_ci validate == Decoder::kBooleanValidation); 1391cb0ef41Sopenharmony_ci STATIC_ASSERT(sizeof...(Args) > 0); 1401cb0ef41Sopenharmony_ci if (validate == Decoder::kBooleanValidation) { 1411cb0ef41Sopenharmony_ci decoder->MarkError(); 1421cb0ef41Sopenharmony_ci } else { 1431cb0ef41Sopenharmony_ci decoder->errorf(pc, str, std::forward<Args>(args)...); 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci} 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci// Decoder error with explicit PC and no format arguments. 1481cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 1491cb0ef41Sopenharmony_civoid DecodeError(Decoder* decoder, const byte* pc, const char* str) { 1501cb0ef41Sopenharmony_ci CHECK(validate == Decoder::kFullValidation || 1511cb0ef41Sopenharmony_ci validate == Decoder::kBooleanValidation); 1521cb0ef41Sopenharmony_ci if (validate == Decoder::kBooleanValidation) { 1531cb0ef41Sopenharmony_ci decoder->MarkError(); 1541cb0ef41Sopenharmony_ci } else { 1551cb0ef41Sopenharmony_ci decoder->error(pc, str); 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci// Decoder error without explicit PC, but with format arguments. 1601cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate, typename... Args> 1611cb0ef41Sopenharmony_civoid DecodeError(Decoder* decoder, const char* str, Args&&... args) { 1621cb0ef41Sopenharmony_ci CHECK(validate == Decoder::kFullValidation || 1631cb0ef41Sopenharmony_ci validate == Decoder::kBooleanValidation); 1641cb0ef41Sopenharmony_ci STATIC_ASSERT(sizeof...(Args) > 0); 1651cb0ef41Sopenharmony_ci if (validate == Decoder::kBooleanValidation) { 1661cb0ef41Sopenharmony_ci decoder->MarkError(); 1671cb0ef41Sopenharmony_ci } else { 1681cb0ef41Sopenharmony_ci decoder->errorf(str, std::forward<Args>(args)...); 1691cb0ef41Sopenharmony_ci } 1701cb0ef41Sopenharmony_ci} 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci// Decoder error without explicit PC and without format arguments. 1731cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 1741cb0ef41Sopenharmony_civoid DecodeError(Decoder* decoder, const char* str) { 1751cb0ef41Sopenharmony_ci CHECK(validate == Decoder::kFullValidation || 1761cb0ef41Sopenharmony_ci validate == Decoder::kBooleanValidation); 1771cb0ef41Sopenharmony_ci if (validate == Decoder::kBooleanValidation) { 1781cb0ef41Sopenharmony_ci decoder->MarkError(); 1791cb0ef41Sopenharmony_ci } else { 1801cb0ef41Sopenharmony_ci decoder->error(str); 1811cb0ef41Sopenharmony_ci } 1821cb0ef41Sopenharmony_ci} 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_cinamespace value_type_reader { 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci// If {module} is not null, the read index will be checked against the module's 1871cb0ef41Sopenharmony_ci// type capacity. 1881cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 1891cb0ef41Sopenharmony_ciHeapType read_heap_type(Decoder* decoder, const byte* pc, 1901cb0ef41Sopenharmony_ci uint32_t* const length, const WasmModule* module, 1911cb0ef41Sopenharmony_ci const WasmFeatures& enabled) { 1921cb0ef41Sopenharmony_ci int64_t heap_index = decoder->read_i33v<validate>(pc, length, "heap type"); 1931cb0ef41Sopenharmony_ci if (heap_index < 0) { 1941cb0ef41Sopenharmony_ci int64_t min_1_byte_leb128 = -64; 1951cb0ef41Sopenharmony_ci if (!VALIDATE(heap_index >= min_1_byte_leb128)) { 1961cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, "Unknown heap type %" PRId64, 1971cb0ef41Sopenharmony_ci heap_index); 1981cb0ef41Sopenharmony_ci return HeapType(HeapType::kBottom); 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci uint8_t uint_7_mask = 0x7F; 2011cb0ef41Sopenharmony_ci uint8_t code = static_cast<ValueTypeCode>(heap_index) & uint_7_mask; 2021cb0ef41Sopenharmony_ci switch (code) { 2031cb0ef41Sopenharmony_ci case kEqRefCode: 2041cb0ef41Sopenharmony_ci case kI31RefCode: 2051cb0ef41Sopenharmony_ci case kDataRefCode: 2061cb0ef41Sopenharmony_ci case kArrayRefCode: 2071cb0ef41Sopenharmony_ci case kAnyRefCodeAlias: 2081cb0ef41Sopenharmony_ci if (!VALIDATE(enabled.has_gc())) { 2091cb0ef41Sopenharmony_ci DecodeError<validate>( 2101cb0ef41Sopenharmony_ci decoder, pc, 2111cb0ef41Sopenharmony_ci "invalid heap type '%s', enable with --experimental-wasm-gc", 2121cb0ef41Sopenharmony_ci HeapType::from_code(code).name().c_str()); 2131cb0ef41Sopenharmony_ci return HeapType(HeapType::kBottom); 2141cb0ef41Sopenharmony_ci } 2151cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 2161cb0ef41Sopenharmony_ci case kAnyRefCode: 2171cb0ef41Sopenharmony_ci case kFuncRefCode: 2181cb0ef41Sopenharmony_ci return HeapType::from_code(code); 2191cb0ef41Sopenharmony_ci default: 2201cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, "Unknown heap type %" PRId64, 2211cb0ef41Sopenharmony_ci heap_index); 2221cb0ef41Sopenharmony_ci return HeapType(HeapType::kBottom); 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci } else { 2251cb0ef41Sopenharmony_ci if (!VALIDATE(enabled.has_typed_funcref())) { 2261cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, 2271cb0ef41Sopenharmony_ci "Invalid indexed heap type, enable with " 2281cb0ef41Sopenharmony_ci "--experimental-wasm-typed-funcref"); 2291cb0ef41Sopenharmony_ci return HeapType(HeapType::kBottom); 2301cb0ef41Sopenharmony_ci } 2311cb0ef41Sopenharmony_ci uint32_t type_index = static_cast<uint32_t>(heap_index); 2321cb0ef41Sopenharmony_ci if (!VALIDATE(type_index < kV8MaxWasmTypes)) { 2331cb0ef41Sopenharmony_ci DecodeError<validate>( 2341cb0ef41Sopenharmony_ci decoder, pc, 2351cb0ef41Sopenharmony_ci "Type index %u is greater than the maximum number %zu " 2361cb0ef41Sopenharmony_ci "of type definitions supported by V8", 2371cb0ef41Sopenharmony_ci type_index, kV8MaxWasmTypes); 2381cb0ef41Sopenharmony_ci return HeapType(HeapType::kBottom); 2391cb0ef41Sopenharmony_ci } 2401cb0ef41Sopenharmony_ci // We use capacity over size so this works mid-DecodeTypeSection. 2411cb0ef41Sopenharmony_ci if (!VALIDATE(module == nullptr || type_index < module->types.capacity())) { 2421cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, "Type index %u is out of bounds", 2431cb0ef41Sopenharmony_ci type_index); 2441cb0ef41Sopenharmony_ci return HeapType(HeapType::kBottom); 2451cb0ef41Sopenharmony_ci } 2461cb0ef41Sopenharmony_ci return HeapType(type_index); 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci} 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ciHeapType consume_heap_type(Decoder* decoder, const WasmModule* module, 2511cb0ef41Sopenharmony_ci const WasmFeatures& enabled); 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci// Read a value type starting at address {pc} using {decoder}. 2541cb0ef41Sopenharmony_ci// No bytes are consumed. 2551cb0ef41Sopenharmony_ci// The length of the read value type is written in {length}. 2561cb0ef41Sopenharmony_ci// Registers an error for an invalid type only if {validate} is not 2571cb0ef41Sopenharmony_ci// kNoValidate. 2581cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 2591cb0ef41Sopenharmony_ciValueType read_value_type(Decoder* decoder, const byte* pc, 2601cb0ef41Sopenharmony_ci uint32_t* const length, const WasmModule* module, 2611cb0ef41Sopenharmony_ci const WasmFeatures& enabled) { 2621cb0ef41Sopenharmony_ci *length = 1; 2631cb0ef41Sopenharmony_ci byte val = decoder->read_u8<validate>(pc, "value type opcode"); 2641cb0ef41Sopenharmony_ci if (decoder->failed()) { 2651cb0ef41Sopenharmony_ci *length = 0; 2661cb0ef41Sopenharmony_ci return kWasmBottom; 2671cb0ef41Sopenharmony_ci } 2681cb0ef41Sopenharmony_ci ValueTypeCode code = static_cast<ValueTypeCode>(val); 2691cb0ef41Sopenharmony_ci switch (code) { 2701cb0ef41Sopenharmony_ci case kEqRefCode: 2711cb0ef41Sopenharmony_ci case kI31RefCode: 2721cb0ef41Sopenharmony_ci case kDataRefCode: 2731cb0ef41Sopenharmony_ci case kArrayRefCode: 2741cb0ef41Sopenharmony_ci case kAnyRefCodeAlias: 2751cb0ef41Sopenharmony_ci if (!VALIDATE(enabled.has_gc())) { 2761cb0ef41Sopenharmony_ci DecodeError<validate>( 2771cb0ef41Sopenharmony_ci decoder, pc, 2781cb0ef41Sopenharmony_ci "invalid value type '%sref', enable with --experimental-wasm-gc", 2791cb0ef41Sopenharmony_ci HeapType::from_code(code).name().c_str()); 2801cb0ef41Sopenharmony_ci return kWasmBottom; 2811cb0ef41Sopenharmony_ci } 2821cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 2831cb0ef41Sopenharmony_ci case kAnyRefCode: 2841cb0ef41Sopenharmony_ci case kFuncRefCode: { 2851cb0ef41Sopenharmony_ci HeapType heap_type = HeapType::from_code(code); 2861cb0ef41Sopenharmony_ci Nullability nullability = 2871cb0ef41Sopenharmony_ci code == kI31RefCode || code == kDataRefCode || code == kArrayRefCode 2881cb0ef41Sopenharmony_ci ? kNonNullable 2891cb0ef41Sopenharmony_ci : kNullable; 2901cb0ef41Sopenharmony_ci return ValueType::Ref(heap_type, nullability); 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci case kI32Code: 2931cb0ef41Sopenharmony_ci return kWasmI32; 2941cb0ef41Sopenharmony_ci case kI64Code: 2951cb0ef41Sopenharmony_ci return kWasmI64; 2961cb0ef41Sopenharmony_ci case kF32Code: 2971cb0ef41Sopenharmony_ci return kWasmF32; 2981cb0ef41Sopenharmony_ci case kF64Code: 2991cb0ef41Sopenharmony_ci return kWasmF64; 3001cb0ef41Sopenharmony_ci case kRefCode: 3011cb0ef41Sopenharmony_ci case kOptRefCode: { 3021cb0ef41Sopenharmony_ci Nullability nullability = code == kOptRefCode ? kNullable : kNonNullable; 3031cb0ef41Sopenharmony_ci if (!VALIDATE(enabled.has_typed_funcref())) { 3041cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, 3051cb0ef41Sopenharmony_ci "Invalid type '(ref%s <heaptype>)', enable with " 3061cb0ef41Sopenharmony_ci "--experimental-wasm-typed-funcref", 3071cb0ef41Sopenharmony_ci nullability == kNullable ? " null" : ""); 3081cb0ef41Sopenharmony_ci return kWasmBottom; 3091cb0ef41Sopenharmony_ci } 3101cb0ef41Sopenharmony_ci HeapType heap_type = 3111cb0ef41Sopenharmony_ci read_heap_type<validate>(decoder, pc + 1, length, module, enabled); 3121cb0ef41Sopenharmony_ci *length += 1; 3131cb0ef41Sopenharmony_ci return heap_type.is_bottom() ? kWasmBottom 3141cb0ef41Sopenharmony_ci : ValueType::Ref(heap_type, nullability); 3151cb0ef41Sopenharmony_ci } 3161cb0ef41Sopenharmony_ci // TODO(7748): This is here only for backwards compatibility, and the parsed 3171cb0ef41Sopenharmony_ci // depth is ignored. 3181cb0ef41Sopenharmony_ci case kRttWithDepthCode: 3191cb0ef41Sopenharmony_ci case kRttCode: { 3201cb0ef41Sopenharmony_ci if (!VALIDATE(enabled.has_gc())) { 3211cb0ef41Sopenharmony_ci DecodeError<validate>( 3221cb0ef41Sopenharmony_ci decoder, pc, 3231cb0ef41Sopenharmony_ci "invalid value type 'rtt', enable with --experimental-wasm-gc"); 3241cb0ef41Sopenharmony_ci return kWasmBottom; 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci if (code == kRttWithDepthCode) { 3271cb0ef41Sopenharmony_ci uint32_t depth = decoder->read_u32v<validate>(pc + 1, length, "depth"); 3281cb0ef41Sopenharmony_ci *length += 1; 3291cb0ef41Sopenharmony_ci if (!VALIDATE(depth <= kV8MaxRttSubtypingDepth)) { 3301cb0ef41Sopenharmony_ci DecodeError<validate>( 3311cb0ef41Sopenharmony_ci decoder, pc, 3321cb0ef41Sopenharmony_ci "subtyping depth %u is greater than the maximum depth " 3331cb0ef41Sopenharmony_ci "%u supported by V8", 3341cb0ef41Sopenharmony_ci depth, kV8MaxRttSubtypingDepth); 3351cb0ef41Sopenharmony_ci return kWasmBottom; 3361cb0ef41Sopenharmony_ci } 3371cb0ef41Sopenharmony_ci } 3381cb0ef41Sopenharmony_ci uint32_t type_index_length; 3391cb0ef41Sopenharmony_ci uint32_t type_index = 3401cb0ef41Sopenharmony_ci decoder->read_u32v<validate>(pc + *length, &type_index_length); 3411cb0ef41Sopenharmony_ci *length += type_index_length; 3421cb0ef41Sopenharmony_ci if (!VALIDATE(type_index < kV8MaxWasmTypes)) { 3431cb0ef41Sopenharmony_ci DecodeError<validate>( 3441cb0ef41Sopenharmony_ci decoder, pc, 3451cb0ef41Sopenharmony_ci "Type index %u is greater than the maximum number %zu " 3461cb0ef41Sopenharmony_ci "of type definitions supported by V8", 3471cb0ef41Sopenharmony_ci type_index, kV8MaxWasmTypes); 3481cb0ef41Sopenharmony_ci return kWasmBottom; 3491cb0ef41Sopenharmony_ci } 3501cb0ef41Sopenharmony_ci // We use capacity over size so this works mid-DecodeTypeSection. 3511cb0ef41Sopenharmony_ci if (!VALIDATE(module == nullptr || 3521cb0ef41Sopenharmony_ci type_index < module->types.capacity())) { 3531cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, "Type index %u is out of bounds", 3541cb0ef41Sopenharmony_ci type_index); 3551cb0ef41Sopenharmony_ci return kWasmBottom; 3561cb0ef41Sopenharmony_ci } 3571cb0ef41Sopenharmony_ci return ValueType::Rtt(type_index); 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci case kS128Code: { 3601cb0ef41Sopenharmony_ci if (!VALIDATE(enabled.has_simd())) { 3611cb0ef41Sopenharmony_ci DecodeError<validate>( 3621cb0ef41Sopenharmony_ci decoder, pc, 3631cb0ef41Sopenharmony_ci "invalid value type 's128', enable with --experimental-wasm-simd"); 3641cb0ef41Sopenharmony_ci return kWasmBottom; 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci if (!VALIDATE(CheckHardwareSupportsSimd())) { 3671cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, "Wasm SIMD unsupported"); 3681cb0ef41Sopenharmony_ci return kWasmBottom; 3691cb0ef41Sopenharmony_ci } 3701cb0ef41Sopenharmony_ci return kWasmS128; 3711cb0ef41Sopenharmony_ci } 3721cb0ef41Sopenharmony_ci // Although these codes are included in ValueTypeCode, they technically 3731cb0ef41Sopenharmony_ci // do not correspond to value types and are only used in specific 3741cb0ef41Sopenharmony_ci // contexts. The caller of this function is responsible for handling them. 3751cb0ef41Sopenharmony_ci case kVoidCode: 3761cb0ef41Sopenharmony_ci case kI8Code: 3771cb0ef41Sopenharmony_ci case kI16Code: 3781cb0ef41Sopenharmony_ci if (validate) { 3791cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, "invalid value type 0x%x", code); 3801cb0ef41Sopenharmony_ci } 3811cb0ef41Sopenharmony_ci return kWasmBottom; 3821cb0ef41Sopenharmony_ci } 3831cb0ef41Sopenharmony_ci // Anything that doesn't match an enumeration value is an invalid type code. 3841cb0ef41Sopenharmony_ci if (validate) { 3851cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, "invalid value type 0x%x", code); 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci return kWasmBottom; 3881cb0ef41Sopenharmony_ci} 3891cb0ef41Sopenharmony_ci} // namespace value_type_reader 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_cienum DecodingMode { kFunctionBody, kInitExpression }; 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci// Helpers for decoding different kinds of immediates which follow bytecodes. 3941cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 3951cb0ef41Sopenharmony_cistruct ImmI32Immediate { 3961cb0ef41Sopenharmony_ci int32_t value; 3971cb0ef41Sopenharmony_ci uint32_t length; 3981cb0ef41Sopenharmony_ci ImmI32Immediate(Decoder* decoder, const byte* pc) { 3991cb0ef41Sopenharmony_ci value = decoder->read_i32v<validate>(pc, &length, "immi32"); 4001cb0ef41Sopenharmony_ci } 4011cb0ef41Sopenharmony_ci}; 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4041cb0ef41Sopenharmony_cistruct ImmI64Immediate { 4051cb0ef41Sopenharmony_ci int64_t value; 4061cb0ef41Sopenharmony_ci uint32_t length; 4071cb0ef41Sopenharmony_ci ImmI64Immediate(Decoder* decoder, const byte* pc) { 4081cb0ef41Sopenharmony_ci value = decoder->read_i64v<validate>(pc, &length, "immi64"); 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci}; 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4131cb0ef41Sopenharmony_cistruct ImmF32Immediate { 4141cb0ef41Sopenharmony_ci float value; 4151cb0ef41Sopenharmony_ci uint32_t length = 4; 4161cb0ef41Sopenharmony_ci ImmF32Immediate(Decoder* decoder, const byte* pc) { 4171cb0ef41Sopenharmony_ci // We can't use bit_cast here because calling any helper function that 4181cb0ef41Sopenharmony_ci // returns a float would potentially flip NaN bits per C++ semantics, so we 4191cb0ef41Sopenharmony_ci // have to inline the memcpy call directly. 4201cb0ef41Sopenharmony_ci uint32_t tmp = decoder->read_u32<validate>(pc, "immf32"); 4211cb0ef41Sopenharmony_ci memcpy(&value, &tmp, sizeof(value)); 4221cb0ef41Sopenharmony_ci } 4231cb0ef41Sopenharmony_ci}; 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4261cb0ef41Sopenharmony_cistruct ImmF64Immediate { 4271cb0ef41Sopenharmony_ci double value; 4281cb0ef41Sopenharmony_ci uint32_t length = 8; 4291cb0ef41Sopenharmony_ci ImmF64Immediate(Decoder* decoder, const byte* pc) { 4301cb0ef41Sopenharmony_ci // Avoid bit_cast because it might not preserve the signalling bit of a NaN. 4311cb0ef41Sopenharmony_ci uint64_t tmp = decoder->read_u64<validate>(pc, "immf64"); 4321cb0ef41Sopenharmony_ci memcpy(&value, &tmp, sizeof(value)); 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci}; 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_ci// This is different than IndexImmediate because {index} is a byte. 4371cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4381cb0ef41Sopenharmony_cistruct MemoryIndexImmediate { 4391cb0ef41Sopenharmony_ci uint8_t index = 0; 4401cb0ef41Sopenharmony_ci uint32_t length = 1; 4411cb0ef41Sopenharmony_ci MemoryIndexImmediate(Decoder* decoder, const byte* pc) { 4421cb0ef41Sopenharmony_ci index = decoder->read_u8<validate>(pc, "memory index"); 4431cb0ef41Sopenharmony_ci } 4441cb0ef41Sopenharmony_ci}; 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_ci// Parent class for all Immediates which read a u32v index value in their 4471cb0ef41Sopenharmony_ci// constructor. 4481cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4491cb0ef41Sopenharmony_cistruct IndexImmediate { 4501cb0ef41Sopenharmony_ci uint32_t index; 4511cb0ef41Sopenharmony_ci uint32_t length; 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci IndexImmediate(Decoder* decoder, const byte* pc, const char* name) { 4541cb0ef41Sopenharmony_ci index = decoder->read_u32v<validate>(pc, &length, name); 4551cb0ef41Sopenharmony_ci } 4561cb0ef41Sopenharmony_ci}; 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4591cb0ef41Sopenharmony_cistruct TagIndexImmediate : public IndexImmediate<validate> { 4601cb0ef41Sopenharmony_ci const WasmTag* tag = nullptr; 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci TagIndexImmediate(Decoder* decoder, const byte* pc) 4631cb0ef41Sopenharmony_ci : IndexImmediate<validate>(decoder, pc, "tag index") {} 4641cb0ef41Sopenharmony_ci}; 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4671cb0ef41Sopenharmony_cistruct GlobalIndexImmediate : public IndexImmediate<validate> { 4681cb0ef41Sopenharmony_ci const WasmGlobal* global = nullptr; 4691cb0ef41Sopenharmony_ci 4701cb0ef41Sopenharmony_ci GlobalIndexImmediate(Decoder* decoder, const byte* pc) 4711cb0ef41Sopenharmony_ci : IndexImmediate<validate>(decoder, pc, "global index") {} 4721cb0ef41Sopenharmony_ci}; 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4751cb0ef41Sopenharmony_cistruct StructIndexImmediate : public IndexImmediate<validate> { 4761cb0ef41Sopenharmony_ci const StructType* struct_type = nullptr; 4771cb0ef41Sopenharmony_ci 4781cb0ef41Sopenharmony_ci StructIndexImmediate(Decoder* decoder, const byte* pc) 4791cb0ef41Sopenharmony_ci : IndexImmediate<validate>(decoder, pc, "struct index") {} 4801cb0ef41Sopenharmony_ci}; 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4831cb0ef41Sopenharmony_cistruct ArrayIndexImmediate : public IndexImmediate<validate> { 4841cb0ef41Sopenharmony_ci const ArrayType* array_type = nullptr; 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci ArrayIndexImmediate(Decoder* decoder, const byte* pc) 4871cb0ef41Sopenharmony_ci : IndexImmediate<validate>(decoder, pc, "array index") {} 4881cb0ef41Sopenharmony_ci}; 4891cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4901cb0ef41Sopenharmony_cistruct CallFunctionImmediate : public IndexImmediate<validate> { 4911cb0ef41Sopenharmony_ci const FunctionSig* sig = nullptr; 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_ci CallFunctionImmediate(Decoder* decoder, const byte* pc) 4941cb0ef41Sopenharmony_ci : IndexImmediate<validate>(decoder, pc, "function index") {} 4951cb0ef41Sopenharmony_ci}; 4961cb0ef41Sopenharmony_ci 4971cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 4981cb0ef41Sopenharmony_cistruct SelectTypeImmediate { 4991cb0ef41Sopenharmony_ci uint32_t length; 5001cb0ef41Sopenharmony_ci ValueType type; 5011cb0ef41Sopenharmony_ci 5021cb0ef41Sopenharmony_ci SelectTypeImmediate(const WasmFeatures& enabled, Decoder* decoder, 5031cb0ef41Sopenharmony_ci const byte* pc, const WasmModule* module) { 5041cb0ef41Sopenharmony_ci uint8_t num_types = 5051cb0ef41Sopenharmony_ci decoder->read_u32v<validate>(pc, &length, "number of select types"); 5061cb0ef41Sopenharmony_ci if (!VALIDATE(num_types == 1)) { 5071cb0ef41Sopenharmony_ci DecodeError<validate>( 5081cb0ef41Sopenharmony_ci decoder, pc + 1, 5091cb0ef41Sopenharmony_ci "Invalid number of types. Select accepts exactly one type"); 5101cb0ef41Sopenharmony_ci return; 5111cb0ef41Sopenharmony_ci } 5121cb0ef41Sopenharmony_ci uint32_t type_length; 5131cb0ef41Sopenharmony_ci type = value_type_reader::read_value_type<validate>( 5141cb0ef41Sopenharmony_ci decoder, pc + length, &type_length, module, enabled); 5151cb0ef41Sopenharmony_ci length += type_length; 5161cb0ef41Sopenharmony_ci } 5171cb0ef41Sopenharmony_ci}; 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 5201cb0ef41Sopenharmony_cistruct BlockTypeImmediate { 5211cb0ef41Sopenharmony_ci uint32_t length = 1; 5221cb0ef41Sopenharmony_ci ValueType type = kWasmVoid; 5231cb0ef41Sopenharmony_ci uint32_t sig_index = 0; 5241cb0ef41Sopenharmony_ci const FunctionSig* sig = nullptr; 5251cb0ef41Sopenharmony_ci 5261cb0ef41Sopenharmony_ci BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder, 5271cb0ef41Sopenharmony_ci const byte* pc, const WasmModule* module) { 5281cb0ef41Sopenharmony_ci int64_t block_type = 5291cb0ef41Sopenharmony_ci decoder->read_i33v<validate>(pc, &length, "block type"); 5301cb0ef41Sopenharmony_ci if (block_type < 0) { 5311cb0ef41Sopenharmony_ci // All valid negative types are 1 byte in length, so we check against the 5321cb0ef41Sopenharmony_ci // minimum 1-byte LEB128 value. 5331cb0ef41Sopenharmony_ci constexpr int64_t min_1_byte_leb128 = -64; 5341cb0ef41Sopenharmony_ci if (!VALIDATE(block_type >= min_1_byte_leb128)) { 5351cb0ef41Sopenharmony_ci DecodeError<validate>(decoder, pc, "invalid block type %" PRId64, 5361cb0ef41Sopenharmony_ci block_type); 5371cb0ef41Sopenharmony_ci return; 5381cb0ef41Sopenharmony_ci } 5391cb0ef41Sopenharmony_ci if (static_cast<ValueTypeCode>(block_type & 0x7F) == kVoidCode) return; 5401cb0ef41Sopenharmony_ci type = value_type_reader::read_value_type<validate>(decoder, pc, &length, 5411cb0ef41Sopenharmony_ci module, enabled); 5421cb0ef41Sopenharmony_ci } else { 5431cb0ef41Sopenharmony_ci type = kWasmBottom; 5441cb0ef41Sopenharmony_ci sig_index = static_cast<uint32_t>(block_type); 5451cb0ef41Sopenharmony_ci } 5461cb0ef41Sopenharmony_ci } 5471cb0ef41Sopenharmony_ci 5481cb0ef41Sopenharmony_ci uint32_t in_arity() const { 5491cb0ef41Sopenharmony_ci if (type != kWasmBottom) return 0; 5501cb0ef41Sopenharmony_ci return static_cast<uint32_t>(sig->parameter_count()); 5511cb0ef41Sopenharmony_ci } 5521cb0ef41Sopenharmony_ci uint32_t out_arity() const { 5531cb0ef41Sopenharmony_ci if (type == kWasmVoid) return 0; 5541cb0ef41Sopenharmony_ci if (type != kWasmBottom) return 1; 5551cb0ef41Sopenharmony_ci return static_cast<uint32_t>(sig->return_count()); 5561cb0ef41Sopenharmony_ci } 5571cb0ef41Sopenharmony_ci ValueType in_type(uint32_t index) { 5581cb0ef41Sopenharmony_ci DCHECK_EQ(kWasmBottom, type); 5591cb0ef41Sopenharmony_ci return sig->GetParam(index); 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci ValueType out_type(uint32_t index) { 5621cb0ef41Sopenharmony_ci if (type == kWasmBottom) return sig->GetReturn(index); 5631cb0ef41Sopenharmony_ci DCHECK_NE(kWasmVoid, type); 5641cb0ef41Sopenharmony_ci DCHECK_EQ(0, index); 5651cb0ef41Sopenharmony_ci return type; 5661cb0ef41Sopenharmony_ci } 5671cb0ef41Sopenharmony_ci}; 5681cb0ef41Sopenharmony_ci 5691cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 5701cb0ef41Sopenharmony_cistruct BranchDepthImmediate { 5711cb0ef41Sopenharmony_ci uint32_t depth; 5721cb0ef41Sopenharmony_ci uint32_t length; 5731cb0ef41Sopenharmony_ci BranchDepthImmediate(Decoder* decoder, const byte* pc) { 5741cb0ef41Sopenharmony_ci depth = decoder->read_u32v<validate>(pc, &length, "branch depth"); 5751cb0ef41Sopenharmony_ci } 5761cb0ef41Sopenharmony_ci}; 5771cb0ef41Sopenharmony_ci 5781cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 5791cb0ef41Sopenharmony_cistruct FieldImmediate { 5801cb0ef41Sopenharmony_ci StructIndexImmediate<validate> struct_imm; 5811cb0ef41Sopenharmony_ci IndexImmediate<validate> field_imm; 5821cb0ef41Sopenharmony_ci uint32_t length; 5831cb0ef41Sopenharmony_ci FieldImmediate(Decoder* decoder, const byte* pc) 5841cb0ef41Sopenharmony_ci : struct_imm(decoder, pc), 5851cb0ef41Sopenharmony_ci field_imm(decoder, pc + struct_imm.length, "field index"), 5861cb0ef41Sopenharmony_ci length(struct_imm.length + field_imm.length) {} 5871cb0ef41Sopenharmony_ci}; 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 5901cb0ef41Sopenharmony_cistruct CallIndirectImmediate { 5911cb0ef41Sopenharmony_ci IndexImmediate<validate> sig_imm; 5921cb0ef41Sopenharmony_ci IndexImmediate<validate> table_imm; 5931cb0ef41Sopenharmony_ci uint32_t length; 5941cb0ef41Sopenharmony_ci const FunctionSig* sig = nullptr; 5951cb0ef41Sopenharmony_ci CallIndirectImmediate(Decoder* decoder, const byte* pc) 5961cb0ef41Sopenharmony_ci : sig_imm(decoder, pc, "singature index"), 5971cb0ef41Sopenharmony_ci table_imm(decoder, pc + sig_imm.length, "table index"), 5981cb0ef41Sopenharmony_ci length(sig_imm.length + table_imm.length) {} 5991cb0ef41Sopenharmony_ci}; 6001cb0ef41Sopenharmony_ci 6011cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 6021cb0ef41Sopenharmony_cistruct BranchTableImmediate { 6031cb0ef41Sopenharmony_ci uint32_t table_count; 6041cb0ef41Sopenharmony_ci const byte* start; 6051cb0ef41Sopenharmony_ci const byte* table; 6061cb0ef41Sopenharmony_ci BranchTableImmediate(Decoder* decoder, const byte* pc) { 6071cb0ef41Sopenharmony_ci start = pc; 6081cb0ef41Sopenharmony_ci uint32_t len = 0; 6091cb0ef41Sopenharmony_ci table_count = decoder->read_u32v<validate>(pc, &len, "table count"); 6101cb0ef41Sopenharmony_ci table = pc + len; 6111cb0ef41Sopenharmony_ci } 6121cb0ef41Sopenharmony_ci}; 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci// A helper to iterate over a branch table. 6151cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 6161cb0ef41Sopenharmony_ciclass BranchTableIterator { 6171cb0ef41Sopenharmony_ci public: 6181cb0ef41Sopenharmony_ci uint32_t cur_index() { return index_; } 6191cb0ef41Sopenharmony_ci bool has_next() { return VALIDATE(decoder_->ok()) && index_ <= table_count_; } 6201cb0ef41Sopenharmony_ci uint32_t next() { 6211cb0ef41Sopenharmony_ci DCHECK(has_next()); 6221cb0ef41Sopenharmony_ci index_++; 6231cb0ef41Sopenharmony_ci uint32_t length; 6241cb0ef41Sopenharmony_ci uint32_t result = 6251cb0ef41Sopenharmony_ci decoder_->read_u32v<validate>(pc_, &length, "branch table entry"); 6261cb0ef41Sopenharmony_ci pc_ += length; 6271cb0ef41Sopenharmony_ci return result; 6281cb0ef41Sopenharmony_ci } 6291cb0ef41Sopenharmony_ci // length, including the length of the {BranchTableImmediate}, but not the 6301cb0ef41Sopenharmony_ci // opcode. 6311cb0ef41Sopenharmony_ci uint32_t length() { 6321cb0ef41Sopenharmony_ci while (has_next()) next(); 6331cb0ef41Sopenharmony_ci return static_cast<uint32_t>(pc_ - start_); 6341cb0ef41Sopenharmony_ci } 6351cb0ef41Sopenharmony_ci const byte* pc() { return pc_; } 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_ci BranchTableIterator(Decoder* decoder, 6381cb0ef41Sopenharmony_ci const BranchTableImmediate<validate>& imm) 6391cb0ef41Sopenharmony_ci : decoder_(decoder), 6401cb0ef41Sopenharmony_ci start_(imm.start), 6411cb0ef41Sopenharmony_ci pc_(imm.table), 6421cb0ef41Sopenharmony_ci table_count_(imm.table_count) {} 6431cb0ef41Sopenharmony_ci 6441cb0ef41Sopenharmony_ci private: 6451cb0ef41Sopenharmony_ci Decoder* const decoder_; 6461cb0ef41Sopenharmony_ci const byte* start_; 6471cb0ef41Sopenharmony_ci const byte* pc_; 6481cb0ef41Sopenharmony_ci uint32_t index_ = 0; // the current index. 6491cb0ef41Sopenharmony_ci const uint32_t table_count_; // the count of entries, not including default. 6501cb0ef41Sopenharmony_ci}; 6511cb0ef41Sopenharmony_ci 6521cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate, 6531cb0ef41Sopenharmony_ci DecodingMode decoding_mode = kFunctionBody> 6541cb0ef41Sopenharmony_ciclass WasmDecoder; 6551cb0ef41Sopenharmony_ci 6561cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 6571cb0ef41Sopenharmony_cistruct MemoryAccessImmediate { 6581cb0ef41Sopenharmony_ci uint32_t alignment; 6591cb0ef41Sopenharmony_ci uint64_t offset; 6601cb0ef41Sopenharmony_ci uint32_t length = 0; 6611cb0ef41Sopenharmony_ci MemoryAccessImmediate(Decoder* decoder, const byte* pc, 6621cb0ef41Sopenharmony_ci uint32_t max_alignment, bool is_memory64) { 6631cb0ef41Sopenharmony_ci uint32_t alignment_length; 6641cb0ef41Sopenharmony_ci alignment = 6651cb0ef41Sopenharmony_ci decoder->read_u32v<validate>(pc, &alignment_length, "alignment"); 6661cb0ef41Sopenharmony_ci if (!VALIDATE(alignment <= max_alignment)) { 6671cb0ef41Sopenharmony_ci DecodeError<validate>( 6681cb0ef41Sopenharmony_ci decoder, pc, 6691cb0ef41Sopenharmony_ci "invalid alignment; expected maximum alignment is %u, " 6701cb0ef41Sopenharmony_ci "actual alignment is %u", 6711cb0ef41Sopenharmony_ci max_alignment, alignment); 6721cb0ef41Sopenharmony_ci } 6731cb0ef41Sopenharmony_ci uint32_t offset_length; 6741cb0ef41Sopenharmony_ci offset = is_memory64 ? decoder->read_u64v<validate>( 6751cb0ef41Sopenharmony_ci pc + alignment_length, &offset_length, "offset") 6761cb0ef41Sopenharmony_ci : decoder->read_u32v<validate>( 6771cb0ef41Sopenharmony_ci pc + alignment_length, &offset_length, "offset"); 6781cb0ef41Sopenharmony_ci length = alignment_length + offset_length; 6791cb0ef41Sopenharmony_ci } 6801cb0ef41Sopenharmony_ci}; 6811cb0ef41Sopenharmony_ci 6821cb0ef41Sopenharmony_ci// Immediate for SIMD lane operations. 6831cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 6841cb0ef41Sopenharmony_cistruct SimdLaneImmediate { 6851cb0ef41Sopenharmony_ci uint8_t lane; 6861cb0ef41Sopenharmony_ci uint32_t length = 1; 6871cb0ef41Sopenharmony_ci 6881cb0ef41Sopenharmony_ci SimdLaneImmediate(Decoder* decoder, const byte* pc) { 6891cb0ef41Sopenharmony_ci lane = decoder->read_u8<validate>(pc, "lane"); 6901cb0ef41Sopenharmony_ci } 6911cb0ef41Sopenharmony_ci}; 6921cb0ef41Sopenharmony_ci 6931cb0ef41Sopenharmony_ci// Immediate for SIMD S8x16 shuffle operations. 6941cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 6951cb0ef41Sopenharmony_cistruct Simd128Immediate { 6961cb0ef41Sopenharmony_ci uint8_t value[kSimd128Size] = {0}; 6971cb0ef41Sopenharmony_ci 6981cb0ef41Sopenharmony_ci Simd128Immediate(Decoder* decoder, const byte* pc) { 6991cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < kSimd128Size; ++i) { 7001cb0ef41Sopenharmony_ci value[i] = decoder->read_u8<validate>(pc + i, "value"); 7011cb0ef41Sopenharmony_ci } 7021cb0ef41Sopenharmony_ci } 7031cb0ef41Sopenharmony_ci}; 7041cb0ef41Sopenharmony_ci 7051cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 7061cb0ef41Sopenharmony_cistruct MemoryInitImmediate { 7071cb0ef41Sopenharmony_ci IndexImmediate<validate> data_segment; 7081cb0ef41Sopenharmony_ci MemoryIndexImmediate<validate> memory; 7091cb0ef41Sopenharmony_ci uint32_t length; 7101cb0ef41Sopenharmony_ci 7111cb0ef41Sopenharmony_ci MemoryInitImmediate(Decoder* decoder, const byte* pc) 7121cb0ef41Sopenharmony_ci : data_segment(decoder, pc, "data segment index"), 7131cb0ef41Sopenharmony_ci memory(decoder, pc + data_segment.length), 7141cb0ef41Sopenharmony_ci length(data_segment.length + memory.length) {} 7151cb0ef41Sopenharmony_ci}; 7161cb0ef41Sopenharmony_ci 7171cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 7181cb0ef41Sopenharmony_cistruct MemoryCopyImmediate { 7191cb0ef41Sopenharmony_ci MemoryIndexImmediate<validate> memory_src; 7201cb0ef41Sopenharmony_ci MemoryIndexImmediate<validate> memory_dst; 7211cb0ef41Sopenharmony_ci uint32_t length; 7221cb0ef41Sopenharmony_ci 7231cb0ef41Sopenharmony_ci MemoryCopyImmediate(Decoder* decoder, const byte* pc) 7241cb0ef41Sopenharmony_ci : memory_src(decoder, pc), 7251cb0ef41Sopenharmony_ci memory_dst(decoder, pc + memory_src.length), 7261cb0ef41Sopenharmony_ci length(memory_src.length + memory_dst.length) {} 7271cb0ef41Sopenharmony_ci}; 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 7301cb0ef41Sopenharmony_cistruct TableInitImmediate { 7311cb0ef41Sopenharmony_ci IndexImmediate<validate> element_segment; 7321cb0ef41Sopenharmony_ci IndexImmediate<validate> table; 7331cb0ef41Sopenharmony_ci uint32_t length; 7341cb0ef41Sopenharmony_ci 7351cb0ef41Sopenharmony_ci TableInitImmediate(Decoder* decoder, const byte* pc) 7361cb0ef41Sopenharmony_ci : element_segment(decoder, pc, "element segment index"), 7371cb0ef41Sopenharmony_ci table(decoder, pc + element_segment.length, "table index"), 7381cb0ef41Sopenharmony_ci length(element_segment.length + table.length) {} 7391cb0ef41Sopenharmony_ci}; 7401cb0ef41Sopenharmony_ci 7411cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 7421cb0ef41Sopenharmony_cistruct TableCopyImmediate { 7431cb0ef41Sopenharmony_ci IndexImmediate<validate> table_dst; 7441cb0ef41Sopenharmony_ci IndexImmediate<validate> table_src; 7451cb0ef41Sopenharmony_ci uint32_t length; 7461cb0ef41Sopenharmony_ci 7471cb0ef41Sopenharmony_ci TableCopyImmediate(Decoder* decoder, const byte* pc) 7481cb0ef41Sopenharmony_ci : table_dst(decoder, pc, "table index"), 7491cb0ef41Sopenharmony_ci table_src(decoder, pc + table_dst.length, "table index"), 7501cb0ef41Sopenharmony_ci length(table_src.length + table_dst.length) {} 7511cb0ef41Sopenharmony_ci}; 7521cb0ef41Sopenharmony_ci 7531cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 7541cb0ef41Sopenharmony_cistruct HeapTypeImmediate { 7551cb0ef41Sopenharmony_ci uint32_t length = 1; 7561cb0ef41Sopenharmony_ci HeapType type; 7571cb0ef41Sopenharmony_ci HeapTypeImmediate(const WasmFeatures& enabled, Decoder* decoder, 7581cb0ef41Sopenharmony_ci const byte* pc, const WasmModule* module) 7591cb0ef41Sopenharmony_ci : type(value_type_reader::read_heap_type<validate>(decoder, pc, &length, 7601cb0ef41Sopenharmony_ci module, enabled)) {} 7611cb0ef41Sopenharmony_ci}; 7621cb0ef41Sopenharmony_ci 7631cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 7641cb0ef41Sopenharmony_cistruct PcForErrors { 7651cb0ef41Sopenharmony_ci PcForErrors(const byte* /* pc */) {} 7661cb0ef41Sopenharmony_ci 7671cb0ef41Sopenharmony_ci const byte* pc() const { return nullptr; } 7681cb0ef41Sopenharmony_ci}; 7691cb0ef41Sopenharmony_ci 7701cb0ef41Sopenharmony_citemplate <> 7711cb0ef41Sopenharmony_cistruct PcForErrors<Decoder::kFullValidation> { 7721cb0ef41Sopenharmony_ci const byte* pc_for_errors = nullptr; 7731cb0ef41Sopenharmony_ci 7741cb0ef41Sopenharmony_ci PcForErrors(const byte* pc) : pc_for_errors(pc) {} 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ci const byte* pc() const { return pc_for_errors; } 7771cb0ef41Sopenharmony_ci}; 7781cb0ef41Sopenharmony_ci 7791cb0ef41Sopenharmony_ci// An entry on the value stack. 7801cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate> 7811cb0ef41Sopenharmony_cistruct ValueBase : public PcForErrors<validate> { 7821cb0ef41Sopenharmony_ci ValueType type = kWasmVoid; 7831cb0ef41Sopenharmony_ci 7841cb0ef41Sopenharmony_ci ValueBase(const byte* pc, ValueType type) 7851cb0ef41Sopenharmony_ci : PcForErrors<validate>(pc), type(type) {} 7861cb0ef41Sopenharmony_ci}; 7871cb0ef41Sopenharmony_ci 7881cb0ef41Sopenharmony_citemplate <typename Value> 7891cb0ef41Sopenharmony_cistruct Merge { 7901cb0ef41Sopenharmony_ci uint32_t arity = 0; 7911cb0ef41Sopenharmony_ci union { // Either multiple values or a single value. 7921cb0ef41Sopenharmony_ci Value* array; 7931cb0ef41Sopenharmony_ci Value first; 7941cb0ef41Sopenharmony_ci } vals = {nullptr}; // Initialize {array} with {nullptr}. 7951cb0ef41Sopenharmony_ci 7961cb0ef41Sopenharmony_ci // Tracks whether this merge was ever reached. Uses precise reachability, like 7971cb0ef41Sopenharmony_ci // Reachability::kReachable. 7981cb0ef41Sopenharmony_ci bool reached; 7991cb0ef41Sopenharmony_ci 8001cb0ef41Sopenharmony_ci explicit Merge(bool reached = false) : reached(reached) {} 8011cb0ef41Sopenharmony_ci 8021cb0ef41Sopenharmony_ci Value& operator[](uint32_t i) { 8031cb0ef41Sopenharmony_ci DCHECK_GT(arity, i); 8041cb0ef41Sopenharmony_ci return arity == 1 ? vals.first : vals.array[i]; 8051cb0ef41Sopenharmony_ci } 8061cb0ef41Sopenharmony_ci}; 8071cb0ef41Sopenharmony_ci 8081cb0ef41Sopenharmony_cienum ControlKind : uint8_t { 8091cb0ef41Sopenharmony_ci kControlIf, 8101cb0ef41Sopenharmony_ci kControlIfElse, 8111cb0ef41Sopenharmony_ci kControlBlock, 8121cb0ef41Sopenharmony_ci kControlLoop, 8131cb0ef41Sopenharmony_ci kControlLet, 8141cb0ef41Sopenharmony_ci kControlTry, 8151cb0ef41Sopenharmony_ci kControlTryCatch, 8161cb0ef41Sopenharmony_ci kControlTryCatchAll, 8171cb0ef41Sopenharmony_ci}; 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_cienum Reachability : uint8_t { 8201cb0ef41Sopenharmony_ci // reachable code. 8211cb0ef41Sopenharmony_ci kReachable, 8221cb0ef41Sopenharmony_ci // reachable code in unreachable block (implies normal validation). 8231cb0ef41Sopenharmony_ci kSpecOnlyReachable, 8241cb0ef41Sopenharmony_ci // code unreachable in its own block (implies polymorphic validation). 8251cb0ef41Sopenharmony_ci kUnreachable 8261cb0ef41Sopenharmony_ci}; 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_ci// An entry on the control stack (i.e. if, block, loop, or try). 8291cb0ef41Sopenharmony_citemplate <typename Value, Decoder::ValidateFlag validate> 8301cb0ef41Sopenharmony_cistruct ControlBase : public PcForErrors<validate> { 8311cb0ef41Sopenharmony_ci ControlKind kind = kControlBlock; 8321cb0ef41Sopenharmony_ci uint32_t locals_count = 0; // Additional locals introduced in this 'let'. 8331cb0ef41Sopenharmony_ci uint32_t stack_depth = 0; // Stack height at the beginning of the construct. 8341cb0ef41Sopenharmony_ci uint32_t init_stack_depth = 0; // Height of "locals initialization" stack 8351cb0ef41Sopenharmony_ci // at the beginning of the construct. 8361cb0ef41Sopenharmony_ci int32_t previous_catch = -1; // Depth of the innermost catch containing this 8371cb0ef41Sopenharmony_ci // 'try'. 8381cb0ef41Sopenharmony_ci Reachability reachability = kReachable; 8391cb0ef41Sopenharmony_ci 8401cb0ef41Sopenharmony_ci // Values merged into the start or end of this control construct. 8411cb0ef41Sopenharmony_ci Merge<Value> start_merge; 8421cb0ef41Sopenharmony_ci Merge<Value> end_merge; 8431cb0ef41Sopenharmony_ci 8441cb0ef41Sopenharmony_ci MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ControlBase); 8451cb0ef41Sopenharmony_ci 8461cb0ef41Sopenharmony_ci ControlBase(ControlKind kind, uint32_t locals_count, uint32_t stack_depth, 8471cb0ef41Sopenharmony_ci uint32_t init_stack_depth, const uint8_t* pc, 8481cb0ef41Sopenharmony_ci Reachability reachability) 8491cb0ef41Sopenharmony_ci : PcForErrors<validate>(pc), 8501cb0ef41Sopenharmony_ci kind(kind), 8511cb0ef41Sopenharmony_ci locals_count(locals_count), 8521cb0ef41Sopenharmony_ci stack_depth(stack_depth), 8531cb0ef41Sopenharmony_ci init_stack_depth(init_stack_depth), 8541cb0ef41Sopenharmony_ci reachability(reachability), 8551cb0ef41Sopenharmony_ci start_merge(reachability == kReachable) { 8561cb0ef41Sopenharmony_ci DCHECK(kind == kControlLet || locals_count == 0); 8571cb0ef41Sopenharmony_ci } 8581cb0ef41Sopenharmony_ci 8591cb0ef41Sopenharmony_ci // Check whether the current block is reachable. 8601cb0ef41Sopenharmony_ci bool reachable() const { return reachability == kReachable; } 8611cb0ef41Sopenharmony_ci 8621cb0ef41Sopenharmony_ci // Check whether the rest of the block is unreachable. 8631cb0ef41Sopenharmony_ci // Note that this is different from {!reachable()}, as there is also the 8641cb0ef41Sopenharmony_ci // "indirect unreachable state", for which both {reachable()} and 8651cb0ef41Sopenharmony_ci // {unreachable()} return false. 8661cb0ef41Sopenharmony_ci bool unreachable() const { return reachability == kUnreachable; } 8671cb0ef41Sopenharmony_ci 8681cb0ef41Sopenharmony_ci // Return the reachability of new control structs started in this block. 8691cb0ef41Sopenharmony_ci Reachability innerReachability() const { 8701cb0ef41Sopenharmony_ci return reachability == kReachable ? kReachable : kSpecOnlyReachable; 8711cb0ef41Sopenharmony_ci } 8721cb0ef41Sopenharmony_ci 8731cb0ef41Sopenharmony_ci bool is_if() const { return is_onearmed_if() || is_if_else(); } 8741cb0ef41Sopenharmony_ci bool is_onearmed_if() const { return kind == kControlIf; } 8751cb0ef41Sopenharmony_ci bool is_if_else() const { return kind == kControlIfElse; } 8761cb0ef41Sopenharmony_ci bool is_block() const { return kind == kControlBlock; } 8771cb0ef41Sopenharmony_ci bool is_let() const { return kind == kControlLet; } 8781cb0ef41Sopenharmony_ci bool is_loop() const { return kind == kControlLoop; } 8791cb0ef41Sopenharmony_ci bool is_incomplete_try() const { return kind == kControlTry; } 8801cb0ef41Sopenharmony_ci bool is_try_catch() const { return kind == kControlTryCatch; } 8811cb0ef41Sopenharmony_ci bool is_try_catchall() const { return kind == kControlTryCatchAll; } 8821cb0ef41Sopenharmony_ci bool is_try() const { 8831cb0ef41Sopenharmony_ci return is_incomplete_try() || is_try_catch() || is_try_catchall(); 8841cb0ef41Sopenharmony_ci } 8851cb0ef41Sopenharmony_ci 8861cb0ef41Sopenharmony_ci Merge<Value>* br_merge() { 8871cb0ef41Sopenharmony_ci return is_loop() ? &this->start_merge : &this->end_merge; 8881cb0ef41Sopenharmony_ci } 8891cb0ef41Sopenharmony_ci}; 8901cb0ef41Sopenharmony_ci 8911cb0ef41Sopenharmony_ci// This is the list of callback functions that an interface for the 8921cb0ef41Sopenharmony_ci// WasmFullDecoder should implement. 8931cb0ef41Sopenharmony_ci// F(Name, args...) 8941cb0ef41Sopenharmony_ci#define INTERFACE_FUNCTIONS(F) \ 8951cb0ef41Sopenharmony_ci INTERFACE_META_FUNCTIONS(F) \ 8961cb0ef41Sopenharmony_ci INTERFACE_CONSTANT_FUNCTIONS(F) \ 8971cb0ef41Sopenharmony_ci INTERFACE_NON_CONSTANT_FUNCTIONS(F) 8981cb0ef41Sopenharmony_ci 8991cb0ef41Sopenharmony_ci#define INTERFACE_META_FUNCTIONS(F) \ 9001cb0ef41Sopenharmony_ci F(StartFunction) \ 9011cb0ef41Sopenharmony_ci F(StartFunctionBody, Control* block) \ 9021cb0ef41Sopenharmony_ci F(FinishFunction) \ 9031cb0ef41Sopenharmony_ci F(OnFirstError) \ 9041cb0ef41Sopenharmony_ci F(NextInstruction, WasmOpcode) \ 9051cb0ef41Sopenharmony_ci F(Forward, const Value& from, Value* to) 9061cb0ef41Sopenharmony_ci 9071cb0ef41Sopenharmony_ci#define INTERFACE_CONSTANT_FUNCTIONS(F) \ 9081cb0ef41Sopenharmony_ci F(I32Const, Value* result, int32_t value) \ 9091cb0ef41Sopenharmony_ci F(I64Const, Value* result, int64_t value) \ 9101cb0ef41Sopenharmony_ci F(F32Const, Value* result, float value) \ 9111cb0ef41Sopenharmony_ci F(F64Const, Value* result, double value) \ 9121cb0ef41Sopenharmony_ci F(S128Const, Simd128Immediate<validate>& imm, Value* result) \ 9131cb0ef41Sopenharmony_ci F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \ 9141cb0ef41Sopenharmony_ci Value* result) \ 9151cb0ef41Sopenharmony_ci F(RefNull, ValueType type, Value* result) \ 9161cb0ef41Sopenharmony_ci F(RefFunc, uint32_t function_index, Value* result) \ 9171cb0ef41Sopenharmony_ci F(GlobalGet, Value* result, const GlobalIndexImmediate<validate>& imm) \ 9181cb0ef41Sopenharmony_ci F(StructNewWithRtt, const StructIndexImmediate<validate>& imm, \ 9191cb0ef41Sopenharmony_ci const Value& rtt, const Value args[], Value* result) \ 9201cb0ef41Sopenharmony_ci F(StructNewDefault, const StructIndexImmediate<validate>& imm, \ 9211cb0ef41Sopenharmony_ci const Value& rtt, Value* result) \ 9221cb0ef41Sopenharmony_ci F(ArrayInit, const ArrayIndexImmediate<validate>& imm, \ 9231cb0ef41Sopenharmony_ci const base::Vector<Value>& elements, const Value& rtt, Value* result) \ 9241cb0ef41Sopenharmony_ci F(ArrayInitFromData, const ArrayIndexImmediate<validate>& array_imm, \ 9251cb0ef41Sopenharmony_ci const IndexImmediate<validate>& data_segment, const Value& offset, \ 9261cb0ef41Sopenharmony_ci const Value& length, const Value& rtt, Value* result) \ 9271cb0ef41Sopenharmony_ci F(RttCanon, uint32_t type_index, Value* result) \ 9281cb0ef41Sopenharmony_ci F(DoReturn, uint32_t drop_values) 9291cb0ef41Sopenharmony_ci 9301cb0ef41Sopenharmony_ci#define INTERFACE_NON_CONSTANT_FUNCTIONS(F) /* force 80 columns */ \ 9311cb0ef41Sopenharmony_ci /* Control: */ \ 9321cb0ef41Sopenharmony_ci F(Block, Control* block) \ 9331cb0ef41Sopenharmony_ci F(Loop, Control* block) \ 9341cb0ef41Sopenharmony_ci F(Try, Control* block) \ 9351cb0ef41Sopenharmony_ci F(If, const Value& cond, Control* if_block) \ 9361cb0ef41Sopenharmony_ci F(FallThruTo, Control* c) \ 9371cb0ef41Sopenharmony_ci F(PopControl, Control* block) \ 9381cb0ef41Sopenharmony_ci /* Instructions: */ \ 9391cb0ef41Sopenharmony_ci F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \ 9401cb0ef41Sopenharmony_ci F(RefAsNonNull, const Value& arg, Value* result) \ 9411cb0ef41Sopenharmony_ci F(Drop) \ 9421cb0ef41Sopenharmony_ci F(LocalGet, Value* result, const IndexImmediate<validate>& imm) \ 9431cb0ef41Sopenharmony_ci F(LocalSet, const Value& value, const IndexImmediate<validate>& imm) \ 9441cb0ef41Sopenharmony_ci F(LocalTee, const Value& value, Value* result, \ 9451cb0ef41Sopenharmony_ci const IndexImmediate<validate>& imm) \ 9461cb0ef41Sopenharmony_ci F(AllocateLocals, base::Vector<Value> local_values) \ 9471cb0ef41Sopenharmony_ci F(DeallocateLocals, uint32_t count) \ 9481cb0ef41Sopenharmony_ci F(GlobalSet, const Value& value, const GlobalIndexImmediate<validate>& imm) \ 9491cb0ef41Sopenharmony_ci F(TableGet, const Value& index, Value* result, \ 9501cb0ef41Sopenharmony_ci const IndexImmediate<validate>& imm) \ 9511cb0ef41Sopenharmony_ci F(TableSet, const Value& index, const Value& value, \ 9521cb0ef41Sopenharmony_ci const IndexImmediate<validate>& imm) \ 9531cb0ef41Sopenharmony_ci F(Trap, TrapReason reason) \ 9541cb0ef41Sopenharmony_ci F(NopForTestingUnsupportedInLiftoff) \ 9551cb0ef41Sopenharmony_ci F(Select, const Value& cond, const Value& fval, const Value& tval, \ 9561cb0ef41Sopenharmony_ci Value* result) \ 9571cb0ef41Sopenharmony_ci F(BrOrRet, uint32_t depth, uint32_t drop_values) \ 9581cb0ef41Sopenharmony_ci F(BrIf, const Value& cond, uint32_t depth) \ 9591cb0ef41Sopenharmony_ci F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \ 9601cb0ef41Sopenharmony_ci F(Else, Control* if_block) \ 9611cb0ef41Sopenharmony_ci F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \ 9621cb0ef41Sopenharmony_ci const Value& index, Value* result) \ 9631cb0ef41Sopenharmony_ci F(LoadTransform, LoadType type, LoadTransformationKind transform, \ 9641cb0ef41Sopenharmony_ci const MemoryAccessImmediate<validate>& imm, const Value& index, \ 9651cb0ef41Sopenharmony_ci Value* result) \ 9661cb0ef41Sopenharmony_ci F(LoadLane, LoadType type, const Value& value, const Value& index, \ 9671cb0ef41Sopenharmony_ci const MemoryAccessImmediate<validate>& imm, const uint8_t laneidx, \ 9681cb0ef41Sopenharmony_ci Value* result) \ 9691cb0ef41Sopenharmony_ci F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \ 9701cb0ef41Sopenharmony_ci const Value& index, const Value& value) \ 9711cb0ef41Sopenharmony_ci F(StoreLane, StoreType type, const MemoryAccessImmediate<validate>& imm, \ 9721cb0ef41Sopenharmony_ci const Value& index, const Value& value, const uint8_t laneidx) \ 9731cb0ef41Sopenharmony_ci F(CurrentMemoryPages, Value* result) \ 9741cb0ef41Sopenharmony_ci F(MemoryGrow, const Value& value, Value* result) \ 9751cb0ef41Sopenharmony_ci F(CallDirect, const CallFunctionImmediate<validate>& imm, \ 9761cb0ef41Sopenharmony_ci const Value args[], Value returns[]) \ 9771cb0ef41Sopenharmony_ci F(CallIndirect, const Value& index, \ 9781cb0ef41Sopenharmony_ci const CallIndirectImmediate<validate>& imm, const Value args[], \ 9791cb0ef41Sopenharmony_ci Value returns[]) \ 9801cb0ef41Sopenharmony_ci F(CallRef, const Value& func_ref, const FunctionSig* sig, \ 9811cb0ef41Sopenharmony_ci uint32_t sig_index, const Value args[], const Value returns[]) \ 9821cb0ef41Sopenharmony_ci F(ReturnCallRef, const Value& func_ref, const FunctionSig* sig, \ 9831cb0ef41Sopenharmony_ci uint32_t sig_index, const Value args[]) \ 9841cb0ef41Sopenharmony_ci F(ReturnCall, const CallFunctionImmediate<validate>& imm, \ 9851cb0ef41Sopenharmony_ci const Value args[]) \ 9861cb0ef41Sopenharmony_ci F(ReturnCallIndirect, const Value& index, \ 9871cb0ef41Sopenharmony_ci const CallIndirectImmediate<validate>& imm, const Value args[]) \ 9881cb0ef41Sopenharmony_ci F(BrOnNull, const Value& ref_object, uint32_t depth, \ 9891cb0ef41Sopenharmony_ci bool pass_null_along_branch, Value* result_on_fallthrough) \ 9901cb0ef41Sopenharmony_ci F(BrOnNonNull, const Value& ref_object, uint32_t depth) \ 9911cb0ef41Sopenharmony_ci F(SimdOp, WasmOpcode opcode, base::Vector<Value> args, Value* result) \ 9921cb0ef41Sopenharmony_ci F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \ 9931cb0ef41Sopenharmony_ci const base::Vector<Value> inputs, Value* result) \ 9941cb0ef41Sopenharmony_ci F(S128Const, const Simd128Immediate<validate>& imm, Value* result) \ 9951cb0ef41Sopenharmony_ci F(Simd8x16ShuffleOp, const Simd128Immediate<validate>& imm, \ 9961cb0ef41Sopenharmony_ci const Value& input0, const Value& input1, Value* result) \ 9971cb0ef41Sopenharmony_ci F(Throw, const TagIndexImmediate<validate>& imm, \ 9981cb0ef41Sopenharmony_ci const base::Vector<Value>& args) \ 9991cb0ef41Sopenharmony_ci F(Rethrow, Control* block) \ 10001cb0ef41Sopenharmony_ci F(CatchException, const TagIndexImmediate<validate>& imm, Control* block, \ 10011cb0ef41Sopenharmony_ci base::Vector<Value> caught_values) \ 10021cb0ef41Sopenharmony_ci F(Delegate, uint32_t depth, Control* block) \ 10031cb0ef41Sopenharmony_ci F(CatchAll, Control* block) \ 10041cb0ef41Sopenharmony_ci F(AtomicOp, WasmOpcode opcode, base::Vector<Value> args, \ 10051cb0ef41Sopenharmony_ci const MemoryAccessImmediate<validate>& imm, Value* result) \ 10061cb0ef41Sopenharmony_ci F(AtomicFence) \ 10071cb0ef41Sopenharmony_ci F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \ 10081cb0ef41Sopenharmony_ci const Value& src, const Value& size) \ 10091cb0ef41Sopenharmony_ci F(DataDrop, const IndexImmediate<validate>& imm) \ 10101cb0ef41Sopenharmony_ci F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst, \ 10111cb0ef41Sopenharmony_ci const Value& src, const Value& size) \ 10121cb0ef41Sopenharmony_ci F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \ 10131cb0ef41Sopenharmony_ci const Value& value, const Value& size) \ 10141cb0ef41Sopenharmony_ci F(TableInit, const TableInitImmediate<validate>& imm, \ 10151cb0ef41Sopenharmony_ci base::Vector<Value> args) \ 10161cb0ef41Sopenharmony_ci F(ElemDrop, const IndexImmediate<validate>& imm) \ 10171cb0ef41Sopenharmony_ci F(TableCopy, const TableCopyImmediate<validate>& imm, \ 10181cb0ef41Sopenharmony_ci base::Vector<Value> args) \ 10191cb0ef41Sopenharmony_ci F(TableGrow, const IndexImmediate<validate>& imm, const Value& value, \ 10201cb0ef41Sopenharmony_ci const Value& delta, Value* result) \ 10211cb0ef41Sopenharmony_ci F(TableSize, const IndexImmediate<validate>& imm, Value* result) \ 10221cb0ef41Sopenharmony_ci F(TableFill, const IndexImmediate<validate>& imm, const Value& start, \ 10231cb0ef41Sopenharmony_ci const Value& value, const Value& count) \ 10241cb0ef41Sopenharmony_ci F(StructGet, const Value& struct_object, \ 10251cb0ef41Sopenharmony_ci const FieldImmediate<validate>& field, bool is_signed, Value* result) \ 10261cb0ef41Sopenharmony_ci F(StructSet, const Value& struct_object, \ 10271cb0ef41Sopenharmony_ci const FieldImmediate<validate>& field, const Value& field_value) \ 10281cb0ef41Sopenharmony_ci F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \ 10291cb0ef41Sopenharmony_ci const Value& length, const Value& initial_value, const Value& rtt, \ 10301cb0ef41Sopenharmony_ci Value* result) \ 10311cb0ef41Sopenharmony_ci F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm, \ 10321cb0ef41Sopenharmony_ci const Value& length, const Value& rtt, Value* result) \ 10331cb0ef41Sopenharmony_ci F(ArrayGet, const Value& array_obj, \ 10341cb0ef41Sopenharmony_ci const ArrayIndexImmediate<validate>& imm, const Value& index, \ 10351cb0ef41Sopenharmony_ci bool is_signed, Value* result) \ 10361cb0ef41Sopenharmony_ci F(ArraySet, const Value& array_obj, \ 10371cb0ef41Sopenharmony_ci const ArrayIndexImmediate<validate>& imm, const Value& index, \ 10381cb0ef41Sopenharmony_ci const Value& value) \ 10391cb0ef41Sopenharmony_ci F(ArrayLen, const Value& array_obj, Value* result) \ 10401cb0ef41Sopenharmony_ci F(ArrayCopy, const Value& src, const Value& src_index, const Value& dst, \ 10411cb0ef41Sopenharmony_ci const Value& dst_index, const Value& length) \ 10421cb0ef41Sopenharmony_ci F(I31New, const Value& input, Value* result) \ 10431cb0ef41Sopenharmony_ci F(I31GetS, const Value& input, Value* result) \ 10441cb0ef41Sopenharmony_ci F(I31GetU, const Value& input, Value* result) \ 10451cb0ef41Sopenharmony_ci F(RefTest, const Value& obj, const Value& rtt, Value* result) \ 10461cb0ef41Sopenharmony_ci F(RefCast, const Value& obj, const Value& rtt, Value* result) \ 10471cb0ef41Sopenharmony_ci F(AssertNull, const Value& obj, Value* result) \ 10481cb0ef41Sopenharmony_ci F(BrOnCast, const Value& obj, const Value& rtt, Value* result_on_branch, \ 10491cb0ef41Sopenharmony_ci uint32_t depth) \ 10501cb0ef41Sopenharmony_ci F(BrOnCastFail, const Value& obj, const Value& rtt, \ 10511cb0ef41Sopenharmony_ci Value* result_on_fallthrough, uint32_t depth) \ 10521cb0ef41Sopenharmony_ci F(RefIsFunc, const Value& object, Value* result) \ 10531cb0ef41Sopenharmony_ci F(RefIsData, const Value& object, Value* result) \ 10541cb0ef41Sopenharmony_ci F(RefIsI31, const Value& object, Value* result) \ 10551cb0ef41Sopenharmony_ci F(RefIsArray, const Value& object, Value* result) \ 10561cb0ef41Sopenharmony_ci F(RefAsFunc, const Value& object, Value* result) \ 10571cb0ef41Sopenharmony_ci F(RefAsData, const Value& object, Value* result) \ 10581cb0ef41Sopenharmony_ci F(RefAsI31, const Value& object, Value* result) \ 10591cb0ef41Sopenharmony_ci F(RefAsArray, const Value& object, Value* result) \ 10601cb0ef41Sopenharmony_ci F(BrOnFunc, const Value& object, Value* value_on_branch, uint32_t br_depth) \ 10611cb0ef41Sopenharmony_ci F(BrOnData, const Value& object, Value* value_on_branch, uint32_t br_depth) \ 10621cb0ef41Sopenharmony_ci F(BrOnI31, const Value& object, Value* value_on_branch, uint32_t br_depth) \ 10631cb0ef41Sopenharmony_ci F(BrOnArray, const Value& object, Value* value_on_branch, uint32_t br_depth) \ 10641cb0ef41Sopenharmony_ci F(BrOnNonFunc, const Value& object, Value* value_on_fallthrough, \ 10651cb0ef41Sopenharmony_ci uint32_t br_depth) \ 10661cb0ef41Sopenharmony_ci F(BrOnNonData, const Value& object, Value* value_on_fallthrough, \ 10671cb0ef41Sopenharmony_ci uint32_t br_depth) \ 10681cb0ef41Sopenharmony_ci F(BrOnNonI31, const Value& object, Value* value_on_fallthrough, \ 10691cb0ef41Sopenharmony_ci uint32_t br_depth) \ 10701cb0ef41Sopenharmony_ci F(BrOnNonArray, const Value& object, Value* value_on_fallthrough, \ 10711cb0ef41Sopenharmony_ci uint32_t br_depth) 10721cb0ef41Sopenharmony_ci 10731cb0ef41Sopenharmony_ci// Generic Wasm bytecode decoder with utilities for decoding immediates, 10741cb0ef41Sopenharmony_ci// lengths, etc. 10751cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate, DecodingMode decoding_mode> 10761cb0ef41Sopenharmony_ciclass WasmDecoder : public Decoder { 10771cb0ef41Sopenharmony_ci public: 10781cb0ef41Sopenharmony_ci WasmDecoder(Zone* zone, const WasmModule* module, const WasmFeatures& enabled, 10791cb0ef41Sopenharmony_ci WasmFeatures* detected, const FunctionSig* sig, const byte* start, 10801cb0ef41Sopenharmony_ci const byte* end, uint32_t buffer_offset = 0) 10811cb0ef41Sopenharmony_ci : Decoder(start, end, buffer_offset), 10821cb0ef41Sopenharmony_ci local_types_(zone), 10831cb0ef41Sopenharmony_ci initialized_locals_(zone), 10841cb0ef41Sopenharmony_ci locals_initializers_stack_(zone), 10851cb0ef41Sopenharmony_ci module_(module), 10861cb0ef41Sopenharmony_ci enabled_(enabled), 10871cb0ef41Sopenharmony_ci detected_(detected), 10881cb0ef41Sopenharmony_ci sig_(sig) {} 10891cb0ef41Sopenharmony_ci 10901cb0ef41Sopenharmony_ci Zone* zone() const { return local_types_.get_allocator().zone(); } 10911cb0ef41Sopenharmony_ci 10921cb0ef41Sopenharmony_ci uint32_t num_locals() const { 10931cb0ef41Sopenharmony_ci DCHECK_EQ(num_locals_, local_types_.size()); 10941cb0ef41Sopenharmony_ci return num_locals_; 10951cb0ef41Sopenharmony_ci } 10961cb0ef41Sopenharmony_ci 10971cb0ef41Sopenharmony_ci ValueType local_type(uint32_t index) const { return local_types_[index]; } 10981cb0ef41Sopenharmony_ci 10991cb0ef41Sopenharmony_ci void InitializeLocalsFromSig() { 11001cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(sig_); 11011cb0ef41Sopenharmony_ci DCHECK_EQ(0, this->local_types_.size()); 11021cb0ef41Sopenharmony_ci local_types_.assign(sig_->parameters().begin(), sig_->parameters().end()); 11031cb0ef41Sopenharmony_ci num_locals_ = static_cast<uint32_t>(sig_->parameters().size()); 11041cb0ef41Sopenharmony_ci } 11051cb0ef41Sopenharmony_ci 11061cb0ef41Sopenharmony_ci // Decodes local definitions in the current decoder. 11071cb0ef41Sopenharmony_ci // Returns the number of newly defined locals, or -1 if decoding failed. 11081cb0ef41Sopenharmony_ci // Writes the total length of decoded locals in {total_length}. 11091cb0ef41Sopenharmony_ci // If {insert_position} is defined, the decoded locals will be inserted into 11101cb0ef41Sopenharmony_ci // the {this->local_types_}. The decoder's pc is not advanced. 11111cb0ef41Sopenharmony_ci int DecodeLocals(const byte* pc, uint32_t* total_length, 11121cb0ef41Sopenharmony_ci const base::Optional<uint32_t> insert_position) { 11131cb0ef41Sopenharmony_ci uint32_t length; 11141cb0ef41Sopenharmony_ci *total_length = 0; 11151cb0ef41Sopenharmony_ci int total_count = 0; 11161cb0ef41Sopenharmony_ci 11171cb0ef41Sopenharmony_ci // The 'else' value is useless, we pass it for convenience. 11181cb0ef41Sopenharmony_ci auto insert_iterator = insert_position.has_value() 11191cb0ef41Sopenharmony_ci ? local_types_.begin() + insert_position.value() 11201cb0ef41Sopenharmony_ci : local_types_.begin(); 11211cb0ef41Sopenharmony_ci 11221cb0ef41Sopenharmony_ci // Decode local declarations, if any. 11231cb0ef41Sopenharmony_ci uint32_t entries = read_u32v<validate>(pc, &length, "local decls count"); 11241cb0ef41Sopenharmony_ci if (!VALIDATE(ok())) { 11251cb0ef41Sopenharmony_ci DecodeError(pc + *total_length, "invalid local decls count"); 11261cb0ef41Sopenharmony_ci return -1; 11271cb0ef41Sopenharmony_ci } 11281cb0ef41Sopenharmony_ci *total_length += length; 11291cb0ef41Sopenharmony_ci TRACE("local decls count: %u\n", entries); 11301cb0ef41Sopenharmony_ci 11311cb0ef41Sopenharmony_ci while (entries-- > 0) { 11321cb0ef41Sopenharmony_ci if (!VALIDATE(more())) { 11331cb0ef41Sopenharmony_ci DecodeError(end(), 11341cb0ef41Sopenharmony_ci "expected more local decls but reached end of input"); 11351cb0ef41Sopenharmony_ci return -1; 11361cb0ef41Sopenharmony_ci } 11371cb0ef41Sopenharmony_ci 11381cb0ef41Sopenharmony_ci uint32_t count = 11391cb0ef41Sopenharmony_ci read_u32v<validate>(pc + *total_length, &length, "local count"); 11401cb0ef41Sopenharmony_ci if (!VALIDATE(ok())) { 11411cb0ef41Sopenharmony_ci DecodeError(pc + *total_length, "invalid local count"); 11421cb0ef41Sopenharmony_ci return -1; 11431cb0ef41Sopenharmony_ci } 11441cb0ef41Sopenharmony_ci DCHECK_LE(local_types_.size(), kV8MaxWasmFunctionLocals); 11451cb0ef41Sopenharmony_ci if (!VALIDATE(count <= kV8MaxWasmFunctionLocals - local_types_.size())) { 11461cb0ef41Sopenharmony_ci DecodeError(pc + *total_length, "local count too large"); 11471cb0ef41Sopenharmony_ci return -1; 11481cb0ef41Sopenharmony_ci } 11491cb0ef41Sopenharmony_ci *total_length += length; 11501cb0ef41Sopenharmony_ci 11511cb0ef41Sopenharmony_ci ValueType type = value_type_reader::read_value_type<validate>( 11521cb0ef41Sopenharmony_ci this, pc + *total_length, &length, this->module_, enabled_); 11531cb0ef41Sopenharmony_ci if (!VALIDATE(type != kWasmBottom)) return -1; 11541cb0ef41Sopenharmony_ci *total_length += length; 11551cb0ef41Sopenharmony_ci total_count += count; 11561cb0ef41Sopenharmony_ci 11571cb0ef41Sopenharmony_ci if (insert_position.has_value()) { 11581cb0ef41Sopenharmony_ci // Move the insertion iterator to the end of the newly inserted locals. 11591cb0ef41Sopenharmony_ci insert_iterator = 11601cb0ef41Sopenharmony_ci local_types_.insert(insert_iterator, count, type) + count; 11611cb0ef41Sopenharmony_ci num_locals_ += count; 11621cb0ef41Sopenharmony_ci } 11631cb0ef41Sopenharmony_ci } 11641cb0ef41Sopenharmony_ci 11651cb0ef41Sopenharmony_ci DCHECK(ok()); 11661cb0ef41Sopenharmony_ci return total_count; 11671cb0ef41Sopenharmony_ci } 11681cb0ef41Sopenharmony_ci 11691cb0ef41Sopenharmony_ci // Shorthand that forwards to the {DecodeError} functions above, passing our 11701cb0ef41Sopenharmony_ci // {validate} flag. 11711cb0ef41Sopenharmony_ci template <typename... Args> 11721cb0ef41Sopenharmony_ci void DecodeError(Args... args) { 11731cb0ef41Sopenharmony_ci wasm::DecodeError<validate>(this, std::forward<Args>(args)...); 11741cb0ef41Sopenharmony_ci } 11751cb0ef41Sopenharmony_ci 11761cb0ef41Sopenharmony_ci // Returns a BitVector of length {locals_count + 1} representing the set of 11771cb0ef41Sopenharmony_ci // variables that are assigned in the loop starting at {pc}. The additional 11781cb0ef41Sopenharmony_ci // position at the end of the vector represents possible assignments to 11791cb0ef41Sopenharmony_ci // the instance cache. 11801cb0ef41Sopenharmony_ci static BitVector* AnalyzeLoopAssignment(WasmDecoder* decoder, const byte* pc, 11811cb0ef41Sopenharmony_ci uint32_t locals_count, Zone* zone) { 11821cb0ef41Sopenharmony_ci if (pc >= decoder->end()) return nullptr; 11831cb0ef41Sopenharmony_ci if (*pc != kExprLoop) return nullptr; 11841cb0ef41Sopenharmony_ci // The number of locals_count is augmented by 1 so that the 'locals_count' 11851cb0ef41Sopenharmony_ci // index can be used to track the instance cache. 11861cb0ef41Sopenharmony_ci BitVector* assigned = zone->New<BitVector>(locals_count + 1, zone); 11871cb0ef41Sopenharmony_ci int depth = -1; // We will increment the depth to 0 when we decode the 11881cb0ef41Sopenharmony_ci // starting 'loop' opcode. 11891cb0ef41Sopenharmony_ci // Since 'let' can add additional locals at the beginning of the locals 11901cb0ef41Sopenharmony_ci // index space, we need to track this offset for every depth up to the 11911cb0ef41Sopenharmony_ci // current depth. 11921cb0ef41Sopenharmony_ci base::SmallVector<uint32_t, 8> local_offsets(8); 11931cb0ef41Sopenharmony_ci // Iteratively process all AST nodes nested inside the loop. 11941cb0ef41Sopenharmony_ci while (pc < decoder->end() && VALIDATE(decoder->ok())) { 11951cb0ef41Sopenharmony_ci WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 11961cb0ef41Sopenharmony_ci switch (opcode) { 11971cb0ef41Sopenharmony_ci case kExprLoop: 11981cb0ef41Sopenharmony_ci case kExprIf: 11991cb0ef41Sopenharmony_ci case kExprBlock: 12001cb0ef41Sopenharmony_ci case kExprTry: 12011cb0ef41Sopenharmony_ci depth++; 12021cb0ef41Sopenharmony_ci local_offsets.resize_no_init(depth + 1); 12031cb0ef41Sopenharmony_ci // No additional locals. 12041cb0ef41Sopenharmony_ci local_offsets[depth] = depth > 0 ? local_offsets[depth - 1] : 0; 12051cb0ef41Sopenharmony_ci break; 12061cb0ef41Sopenharmony_ci case kExprLet: { 12071cb0ef41Sopenharmony_ci depth++; 12081cb0ef41Sopenharmony_ci local_offsets.resize_no_init(depth + 1); 12091cb0ef41Sopenharmony_ci BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 12101cb0ef41Sopenharmony_ci nullptr); 12111cb0ef41Sopenharmony_ci uint32_t locals_length; 12121cb0ef41Sopenharmony_ci int new_locals_count = decoder->DecodeLocals( 12131cb0ef41Sopenharmony_ci pc + 1 + imm.length, &locals_length, base::Optional<uint32_t>()); 12141cb0ef41Sopenharmony_ci local_offsets[depth] = local_offsets[depth - 1] + new_locals_count; 12151cb0ef41Sopenharmony_ci break; 12161cb0ef41Sopenharmony_ci } 12171cb0ef41Sopenharmony_ci case kExprLocalSet: 12181cb0ef41Sopenharmony_ci case kExprLocalTee: { 12191cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(decoder, pc + 1, "local index"); 12201cb0ef41Sopenharmony_ci // Unverified code might have an out-of-bounds index. 12211cb0ef41Sopenharmony_ci if (imm.index >= local_offsets[depth] && 12221cb0ef41Sopenharmony_ci imm.index - local_offsets[depth] < locals_count) { 12231cb0ef41Sopenharmony_ci assigned->Add(imm.index - local_offsets[depth]); 12241cb0ef41Sopenharmony_ci } 12251cb0ef41Sopenharmony_ci break; 12261cb0ef41Sopenharmony_ci } 12271cb0ef41Sopenharmony_ci case kExprMemoryGrow: 12281cb0ef41Sopenharmony_ci case kExprCallFunction: 12291cb0ef41Sopenharmony_ci case kExprCallIndirect: 12301cb0ef41Sopenharmony_ci case kExprCallRef: 12311cb0ef41Sopenharmony_ci // Add instance cache to the assigned set. 12321cb0ef41Sopenharmony_ci assigned->Add(locals_count); 12331cb0ef41Sopenharmony_ci break; 12341cb0ef41Sopenharmony_ci case kExprEnd: 12351cb0ef41Sopenharmony_ci depth--; 12361cb0ef41Sopenharmony_ci break; 12371cb0ef41Sopenharmony_ci default: 12381cb0ef41Sopenharmony_ci break; 12391cb0ef41Sopenharmony_ci } 12401cb0ef41Sopenharmony_ci if (depth < 0) break; 12411cb0ef41Sopenharmony_ci pc += OpcodeLength(decoder, pc); 12421cb0ef41Sopenharmony_ci } 12431cb0ef41Sopenharmony_ci return VALIDATE(decoder->ok()) ? assigned : nullptr; 12441cb0ef41Sopenharmony_ci } 12451cb0ef41Sopenharmony_ci 12461cb0ef41Sopenharmony_ci bool Validate(const byte* pc, TagIndexImmediate<validate>& imm) { 12471cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index < module_->tags.size())) { 12481cb0ef41Sopenharmony_ci DecodeError(pc, "Invalid tag index: %u", imm.index); 12491cb0ef41Sopenharmony_ci return false; 12501cb0ef41Sopenharmony_ci } 12511cb0ef41Sopenharmony_ci imm.tag = &module_->tags[imm.index]; 12521cb0ef41Sopenharmony_ci return true; 12531cb0ef41Sopenharmony_ci } 12541cb0ef41Sopenharmony_ci 12551cb0ef41Sopenharmony_ci bool Validate(const byte* pc, GlobalIndexImmediate<validate>& imm) { 12561cb0ef41Sopenharmony_ci // We compare with the current size of the globals vector. This is important 12571cb0ef41Sopenharmony_ci // if we are decoding a constant expression in the global section. 12581cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index < module_->globals.size())) { 12591cb0ef41Sopenharmony_ci DecodeError(pc, "Invalid global index: %u", imm.index); 12601cb0ef41Sopenharmony_ci return false; 12611cb0ef41Sopenharmony_ci } 12621cb0ef41Sopenharmony_ci imm.global = &module_->globals[imm.index]; 12631cb0ef41Sopenharmony_ci 12641cb0ef41Sopenharmony_ci if (decoding_mode == kInitExpression) { 12651cb0ef41Sopenharmony_ci if (!VALIDATE(!imm.global->mutability)) { 12661cb0ef41Sopenharmony_ci this->DecodeError(pc, 12671cb0ef41Sopenharmony_ci "mutable globals cannot be used in initializer " 12681cb0ef41Sopenharmony_ci "expressions"); 12691cb0ef41Sopenharmony_ci return false; 12701cb0ef41Sopenharmony_ci } 12711cb0ef41Sopenharmony_ci if (!VALIDATE(imm.global->imported || this->enabled_.has_gc())) { 12721cb0ef41Sopenharmony_ci this->DecodeError( 12731cb0ef41Sopenharmony_ci pc, 12741cb0ef41Sopenharmony_ci "non-imported globals cannot be used in initializer expressions"); 12751cb0ef41Sopenharmony_ci return false; 12761cb0ef41Sopenharmony_ci } 12771cb0ef41Sopenharmony_ci } 12781cb0ef41Sopenharmony_ci 12791cb0ef41Sopenharmony_ci return true; 12801cb0ef41Sopenharmony_ci } 12811cb0ef41Sopenharmony_ci 12821cb0ef41Sopenharmony_ci bool Validate(const byte* pc, StructIndexImmediate<validate>& imm) { 12831cb0ef41Sopenharmony_ci if (!VALIDATE(module_->has_struct(imm.index))) { 12841cb0ef41Sopenharmony_ci DecodeError(pc, "invalid struct index: %u", imm.index); 12851cb0ef41Sopenharmony_ci return false; 12861cb0ef41Sopenharmony_ci } 12871cb0ef41Sopenharmony_ci imm.struct_type = module_->struct_type(imm.index); 12881cb0ef41Sopenharmony_ci return true; 12891cb0ef41Sopenharmony_ci } 12901cb0ef41Sopenharmony_ci 12911cb0ef41Sopenharmony_ci bool Validate(const byte* pc, FieldImmediate<validate>& imm) { 12921cb0ef41Sopenharmony_ci if (!Validate(pc, imm.struct_imm)) return false; 12931cb0ef41Sopenharmony_ci if (!VALIDATE(imm.field_imm.index < 12941cb0ef41Sopenharmony_ci imm.struct_imm.struct_type->field_count())) { 12951cb0ef41Sopenharmony_ci DecodeError(pc + imm.struct_imm.length, "invalid field index: %u", 12961cb0ef41Sopenharmony_ci imm.field_imm.index); 12971cb0ef41Sopenharmony_ci return false; 12981cb0ef41Sopenharmony_ci } 12991cb0ef41Sopenharmony_ci return true; 13001cb0ef41Sopenharmony_ci } 13011cb0ef41Sopenharmony_ci 13021cb0ef41Sopenharmony_ci bool Validate(const byte* pc, ArrayIndexImmediate<validate>& imm) { 13031cb0ef41Sopenharmony_ci if (!VALIDATE(module_->has_array(imm.index))) { 13041cb0ef41Sopenharmony_ci DecodeError(pc, "invalid array index: %u", imm.index); 13051cb0ef41Sopenharmony_ci return false; 13061cb0ef41Sopenharmony_ci } 13071cb0ef41Sopenharmony_ci imm.array_type = module_->array_type(imm.index); 13081cb0ef41Sopenharmony_ci return true; 13091cb0ef41Sopenharmony_ci } 13101cb0ef41Sopenharmony_ci 13111cb0ef41Sopenharmony_ci bool CanReturnCall(const FunctionSig* target_sig) { 13121cb0ef41Sopenharmony_ci if (sig_->return_count() != target_sig->return_count()) return false; 13131cb0ef41Sopenharmony_ci auto target_sig_it = target_sig->returns().begin(); 13141cb0ef41Sopenharmony_ci for (ValueType ret_type : sig_->returns()) { 13151cb0ef41Sopenharmony_ci if (!IsSubtypeOf(*target_sig_it++, ret_type, this->module_)) return false; 13161cb0ef41Sopenharmony_ci } 13171cb0ef41Sopenharmony_ci return true; 13181cb0ef41Sopenharmony_ci } 13191cb0ef41Sopenharmony_ci 13201cb0ef41Sopenharmony_ci bool Validate(const byte* pc, CallFunctionImmediate<validate>& imm) { 13211cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index < module_->functions.size())) { 13221cb0ef41Sopenharmony_ci DecodeError(pc, "function index #%u is out of bounds", imm.index); 13231cb0ef41Sopenharmony_ci return false; 13241cb0ef41Sopenharmony_ci } 13251cb0ef41Sopenharmony_ci imm.sig = module_->functions[imm.index].sig; 13261cb0ef41Sopenharmony_ci return true; 13271cb0ef41Sopenharmony_ci } 13281cb0ef41Sopenharmony_ci 13291cb0ef41Sopenharmony_ci bool Validate(const byte* pc, CallIndirectImmediate<validate>& imm) { 13301cb0ef41Sopenharmony_ci if (!ValidateSignature(pc, imm.sig_imm)) return false; 13311cb0ef41Sopenharmony_ci if (!ValidateTable(pc + imm.sig_imm.length, imm.table_imm)) { 13321cb0ef41Sopenharmony_ci return false; 13331cb0ef41Sopenharmony_ci } 13341cb0ef41Sopenharmony_ci ValueType table_type = module_->tables[imm.table_imm.index].type; 13351cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(table_type, kWasmFuncRef, module_))) { 13361cb0ef41Sopenharmony_ci DecodeError( 13371cb0ef41Sopenharmony_ci pc, "call_indirect: immediate table #%u is not of a function type", 13381cb0ef41Sopenharmony_ci imm.table_imm.index); 13391cb0ef41Sopenharmony_ci return false; 13401cb0ef41Sopenharmony_ci } 13411cb0ef41Sopenharmony_ci 13421cb0ef41Sopenharmony_ci // Check that the dynamic signature for this call is a subtype of the static 13431cb0ef41Sopenharmony_ci // type of the table the function is defined in. 13441cb0ef41Sopenharmony_ci ValueType immediate_type = ValueType::Ref(imm.sig_imm.index, kNonNullable); 13451cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(immediate_type, table_type, module_))) { 13461cb0ef41Sopenharmony_ci DecodeError(pc, 13471cb0ef41Sopenharmony_ci "call_indirect: Immediate signature #%u is not a subtype of " 13481cb0ef41Sopenharmony_ci "immediate table #%u", 13491cb0ef41Sopenharmony_ci imm.sig_imm.index, imm.table_imm.index); 13501cb0ef41Sopenharmony_ci return false; 13511cb0ef41Sopenharmony_ci } 13521cb0ef41Sopenharmony_ci 13531cb0ef41Sopenharmony_ci imm.sig = module_->signature(imm.sig_imm.index); 13541cb0ef41Sopenharmony_ci return true; 13551cb0ef41Sopenharmony_ci } 13561cb0ef41Sopenharmony_ci 13571cb0ef41Sopenharmony_ci bool Validate(const byte* pc, BranchDepthImmediate<validate>& imm, 13581cb0ef41Sopenharmony_ci size_t control_depth) { 13591cb0ef41Sopenharmony_ci if (!VALIDATE(imm.depth < control_depth)) { 13601cb0ef41Sopenharmony_ci DecodeError(pc, "invalid branch depth: %u", imm.depth); 13611cb0ef41Sopenharmony_ci return false; 13621cb0ef41Sopenharmony_ci } 13631cb0ef41Sopenharmony_ci return true; 13641cb0ef41Sopenharmony_ci } 13651cb0ef41Sopenharmony_ci 13661cb0ef41Sopenharmony_ci bool Validate(const byte* pc, BranchTableImmediate<validate>& imm, 13671cb0ef41Sopenharmony_ci size_t block_depth) { 13681cb0ef41Sopenharmony_ci if (!VALIDATE(imm.table_count <= kV8MaxWasmFunctionBrTableSize)) { 13691cb0ef41Sopenharmony_ci DecodeError(pc, "invalid table count (> max br_table size): %u", 13701cb0ef41Sopenharmony_ci imm.table_count); 13711cb0ef41Sopenharmony_ci return false; 13721cb0ef41Sopenharmony_ci } 13731cb0ef41Sopenharmony_ci return checkAvailable(imm.table_count); 13741cb0ef41Sopenharmony_ci } 13751cb0ef41Sopenharmony_ci 13761cb0ef41Sopenharmony_ci bool Validate(const byte* pc, WasmOpcode opcode, 13771cb0ef41Sopenharmony_ci SimdLaneImmediate<validate>& imm) { 13781cb0ef41Sopenharmony_ci uint8_t num_lanes = 0; 13791cb0ef41Sopenharmony_ci switch (opcode) { 13801cb0ef41Sopenharmony_ci case kExprF64x2ExtractLane: 13811cb0ef41Sopenharmony_ci case kExprF64x2ReplaceLane: 13821cb0ef41Sopenharmony_ci case kExprI64x2ExtractLane: 13831cb0ef41Sopenharmony_ci case kExprI64x2ReplaceLane: 13841cb0ef41Sopenharmony_ci case kExprS128Load64Lane: 13851cb0ef41Sopenharmony_ci case kExprS128Store64Lane: 13861cb0ef41Sopenharmony_ci num_lanes = 2; 13871cb0ef41Sopenharmony_ci break; 13881cb0ef41Sopenharmony_ci case kExprF32x4ExtractLane: 13891cb0ef41Sopenharmony_ci case kExprF32x4ReplaceLane: 13901cb0ef41Sopenharmony_ci case kExprI32x4ExtractLane: 13911cb0ef41Sopenharmony_ci case kExprI32x4ReplaceLane: 13921cb0ef41Sopenharmony_ci case kExprS128Load32Lane: 13931cb0ef41Sopenharmony_ci case kExprS128Store32Lane: 13941cb0ef41Sopenharmony_ci num_lanes = 4; 13951cb0ef41Sopenharmony_ci break; 13961cb0ef41Sopenharmony_ci case kExprI16x8ExtractLaneS: 13971cb0ef41Sopenharmony_ci case kExprI16x8ExtractLaneU: 13981cb0ef41Sopenharmony_ci case kExprI16x8ReplaceLane: 13991cb0ef41Sopenharmony_ci case kExprS128Load16Lane: 14001cb0ef41Sopenharmony_ci case kExprS128Store16Lane: 14011cb0ef41Sopenharmony_ci num_lanes = 8; 14021cb0ef41Sopenharmony_ci break; 14031cb0ef41Sopenharmony_ci case kExprI8x16ExtractLaneS: 14041cb0ef41Sopenharmony_ci case kExprI8x16ExtractLaneU: 14051cb0ef41Sopenharmony_ci case kExprI8x16ReplaceLane: 14061cb0ef41Sopenharmony_ci case kExprS128Load8Lane: 14071cb0ef41Sopenharmony_ci case kExprS128Store8Lane: 14081cb0ef41Sopenharmony_ci num_lanes = 16; 14091cb0ef41Sopenharmony_ci break; 14101cb0ef41Sopenharmony_ci default: 14111cb0ef41Sopenharmony_ci UNREACHABLE(); 14121cb0ef41Sopenharmony_ci break; 14131cb0ef41Sopenharmony_ci } 14141cb0ef41Sopenharmony_ci if (!VALIDATE(imm.lane >= 0 && imm.lane < num_lanes)) { 14151cb0ef41Sopenharmony_ci DecodeError(pc, "invalid lane index"); 14161cb0ef41Sopenharmony_ci return false; 14171cb0ef41Sopenharmony_ci } else { 14181cb0ef41Sopenharmony_ci return true; 14191cb0ef41Sopenharmony_ci } 14201cb0ef41Sopenharmony_ci } 14211cb0ef41Sopenharmony_ci 14221cb0ef41Sopenharmony_ci bool Validate(const byte* pc, Simd128Immediate<validate>& imm) { 14231cb0ef41Sopenharmony_ci uint8_t max_lane = 0; 14241cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < kSimd128Size; ++i) { 14251cb0ef41Sopenharmony_ci max_lane = std::max(max_lane, imm.value[i]); 14261cb0ef41Sopenharmony_ci } 14271cb0ef41Sopenharmony_ci // Shuffle indices must be in [0..31] for a 16 lane shuffle. 14281cb0ef41Sopenharmony_ci if (!VALIDATE(max_lane < 2 * kSimd128Size)) { 14291cb0ef41Sopenharmony_ci DecodeError(pc, "invalid shuffle mask"); 14301cb0ef41Sopenharmony_ci return false; 14311cb0ef41Sopenharmony_ci } 14321cb0ef41Sopenharmony_ci return true; 14331cb0ef41Sopenharmony_ci } 14341cb0ef41Sopenharmony_ci 14351cb0ef41Sopenharmony_ci bool Validate(const byte* pc, BlockTypeImmediate<validate>& imm) { 14361cb0ef41Sopenharmony_ci if (imm.type != kWasmBottom) return true; 14371cb0ef41Sopenharmony_ci if (!VALIDATE(module_->has_signature(imm.sig_index))) { 14381cb0ef41Sopenharmony_ci DecodeError(pc, "block type index %u is not a signature definition", 14391cb0ef41Sopenharmony_ci imm.sig_index); 14401cb0ef41Sopenharmony_ci return false; 14411cb0ef41Sopenharmony_ci } 14421cb0ef41Sopenharmony_ci imm.sig = module_->signature(imm.sig_index); 14431cb0ef41Sopenharmony_ci return true; 14441cb0ef41Sopenharmony_ci } 14451cb0ef41Sopenharmony_ci 14461cb0ef41Sopenharmony_ci bool Validate(const byte* pc, MemoryIndexImmediate<validate>& imm) { 14471cb0ef41Sopenharmony_ci if (!VALIDATE(this->module_->has_memory)) { 14481cb0ef41Sopenharmony_ci this->DecodeError(pc, "memory instruction with no memory"); 14491cb0ef41Sopenharmony_ci return false; 14501cb0ef41Sopenharmony_ci } 14511cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index == uint8_t{0})) { 14521cb0ef41Sopenharmony_ci DecodeError(pc, "expected memory index 0, found %u", imm.index); 14531cb0ef41Sopenharmony_ci return false; 14541cb0ef41Sopenharmony_ci } 14551cb0ef41Sopenharmony_ci return true; 14561cb0ef41Sopenharmony_ci } 14571cb0ef41Sopenharmony_ci 14581cb0ef41Sopenharmony_ci bool Validate(const byte* pc, MemoryAccessImmediate<validate>& imm) { 14591cb0ef41Sopenharmony_ci if (!VALIDATE(this->module_->has_memory)) { 14601cb0ef41Sopenharmony_ci this->DecodeError(pc, "memory instruction with no memory"); 14611cb0ef41Sopenharmony_ci return false; 14621cb0ef41Sopenharmony_ci } 14631cb0ef41Sopenharmony_ci return true; 14641cb0ef41Sopenharmony_ci } 14651cb0ef41Sopenharmony_ci 14661cb0ef41Sopenharmony_ci bool Validate(const byte* pc, MemoryInitImmediate<validate>& imm) { 14671cb0ef41Sopenharmony_ci return ValidateDataSegment(pc, imm.data_segment) && 14681cb0ef41Sopenharmony_ci Validate(pc + imm.data_segment.length, imm.memory); 14691cb0ef41Sopenharmony_ci } 14701cb0ef41Sopenharmony_ci 14711cb0ef41Sopenharmony_ci bool Validate(const byte* pc, MemoryCopyImmediate<validate>& imm) { 14721cb0ef41Sopenharmony_ci return Validate(pc, imm.memory_src) && 14731cb0ef41Sopenharmony_ci Validate(pc + imm.memory_src.length, imm.memory_dst); 14741cb0ef41Sopenharmony_ci } 14751cb0ef41Sopenharmony_ci 14761cb0ef41Sopenharmony_ci bool Validate(const byte* pc, TableInitImmediate<validate>& imm) { 14771cb0ef41Sopenharmony_ci if (!ValidateElementSegment(pc, imm.element_segment)) return false; 14781cb0ef41Sopenharmony_ci if (!ValidateTable(pc + imm.element_segment.length, imm.table)) { 14791cb0ef41Sopenharmony_ci return false; 14801cb0ef41Sopenharmony_ci } 14811cb0ef41Sopenharmony_ci ValueType elem_type = 14821cb0ef41Sopenharmony_ci module_->elem_segments[imm.element_segment.index].type; 14831cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(elem_type, module_->tables[imm.table.index].type, 14841cb0ef41Sopenharmony_ci module_))) { 14851cb0ef41Sopenharmony_ci DecodeError(pc, "table %u is not a super-type of %s", imm.table.index, 14861cb0ef41Sopenharmony_ci elem_type.name().c_str()); 14871cb0ef41Sopenharmony_ci return false; 14881cb0ef41Sopenharmony_ci } 14891cb0ef41Sopenharmony_ci return true; 14901cb0ef41Sopenharmony_ci } 14911cb0ef41Sopenharmony_ci 14921cb0ef41Sopenharmony_ci bool Validate(const byte* pc, TableCopyImmediate<validate>& imm) { 14931cb0ef41Sopenharmony_ci if (!ValidateTable(pc, imm.table_src)) return false; 14941cb0ef41Sopenharmony_ci if (!ValidateTable(pc + imm.table_src.length, imm.table_dst)) return false; 14951cb0ef41Sopenharmony_ci ValueType src_type = module_->tables[imm.table_src.index].type; 14961cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf( 14971cb0ef41Sopenharmony_ci src_type, module_->tables[imm.table_dst.index].type, module_))) { 14981cb0ef41Sopenharmony_ci DecodeError(pc, "table %u is not a super-type of %s", imm.table_dst.index, 14991cb0ef41Sopenharmony_ci src_type.name().c_str()); 15001cb0ef41Sopenharmony_ci return false; 15011cb0ef41Sopenharmony_ci } 15021cb0ef41Sopenharmony_ci return true; 15031cb0ef41Sopenharmony_ci } 15041cb0ef41Sopenharmony_ci 15051cb0ef41Sopenharmony_ci // The following Validate* functions all validate an IndexImmediate, albeit 15061cb0ef41Sopenharmony_ci // differently according to context. 15071cb0ef41Sopenharmony_ci bool ValidateTable(const byte* pc, IndexImmediate<validate>& imm) { 15081cb0ef41Sopenharmony_ci if (imm.index > 0 || imm.length > 1) { 15091cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_reftypes); 15101cb0ef41Sopenharmony_ci } 15111cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index < module_->tables.size())) { 15121cb0ef41Sopenharmony_ci DecodeError(pc, "invalid table index: %u", imm.index); 15131cb0ef41Sopenharmony_ci return false; 15141cb0ef41Sopenharmony_ci } 15151cb0ef41Sopenharmony_ci return true; 15161cb0ef41Sopenharmony_ci } 15171cb0ef41Sopenharmony_ci 15181cb0ef41Sopenharmony_ci bool ValidateElementSegment(const byte* pc, IndexImmediate<validate>& imm) { 15191cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index < module_->elem_segments.size())) { 15201cb0ef41Sopenharmony_ci DecodeError(pc, "invalid element segment index: %u", imm.index); 15211cb0ef41Sopenharmony_ci return false; 15221cb0ef41Sopenharmony_ci } 15231cb0ef41Sopenharmony_ci return true; 15241cb0ef41Sopenharmony_ci } 15251cb0ef41Sopenharmony_ci 15261cb0ef41Sopenharmony_ci bool ValidateLocal(const byte* pc, IndexImmediate<validate>& imm) { 15271cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index < num_locals())) { 15281cb0ef41Sopenharmony_ci DecodeError(pc, "invalid local index: %u", imm.index); 15291cb0ef41Sopenharmony_ci return false; 15301cb0ef41Sopenharmony_ci } 15311cb0ef41Sopenharmony_ci return true; 15321cb0ef41Sopenharmony_ci } 15331cb0ef41Sopenharmony_ci 15341cb0ef41Sopenharmony_ci bool ValidateType(const byte* pc, IndexImmediate<validate>& imm) { 15351cb0ef41Sopenharmony_ci if (!VALIDATE(module_->has_type(imm.index))) { 15361cb0ef41Sopenharmony_ci DecodeError(pc, "invalid type index: %u", imm.index); 15371cb0ef41Sopenharmony_ci return false; 15381cb0ef41Sopenharmony_ci } 15391cb0ef41Sopenharmony_ci return true; 15401cb0ef41Sopenharmony_ci } 15411cb0ef41Sopenharmony_ci 15421cb0ef41Sopenharmony_ci bool ValidateSignature(const byte* pc, IndexImmediate<validate>& imm) { 15431cb0ef41Sopenharmony_ci if (!VALIDATE(module_->has_signature(imm.index))) { 15441cb0ef41Sopenharmony_ci DecodeError(pc, "invalid signature index: %u", imm.index); 15451cb0ef41Sopenharmony_ci return false; 15461cb0ef41Sopenharmony_ci } 15471cb0ef41Sopenharmony_ci return true; 15481cb0ef41Sopenharmony_ci } 15491cb0ef41Sopenharmony_ci 15501cb0ef41Sopenharmony_ci bool ValidateFunction(const byte* pc, IndexImmediate<validate>& imm) { 15511cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index < module_->functions.size())) { 15521cb0ef41Sopenharmony_ci DecodeError(pc, "function index #%u is out of bounds", imm.index); 15531cb0ef41Sopenharmony_ci return false; 15541cb0ef41Sopenharmony_ci } 15551cb0ef41Sopenharmony_ci if (decoding_mode == kFunctionBody && 15561cb0ef41Sopenharmony_ci !VALIDATE(module_->functions[imm.index].declared)) { 15571cb0ef41Sopenharmony_ci DecodeError(pc, "undeclared reference to function #%u", imm.index); 15581cb0ef41Sopenharmony_ci return false; 15591cb0ef41Sopenharmony_ci } 15601cb0ef41Sopenharmony_ci return true; 15611cb0ef41Sopenharmony_ci } 15621cb0ef41Sopenharmony_ci 15631cb0ef41Sopenharmony_ci bool ValidateDataSegment(const byte* pc, IndexImmediate<validate>& imm) { 15641cb0ef41Sopenharmony_ci if (!VALIDATE(imm.index < module_->num_declared_data_segments)) { 15651cb0ef41Sopenharmony_ci DecodeError(pc, "invalid data segment index: %u", imm.index); 15661cb0ef41Sopenharmony_ci return false; 15671cb0ef41Sopenharmony_ci } 15681cb0ef41Sopenharmony_ci return true; 15691cb0ef41Sopenharmony_ci } 15701cb0ef41Sopenharmony_ci 15711cb0ef41Sopenharmony_ci // Returns the length of the opcode under {pc}. 15721cb0ef41Sopenharmony_ci static uint32_t OpcodeLength(WasmDecoder* decoder, const byte* pc) { 15731cb0ef41Sopenharmony_ci WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 15741cb0ef41Sopenharmony_ci // We don't have information about the module here, so we just assume that 15751cb0ef41Sopenharmony_ci // memory64 is enabled when parsing memory access immediates. This is 15761cb0ef41Sopenharmony_ci // backwards-compatible; decode errors will be detected at another time when 15771cb0ef41Sopenharmony_ci // actually decoding that opcode. 15781cb0ef41Sopenharmony_ci constexpr bool kConservativelyAssumeMemory64 = true; 15791cb0ef41Sopenharmony_ci switch (opcode) { 15801cb0ef41Sopenharmony_ci /********** Control opcodes **********/ 15811cb0ef41Sopenharmony_ci case kExprUnreachable: 15821cb0ef41Sopenharmony_ci case kExprNop: 15831cb0ef41Sopenharmony_ci case kExprNopForTestingUnsupportedInLiftoff: 15841cb0ef41Sopenharmony_ci case kExprElse: 15851cb0ef41Sopenharmony_ci case kExprEnd: 15861cb0ef41Sopenharmony_ci case kExprReturn: 15871cb0ef41Sopenharmony_ci return 1; 15881cb0ef41Sopenharmony_ci case kExprTry: 15891cb0ef41Sopenharmony_ci case kExprIf: 15901cb0ef41Sopenharmony_ci case kExprLoop: 15911cb0ef41Sopenharmony_ci case kExprBlock: { 15921cb0ef41Sopenharmony_ci BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 15931cb0ef41Sopenharmony_ci nullptr); 15941cb0ef41Sopenharmony_ci return 1 + imm.length; 15951cb0ef41Sopenharmony_ci } 15961cb0ef41Sopenharmony_ci case kExprRethrow: 15971cb0ef41Sopenharmony_ci case kExprBr: 15981cb0ef41Sopenharmony_ci case kExprBrIf: 15991cb0ef41Sopenharmony_ci case kExprBrOnNull: 16001cb0ef41Sopenharmony_ci case kExprBrOnNonNull: 16011cb0ef41Sopenharmony_ci case kExprDelegate: { 16021cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> imm(decoder, pc + 1); 16031cb0ef41Sopenharmony_ci return 1 + imm.length; 16041cb0ef41Sopenharmony_ci } 16051cb0ef41Sopenharmony_ci case kExprBrTable: { 16061cb0ef41Sopenharmony_ci BranchTableImmediate<validate> imm(decoder, pc + 1); 16071cb0ef41Sopenharmony_ci BranchTableIterator<validate> iterator(decoder, imm); 16081cb0ef41Sopenharmony_ci return 1 + iterator.length(); 16091cb0ef41Sopenharmony_ci } 16101cb0ef41Sopenharmony_ci case kExprThrow: 16111cb0ef41Sopenharmony_ci case kExprCatch: { 16121cb0ef41Sopenharmony_ci TagIndexImmediate<validate> imm(decoder, pc + 1); 16131cb0ef41Sopenharmony_ci return 1 + imm.length; 16141cb0ef41Sopenharmony_ci } 16151cb0ef41Sopenharmony_ci case kExprLet: { 16161cb0ef41Sopenharmony_ci BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 16171cb0ef41Sopenharmony_ci nullptr); 16181cb0ef41Sopenharmony_ci uint32_t locals_length; 16191cb0ef41Sopenharmony_ci int new_locals_count = decoder->DecodeLocals( 16201cb0ef41Sopenharmony_ci pc + 1 + imm.length, &locals_length, base::Optional<uint32_t>()); 16211cb0ef41Sopenharmony_ci return 1 + imm.length + ((new_locals_count >= 0) ? locals_length : 0); 16221cb0ef41Sopenharmony_ci } 16231cb0ef41Sopenharmony_ci 16241cb0ef41Sopenharmony_ci /********** Misc opcodes **********/ 16251cb0ef41Sopenharmony_ci case kExprCallFunction: 16261cb0ef41Sopenharmony_ci case kExprReturnCall: { 16271cb0ef41Sopenharmony_ci CallFunctionImmediate<validate> imm(decoder, pc + 1); 16281cb0ef41Sopenharmony_ci return 1 + imm.length; 16291cb0ef41Sopenharmony_ci } 16301cb0ef41Sopenharmony_ci case kExprCallIndirect: 16311cb0ef41Sopenharmony_ci case kExprReturnCallIndirect: { 16321cb0ef41Sopenharmony_ci CallIndirectImmediate<validate> imm(decoder, pc + 1); 16331cb0ef41Sopenharmony_ci return 1 + imm.length; 16341cb0ef41Sopenharmony_ci } 16351cb0ef41Sopenharmony_ci case kExprCallRef: 16361cb0ef41Sopenharmony_ci case kExprReturnCallRef: 16371cb0ef41Sopenharmony_ci case kExprDrop: 16381cb0ef41Sopenharmony_ci case kExprSelect: 16391cb0ef41Sopenharmony_ci case kExprCatchAll: 16401cb0ef41Sopenharmony_ci return 1; 16411cb0ef41Sopenharmony_ci case kExprSelectWithType: { 16421cb0ef41Sopenharmony_ci SelectTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 16431cb0ef41Sopenharmony_ci nullptr); 16441cb0ef41Sopenharmony_ci return 1 + imm.length; 16451cb0ef41Sopenharmony_ci } 16461cb0ef41Sopenharmony_ci 16471cb0ef41Sopenharmony_ci case kExprLocalGet: 16481cb0ef41Sopenharmony_ci case kExprLocalSet: 16491cb0ef41Sopenharmony_ci case kExprLocalTee: { 16501cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(decoder, pc + 1, "local index"); 16511cb0ef41Sopenharmony_ci return 1 + imm.length; 16521cb0ef41Sopenharmony_ci } 16531cb0ef41Sopenharmony_ci case kExprGlobalGet: 16541cb0ef41Sopenharmony_ci case kExprGlobalSet: { 16551cb0ef41Sopenharmony_ci GlobalIndexImmediate<validate> imm(decoder, pc + 1); 16561cb0ef41Sopenharmony_ci return 1 + imm.length; 16571cb0ef41Sopenharmony_ci } 16581cb0ef41Sopenharmony_ci case kExprTableGet: 16591cb0ef41Sopenharmony_ci case kExprTableSet: { 16601cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(decoder, pc + 1, "table index"); 16611cb0ef41Sopenharmony_ci return 1 + imm.length; 16621cb0ef41Sopenharmony_ci } 16631cb0ef41Sopenharmony_ci case kExprI32Const: { 16641cb0ef41Sopenharmony_ci ImmI32Immediate<validate> imm(decoder, pc + 1); 16651cb0ef41Sopenharmony_ci return 1 + imm.length; 16661cb0ef41Sopenharmony_ci } 16671cb0ef41Sopenharmony_ci case kExprI64Const: { 16681cb0ef41Sopenharmony_ci ImmI64Immediate<validate> imm(decoder, pc + 1); 16691cb0ef41Sopenharmony_ci return 1 + imm.length; 16701cb0ef41Sopenharmony_ci } 16711cb0ef41Sopenharmony_ci case kExprF32Const: 16721cb0ef41Sopenharmony_ci return 5; 16731cb0ef41Sopenharmony_ci case kExprF64Const: 16741cb0ef41Sopenharmony_ci return 9; 16751cb0ef41Sopenharmony_ci case kExprRefNull: { 16761cb0ef41Sopenharmony_ci HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 16771cb0ef41Sopenharmony_ci nullptr); 16781cb0ef41Sopenharmony_ci return 1 + imm.length; 16791cb0ef41Sopenharmony_ci } 16801cb0ef41Sopenharmony_ci case kExprRefIsNull: { 16811cb0ef41Sopenharmony_ci return 1; 16821cb0ef41Sopenharmony_ci } 16831cb0ef41Sopenharmony_ci case kExprRefFunc: { 16841cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(decoder, pc + 1, "function index"); 16851cb0ef41Sopenharmony_ci return 1 + imm.length; 16861cb0ef41Sopenharmony_ci } 16871cb0ef41Sopenharmony_ci case kExprRefAsNonNull: 16881cb0ef41Sopenharmony_ci return 1; 16891cb0ef41Sopenharmony_ci 16901cb0ef41Sopenharmony_ci#define DECLARE_OPCODE_CASE(name, ...) case kExpr##name: 16911cb0ef41Sopenharmony_ci // clang-format off 16921cb0ef41Sopenharmony_ci /********** Simple and memory opcodes **********/ 16931cb0ef41Sopenharmony_ci FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) 16941cb0ef41Sopenharmony_ci FOREACH_SIMPLE_PROTOTYPE_OPCODE(DECLARE_OPCODE_CASE) 16951cb0ef41Sopenharmony_ci return 1; 16961cb0ef41Sopenharmony_ci FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) 16971cb0ef41Sopenharmony_ci FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) { 16981cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX, 16991cb0ef41Sopenharmony_ci kConservativelyAssumeMemory64); 17001cb0ef41Sopenharmony_ci return 1 + imm.length; 17011cb0ef41Sopenharmony_ci } 17021cb0ef41Sopenharmony_ci // clang-format on 17031cb0ef41Sopenharmony_ci case kExprMemoryGrow: 17041cb0ef41Sopenharmony_ci case kExprMemorySize: { 17051cb0ef41Sopenharmony_ci MemoryIndexImmediate<validate> imm(decoder, pc + 1); 17061cb0ef41Sopenharmony_ci return 1 + imm.length; 17071cb0ef41Sopenharmony_ci } 17081cb0ef41Sopenharmony_ci 17091cb0ef41Sopenharmony_ci /********** Prefixed opcodes **********/ 17101cb0ef41Sopenharmony_ci case kNumericPrefix: { 17111cb0ef41Sopenharmony_ci uint32_t length = 0; 17121cb0ef41Sopenharmony_ci opcode = decoder->read_prefixed_opcode<validate>(pc, &length); 17131cb0ef41Sopenharmony_ci switch (opcode) { 17141cb0ef41Sopenharmony_ci case kExprI32SConvertSatF32: 17151cb0ef41Sopenharmony_ci case kExprI32UConvertSatF32: 17161cb0ef41Sopenharmony_ci case kExprI32SConvertSatF64: 17171cb0ef41Sopenharmony_ci case kExprI32UConvertSatF64: 17181cb0ef41Sopenharmony_ci case kExprI64SConvertSatF32: 17191cb0ef41Sopenharmony_ci case kExprI64UConvertSatF32: 17201cb0ef41Sopenharmony_ci case kExprI64SConvertSatF64: 17211cb0ef41Sopenharmony_ci case kExprI64UConvertSatF64: 17221cb0ef41Sopenharmony_ci return length; 17231cb0ef41Sopenharmony_ci case kExprMemoryInit: { 17241cb0ef41Sopenharmony_ci MemoryInitImmediate<validate> imm(decoder, pc + length); 17251cb0ef41Sopenharmony_ci return length + imm.length; 17261cb0ef41Sopenharmony_ci } 17271cb0ef41Sopenharmony_ci case kExprDataDrop: { 17281cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(decoder, pc + length, 17291cb0ef41Sopenharmony_ci "data segment index"); 17301cb0ef41Sopenharmony_ci return length + imm.length; 17311cb0ef41Sopenharmony_ci } 17321cb0ef41Sopenharmony_ci case kExprMemoryCopy: { 17331cb0ef41Sopenharmony_ci MemoryCopyImmediate<validate> imm(decoder, pc + length); 17341cb0ef41Sopenharmony_ci return length + imm.length; 17351cb0ef41Sopenharmony_ci } 17361cb0ef41Sopenharmony_ci case kExprMemoryFill: { 17371cb0ef41Sopenharmony_ci MemoryIndexImmediate<validate> imm(decoder, pc + length); 17381cb0ef41Sopenharmony_ci return length + imm.length; 17391cb0ef41Sopenharmony_ci } 17401cb0ef41Sopenharmony_ci case kExprTableInit: { 17411cb0ef41Sopenharmony_ci TableInitImmediate<validate> imm(decoder, pc + length); 17421cb0ef41Sopenharmony_ci return length + imm.length; 17431cb0ef41Sopenharmony_ci } 17441cb0ef41Sopenharmony_ci case kExprElemDrop: { 17451cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(decoder, pc + length, 17461cb0ef41Sopenharmony_ci "element segment index"); 17471cb0ef41Sopenharmony_ci return length + imm.length; 17481cb0ef41Sopenharmony_ci } 17491cb0ef41Sopenharmony_ci case kExprTableCopy: { 17501cb0ef41Sopenharmony_ci TableCopyImmediate<validate> imm(decoder, pc + length); 17511cb0ef41Sopenharmony_ci return length + imm.length; 17521cb0ef41Sopenharmony_ci } 17531cb0ef41Sopenharmony_ci case kExprTableGrow: 17541cb0ef41Sopenharmony_ci case kExprTableSize: 17551cb0ef41Sopenharmony_ci case kExprTableFill: { 17561cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(decoder, pc + length, "table index"); 17571cb0ef41Sopenharmony_ci return length + imm.length; 17581cb0ef41Sopenharmony_ci } 17591cb0ef41Sopenharmony_ci default: 17601cb0ef41Sopenharmony_ci if (validate) { 17611cb0ef41Sopenharmony_ci decoder->DecodeError(pc, "invalid numeric opcode"); 17621cb0ef41Sopenharmony_ci } 17631cb0ef41Sopenharmony_ci return length; 17641cb0ef41Sopenharmony_ci } 17651cb0ef41Sopenharmony_ci } 17661cb0ef41Sopenharmony_ci case kSimdPrefix: { 17671cb0ef41Sopenharmony_ci uint32_t length = 0; 17681cb0ef41Sopenharmony_ci opcode = decoder->read_prefixed_opcode<validate>(pc, &length); 17691cb0ef41Sopenharmony_ci switch (opcode) { 17701cb0ef41Sopenharmony_ci // clang-format off 17711cb0ef41Sopenharmony_ci FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) 17721cb0ef41Sopenharmony_ci return length; 17731cb0ef41Sopenharmony_ci FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) 17741cb0ef41Sopenharmony_ci return length + 1; 17751cb0ef41Sopenharmony_ci FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE) { 17761cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> imm(decoder, pc + length, 17771cb0ef41Sopenharmony_ci UINT32_MAX, 17781cb0ef41Sopenharmony_ci kConservativelyAssumeMemory64); 17791cb0ef41Sopenharmony_ci return length + imm.length; 17801cb0ef41Sopenharmony_ci } 17811cb0ef41Sopenharmony_ci FOREACH_SIMD_MEM_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { 17821cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> imm( 17831cb0ef41Sopenharmony_ci decoder, pc + length, UINT32_MAX, 17841cb0ef41Sopenharmony_ci kConservativelyAssumeMemory64); 17851cb0ef41Sopenharmony_ci // 1 more byte for lane index immediate. 17861cb0ef41Sopenharmony_ci return length + imm.length + 1; 17871cb0ef41Sopenharmony_ci } 17881cb0ef41Sopenharmony_ci // clang-format on 17891cb0ef41Sopenharmony_ci // Shuffles require a byte per lane, or 16 immediate bytes. 17901cb0ef41Sopenharmony_ci case kExprS128Const: 17911cb0ef41Sopenharmony_ci case kExprI8x16Shuffle: 17921cb0ef41Sopenharmony_ci return length + kSimd128Size; 17931cb0ef41Sopenharmony_ci default: 17941cb0ef41Sopenharmony_ci if (validate) { 17951cb0ef41Sopenharmony_ci decoder->DecodeError(pc, "invalid SIMD opcode"); 17961cb0ef41Sopenharmony_ci } 17971cb0ef41Sopenharmony_ci return length; 17981cb0ef41Sopenharmony_ci } 17991cb0ef41Sopenharmony_ci } 18001cb0ef41Sopenharmony_ci case kAtomicPrefix: { 18011cb0ef41Sopenharmony_ci uint32_t length = 0; 18021cb0ef41Sopenharmony_ci opcode = decoder->read_prefixed_opcode<validate>(pc, &length, 18031cb0ef41Sopenharmony_ci "atomic_index"); 18041cb0ef41Sopenharmony_ci switch (opcode) { 18051cb0ef41Sopenharmony_ci FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE) { 18061cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> imm(decoder, pc + length, 18071cb0ef41Sopenharmony_ci UINT32_MAX, 18081cb0ef41Sopenharmony_ci kConservativelyAssumeMemory64); 18091cb0ef41Sopenharmony_ci return length + imm.length; 18101cb0ef41Sopenharmony_ci } 18111cb0ef41Sopenharmony_ci FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { 18121cb0ef41Sopenharmony_ci return length + 1; 18131cb0ef41Sopenharmony_ci } 18141cb0ef41Sopenharmony_ci default: 18151cb0ef41Sopenharmony_ci if (validate) { 18161cb0ef41Sopenharmony_ci decoder->DecodeError(pc, "invalid Atomics opcode"); 18171cb0ef41Sopenharmony_ci } 18181cb0ef41Sopenharmony_ci return length; 18191cb0ef41Sopenharmony_ci } 18201cb0ef41Sopenharmony_ci } 18211cb0ef41Sopenharmony_ci case kGCPrefix: { 18221cb0ef41Sopenharmony_ci uint32_t length = 0; 18231cb0ef41Sopenharmony_ci opcode = 18241cb0ef41Sopenharmony_ci decoder->read_prefixed_opcode<validate>(pc, &length, "gc_index"); 18251cb0ef41Sopenharmony_ci switch (opcode) { 18261cb0ef41Sopenharmony_ci case kExprStructNew: 18271cb0ef41Sopenharmony_ci case kExprStructNewWithRtt: 18281cb0ef41Sopenharmony_ci case kExprStructNewDefault: 18291cb0ef41Sopenharmony_ci case kExprStructNewDefaultWithRtt: { 18301cb0ef41Sopenharmony_ci StructIndexImmediate<validate> imm(decoder, pc + length); 18311cb0ef41Sopenharmony_ci return length + imm.length; 18321cb0ef41Sopenharmony_ci } 18331cb0ef41Sopenharmony_ci case kExprStructGet: 18341cb0ef41Sopenharmony_ci case kExprStructGetS: 18351cb0ef41Sopenharmony_ci case kExprStructGetU: 18361cb0ef41Sopenharmony_ci case kExprStructSet: { 18371cb0ef41Sopenharmony_ci FieldImmediate<validate> imm(decoder, pc + length); 18381cb0ef41Sopenharmony_ci return length + imm.length; 18391cb0ef41Sopenharmony_ci } 18401cb0ef41Sopenharmony_ci case kExprArrayNew: 18411cb0ef41Sopenharmony_ci case kExprArrayNewWithRtt: 18421cb0ef41Sopenharmony_ci case kExprArrayNewDefault: 18431cb0ef41Sopenharmony_ci case kExprArrayNewDefaultWithRtt: 18441cb0ef41Sopenharmony_ci case kExprArrayGet: 18451cb0ef41Sopenharmony_ci case kExprArrayGetS: 18461cb0ef41Sopenharmony_ci case kExprArrayGetU: 18471cb0ef41Sopenharmony_ci case kExprArraySet: 18481cb0ef41Sopenharmony_ci case kExprArrayLen: { 18491cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> imm(decoder, pc + length); 18501cb0ef41Sopenharmony_ci return length + imm.length; 18511cb0ef41Sopenharmony_ci } 18521cb0ef41Sopenharmony_ci case kExprArrayInit: 18531cb0ef41Sopenharmony_ci case kExprArrayInitStatic: { 18541cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> array_imm(decoder, pc + length); 18551cb0ef41Sopenharmony_ci IndexImmediate<validate> length_imm( 18561cb0ef41Sopenharmony_ci decoder, pc + length + array_imm.length, "array length"); 18571cb0ef41Sopenharmony_ci return length + array_imm.length + length_imm.length; 18581cb0ef41Sopenharmony_ci } 18591cb0ef41Sopenharmony_ci case kExprArrayCopy: { 18601cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> dst_imm(decoder, pc + length); 18611cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> src_imm(decoder, 18621cb0ef41Sopenharmony_ci pc + length + dst_imm.length); 18631cb0ef41Sopenharmony_ci return length + dst_imm.length + src_imm.length; 18641cb0ef41Sopenharmony_ci } 18651cb0ef41Sopenharmony_ci case kExprArrayInitFromData: 18661cb0ef41Sopenharmony_ci case kExprArrayInitFromDataStatic: { 18671cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> array_imm(decoder, pc + length); 18681cb0ef41Sopenharmony_ci IndexImmediate<validate> data_imm( 18691cb0ef41Sopenharmony_ci decoder, pc + length + array_imm.length, "data segment index"); 18701cb0ef41Sopenharmony_ci return length + array_imm.length + data_imm.length; 18711cb0ef41Sopenharmony_ci } 18721cb0ef41Sopenharmony_ci case kExprBrOnCast: 18731cb0ef41Sopenharmony_ci case kExprBrOnCastFail: 18741cb0ef41Sopenharmony_ci case kExprBrOnData: 18751cb0ef41Sopenharmony_ci case kExprBrOnFunc: 18761cb0ef41Sopenharmony_ci case kExprBrOnI31: { 18771cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> imm(decoder, pc + length); 18781cb0ef41Sopenharmony_ci return length + imm.length; 18791cb0ef41Sopenharmony_ci } 18801cb0ef41Sopenharmony_ci case kExprRttCanon: 18811cb0ef41Sopenharmony_ci case kExprRefTestStatic: 18821cb0ef41Sopenharmony_ci case kExprRefCastStatic: 18831cb0ef41Sopenharmony_ci case kExprBrOnCastStatic: 18841cb0ef41Sopenharmony_ci case kExprBrOnCastStaticFail: { 18851cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(decoder, pc + length, "type index"); 18861cb0ef41Sopenharmony_ci return length + imm.length; 18871cb0ef41Sopenharmony_ci } 18881cb0ef41Sopenharmony_ci case kExprI31New: 18891cb0ef41Sopenharmony_ci case kExprI31GetS: 18901cb0ef41Sopenharmony_ci case kExprI31GetU: 18911cb0ef41Sopenharmony_ci case kExprRefAsData: 18921cb0ef41Sopenharmony_ci case kExprRefAsFunc: 18931cb0ef41Sopenharmony_ci case kExprRefAsI31: 18941cb0ef41Sopenharmony_ci case kExprRefIsData: 18951cb0ef41Sopenharmony_ci case kExprRefIsFunc: 18961cb0ef41Sopenharmony_ci case kExprRefIsI31: 18971cb0ef41Sopenharmony_ci case kExprRefTest: 18981cb0ef41Sopenharmony_ci case kExprRefCast: 18991cb0ef41Sopenharmony_ci return length; 19001cb0ef41Sopenharmony_ci default: 19011cb0ef41Sopenharmony_ci // This is unreachable except for malformed modules. 19021cb0ef41Sopenharmony_ci if (validate) { 19031cb0ef41Sopenharmony_ci decoder->DecodeError(pc, "invalid gc opcode"); 19041cb0ef41Sopenharmony_ci } 19051cb0ef41Sopenharmony_ci return length; 19061cb0ef41Sopenharmony_ci } 19071cb0ef41Sopenharmony_ci } 19081cb0ef41Sopenharmony_ci 19091cb0ef41Sopenharmony_ci // clang-format off 19101cb0ef41Sopenharmony_ci /********** Asmjs opcodes **********/ 19111cb0ef41Sopenharmony_ci FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE) 19121cb0ef41Sopenharmony_ci return 1; 19131cb0ef41Sopenharmony_ci 19141cb0ef41Sopenharmony_ci // Prefixed opcodes (already handled, included here for completeness of 19151cb0ef41Sopenharmony_ci // switch) 19161cb0ef41Sopenharmony_ci FOREACH_SIMD_OPCODE(DECLARE_OPCODE_CASE) 19171cb0ef41Sopenharmony_ci FOREACH_NUMERIC_OPCODE(DECLARE_OPCODE_CASE, DECLARE_OPCODE_CASE) 19181cb0ef41Sopenharmony_ci FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE) 19191cb0ef41Sopenharmony_ci FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) 19201cb0ef41Sopenharmony_ci FOREACH_GC_OPCODE(DECLARE_OPCODE_CASE) 19211cb0ef41Sopenharmony_ci UNREACHABLE(); 19221cb0ef41Sopenharmony_ci // clang-format on 19231cb0ef41Sopenharmony_ci#undef DECLARE_OPCODE_CASE 19241cb0ef41Sopenharmony_ci } 19251cb0ef41Sopenharmony_ci // Invalid modules will reach this point. 19261cb0ef41Sopenharmony_ci if (validate) { 19271cb0ef41Sopenharmony_ci decoder->DecodeError(pc, "invalid opcode"); 19281cb0ef41Sopenharmony_ci } 19291cb0ef41Sopenharmony_ci return 1; 19301cb0ef41Sopenharmony_ci } 19311cb0ef41Sopenharmony_ci 19321cb0ef41Sopenharmony_ci // TODO(clemensb): This is only used by the interpreter; move there. 19331cb0ef41Sopenharmony_ci V8_EXPORT_PRIVATE std::pair<uint32_t, uint32_t> StackEffect(const byte* pc) { 19341cb0ef41Sopenharmony_ci WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 19351cb0ef41Sopenharmony_ci // Handle "simple" opcodes with a fixed signature first. 19361cb0ef41Sopenharmony_ci const FunctionSig* sig = WasmOpcodes::Signature(opcode); 19371cb0ef41Sopenharmony_ci if (!sig) sig = WasmOpcodes::AsmjsSignature(opcode); 19381cb0ef41Sopenharmony_ci if (sig) return {sig->parameter_count(), sig->return_count()}; 19391cb0ef41Sopenharmony_ci 19401cb0ef41Sopenharmony_ci#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 19411cb0ef41Sopenharmony_ci // clang-format off 19421cb0ef41Sopenharmony_ci switch (opcode) { 19431cb0ef41Sopenharmony_ci case kExprSelect: 19441cb0ef41Sopenharmony_ci case kExprSelectWithType: 19451cb0ef41Sopenharmony_ci return {3, 1}; 19461cb0ef41Sopenharmony_ci case kExprTableSet: 19471cb0ef41Sopenharmony_ci FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) 19481cb0ef41Sopenharmony_ci return {2, 0}; 19491cb0ef41Sopenharmony_ci FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) 19501cb0ef41Sopenharmony_ci case kExprTableGet: 19511cb0ef41Sopenharmony_ci case kExprLocalTee: 19521cb0ef41Sopenharmony_ci case kExprMemoryGrow: 19531cb0ef41Sopenharmony_ci case kExprRefAsNonNull: 19541cb0ef41Sopenharmony_ci case kExprBrOnNull: 19551cb0ef41Sopenharmony_ci case kExprRefIsNull: 19561cb0ef41Sopenharmony_ci return {1, 1}; 19571cb0ef41Sopenharmony_ci case kExprLocalSet: 19581cb0ef41Sopenharmony_ci case kExprGlobalSet: 19591cb0ef41Sopenharmony_ci case kExprDrop: 19601cb0ef41Sopenharmony_ci case kExprBrIf: 19611cb0ef41Sopenharmony_ci case kExprBrTable: 19621cb0ef41Sopenharmony_ci case kExprIf: 19631cb0ef41Sopenharmony_ci case kExprBrOnNonNull: 19641cb0ef41Sopenharmony_ci return {1, 0}; 19651cb0ef41Sopenharmony_ci case kExprLocalGet: 19661cb0ef41Sopenharmony_ci case kExprGlobalGet: 19671cb0ef41Sopenharmony_ci case kExprI32Const: 19681cb0ef41Sopenharmony_ci case kExprI64Const: 19691cb0ef41Sopenharmony_ci case kExprF32Const: 19701cb0ef41Sopenharmony_ci case kExprF64Const: 19711cb0ef41Sopenharmony_ci case kExprRefNull: 19721cb0ef41Sopenharmony_ci case kExprRefFunc: 19731cb0ef41Sopenharmony_ci case kExprMemorySize: 19741cb0ef41Sopenharmony_ci return {0, 1}; 19751cb0ef41Sopenharmony_ci case kExprCallFunction: { 19761cb0ef41Sopenharmony_ci CallFunctionImmediate<validate> imm(this, pc + 1); 19771cb0ef41Sopenharmony_ci CHECK(Validate(pc + 1, imm)); 19781cb0ef41Sopenharmony_ci return {imm.sig->parameter_count(), imm.sig->return_count()}; 19791cb0ef41Sopenharmony_ci } 19801cb0ef41Sopenharmony_ci case kExprCallIndirect: { 19811cb0ef41Sopenharmony_ci CallIndirectImmediate<validate> imm(this, pc + 1); 19821cb0ef41Sopenharmony_ci CHECK(Validate(pc + 1, imm)); 19831cb0ef41Sopenharmony_ci // Indirect calls pop an additional argument for the table index. 19841cb0ef41Sopenharmony_ci return {imm.sig->parameter_count() + 1, 19851cb0ef41Sopenharmony_ci imm.sig->return_count()}; 19861cb0ef41Sopenharmony_ci } 19871cb0ef41Sopenharmony_ci case kExprThrow: { 19881cb0ef41Sopenharmony_ci TagIndexImmediate<validate> imm(this, pc + 1); 19891cb0ef41Sopenharmony_ci CHECK(Validate(pc + 1, imm)); 19901cb0ef41Sopenharmony_ci DCHECK_EQ(0, imm.tag->sig->return_count()); 19911cb0ef41Sopenharmony_ci return {imm.tag->sig->parameter_count(), 0}; 19921cb0ef41Sopenharmony_ci } 19931cb0ef41Sopenharmony_ci case kExprBr: 19941cb0ef41Sopenharmony_ci case kExprBlock: 19951cb0ef41Sopenharmony_ci case kExprLoop: 19961cb0ef41Sopenharmony_ci case kExprEnd: 19971cb0ef41Sopenharmony_ci case kExprElse: 19981cb0ef41Sopenharmony_ci case kExprTry: 19991cb0ef41Sopenharmony_ci case kExprCatch: 20001cb0ef41Sopenharmony_ci case kExprCatchAll: 20011cb0ef41Sopenharmony_ci case kExprDelegate: 20021cb0ef41Sopenharmony_ci case kExprRethrow: 20031cb0ef41Sopenharmony_ci case kExprNop: 20041cb0ef41Sopenharmony_ci case kExprNopForTestingUnsupportedInLiftoff: 20051cb0ef41Sopenharmony_ci case kExprReturn: 20061cb0ef41Sopenharmony_ci case kExprReturnCall: 20071cb0ef41Sopenharmony_ci case kExprReturnCallIndirect: 20081cb0ef41Sopenharmony_ci case kExprUnreachable: 20091cb0ef41Sopenharmony_ci return {0, 0}; 20101cb0ef41Sopenharmony_ci case kExprLet: 20111cb0ef41Sopenharmony_ci // TODO(7748): Implement 20121cb0ef41Sopenharmony_ci return {0, 0}; 20131cb0ef41Sopenharmony_ci case kNumericPrefix: 20141cb0ef41Sopenharmony_ci case kAtomicPrefix: 20151cb0ef41Sopenharmony_ci case kSimdPrefix: { 20161cb0ef41Sopenharmony_ci opcode = this->read_prefixed_opcode<validate>(pc); 20171cb0ef41Sopenharmony_ci switch (opcode) { 20181cb0ef41Sopenharmony_ci FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE) 20191cb0ef41Sopenharmony_ci return {1, 1}; 20201cb0ef41Sopenharmony_ci FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE) 20211cb0ef41Sopenharmony_ci FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE) 20221cb0ef41Sopenharmony_ci return {2, 1}; 20231cb0ef41Sopenharmony_ci FOREACH_SIMD_CONST_OPCODE(DECLARE_OPCODE_CASE) 20241cb0ef41Sopenharmony_ci return {0, 1}; 20251cb0ef41Sopenharmony_ci // Special case numeric opcodes without fixed signature. 20261cb0ef41Sopenharmony_ci case kExprMemoryInit: 20271cb0ef41Sopenharmony_ci case kExprMemoryCopy: 20281cb0ef41Sopenharmony_ci case kExprMemoryFill: 20291cb0ef41Sopenharmony_ci return {3, 0}; 20301cb0ef41Sopenharmony_ci case kExprTableGrow: 20311cb0ef41Sopenharmony_ci return {2, 1}; 20321cb0ef41Sopenharmony_ci case kExprTableFill: 20331cb0ef41Sopenharmony_ci return {3, 0}; 20341cb0ef41Sopenharmony_ci default: { 20351cb0ef41Sopenharmony_ci sig = WasmOpcodes::Signature(opcode); 20361cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(sig); 20371cb0ef41Sopenharmony_ci return {sig->parameter_count(), sig->return_count()}; 20381cb0ef41Sopenharmony_ci } 20391cb0ef41Sopenharmony_ci } 20401cb0ef41Sopenharmony_ci } 20411cb0ef41Sopenharmony_ci case kGCPrefix: { 20421cb0ef41Sopenharmony_ci opcode = this->read_prefixed_opcode<validate>(pc); 20431cb0ef41Sopenharmony_ci switch (opcode) { 20441cb0ef41Sopenharmony_ci case kExprStructNewDefaultWithRtt: 20451cb0ef41Sopenharmony_ci case kExprStructGet: 20461cb0ef41Sopenharmony_ci case kExprStructGetS: 20471cb0ef41Sopenharmony_ci case kExprStructGetU: 20481cb0ef41Sopenharmony_ci case kExprI31New: 20491cb0ef41Sopenharmony_ci case kExprI31GetS: 20501cb0ef41Sopenharmony_ci case kExprI31GetU: 20511cb0ef41Sopenharmony_ci case kExprArrayNewDefault: 20521cb0ef41Sopenharmony_ci case kExprArrayLen: 20531cb0ef41Sopenharmony_ci case kExprRefTestStatic: 20541cb0ef41Sopenharmony_ci case kExprRefCastStatic: 20551cb0ef41Sopenharmony_ci case kExprBrOnCastStatic: 20561cb0ef41Sopenharmony_ci case kExprBrOnCastStaticFail: 20571cb0ef41Sopenharmony_ci return {1, 1}; 20581cb0ef41Sopenharmony_ci case kExprStructSet: 20591cb0ef41Sopenharmony_ci return {2, 0}; 20601cb0ef41Sopenharmony_ci case kExprArrayNew: 20611cb0ef41Sopenharmony_ci case kExprArrayNewDefaultWithRtt: 20621cb0ef41Sopenharmony_ci case kExprArrayInitFromDataStatic: 20631cb0ef41Sopenharmony_ci case kExprArrayGet: 20641cb0ef41Sopenharmony_ci case kExprArrayGetS: 20651cb0ef41Sopenharmony_ci case kExprArrayGetU: 20661cb0ef41Sopenharmony_ci case kExprRefTest: 20671cb0ef41Sopenharmony_ci case kExprRefCast: 20681cb0ef41Sopenharmony_ci case kExprBrOnCast: 20691cb0ef41Sopenharmony_ci case kExprBrOnCastFail: 20701cb0ef41Sopenharmony_ci return {2, 1}; 20711cb0ef41Sopenharmony_ci case kExprArraySet: 20721cb0ef41Sopenharmony_ci return {3, 0}; 20731cb0ef41Sopenharmony_ci case kExprArrayCopy: 20741cb0ef41Sopenharmony_ci return {5, 0}; 20751cb0ef41Sopenharmony_ci case kExprRttCanon: 20761cb0ef41Sopenharmony_ci case kExprStructNewDefault: 20771cb0ef41Sopenharmony_ci return {0, 1}; 20781cb0ef41Sopenharmony_ci case kExprArrayNewWithRtt: 20791cb0ef41Sopenharmony_ci case kExprArrayInitFromData: 20801cb0ef41Sopenharmony_ci return {3, 1}; 20811cb0ef41Sopenharmony_ci case kExprStructNewWithRtt: { 20821cb0ef41Sopenharmony_ci StructIndexImmediate<validate> imm(this, pc + 2); 20831cb0ef41Sopenharmony_ci CHECK(Validate(pc + 2, imm)); 20841cb0ef41Sopenharmony_ci return {imm.struct_type->field_count() + 1, 1}; 20851cb0ef41Sopenharmony_ci } 20861cb0ef41Sopenharmony_ci case kExprStructNew: { 20871cb0ef41Sopenharmony_ci StructIndexImmediate<validate> imm(this, pc + 2); 20881cb0ef41Sopenharmony_ci CHECK(Validate(pc + 2, imm)); 20891cb0ef41Sopenharmony_ci return {imm.struct_type->field_count(), 1}; 20901cb0ef41Sopenharmony_ci } 20911cb0ef41Sopenharmony_ci case kExprArrayInit: 20921cb0ef41Sopenharmony_ci case kExprArrayInitStatic: { 20931cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> array_imm(this, pc + 2); 20941cb0ef41Sopenharmony_ci IndexImmediate<validate> length_imm(this, pc + 2 + array_imm.length, 20951cb0ef41Sopenharmony_ci "array length"); 20961cb0ef41Sopenharmony_ci return {length_imm.index + (opcode == kExprArrayInit ? 1 : 0), 1}; 20971cb0ef41Sopenharmony_ci } 20981cb0ef41Sopenharmony_ci default: 20991cb0ef41Sopenharmony_ci UNREACHABLE(); 21001cb0ef41Sopenharmony_ci } 21011cb0ef41Sopenharmony_ci } 21021cb0ef41Sopenharmony_ci default: 21031cb0ef41Sopenharmony_ci FATAL("unimplemented opcode: %x (%s)", opcode, 21041cb0ef41Sopenharmony_ci WasmOpcodes::OpcodeName(opcode)); 21051cb0ef41Sopenharmony_ci return {0, 0}; 21061cb0ef41Sopenharmony_ci } 21071cb0ef41Sopenharmony_ci#undef DECLARE_OPCODE_CASE 21081cb0ef41Sopenharmony_ci // clang-format on 21091cb0ef41Sopenharmony_ci } 21101cb0ef41Sopenharmony_ci 21111cb0ef41Sopenharmony_ci bool is_local_initialized(uint32_t local_index) { 21121cb0ef41Sopenharmony_ci return initialized_locals_[local_index]; 21131cb0ef41Sopenharmony_ci } 21141cb0ef41Sopenharmony_ci 21151cb0ef41Sopenharmony_ci void set_local_initialized(uint32_t local_index) { 21161cb0ef41Sopenharmony_ci if (!enabled_.has_nn_locals()) return; 21171cb0ef41Sopenharmony_ci // This implicitly covers defaultable locals too (which are always 21181cb0ef41Sopenharmony_ci // initialized). 21191cb0ef41Sopenharmony_ci if (is_local_initialized(local_index)) return; 21201cb0ef41Sopenharmony_ci initialized_locals_[local_index] = true; 21211cb0ef41Sopenharmony_ci locals_initializers_stack_.push_back(local_index); 21221cb0ef41Sopenharmony_ci } 21231cb0ef41Sopenharmony_ci 21241cb0ef41Sopenharmony_ci uint32_t locals_initialization_stack_depth() const { 21251cb0ef41Sopenharmony_ci return static_cast<uint32_t>(locals_initializers_stack_.size()); 21261cb0ef41Sopenharmony_ci } 21271cb0ef41Sopenharmony_ci 21281cb0ef41Sopenharmony_ci void RollbackLocalsInitialization(uint32_t previous_stack_height) { 21291cb0ef41Sopenharmony_ci if (!enabled_.has_nn_locals()) return; 21301cb0ef41Sopenharmony_ci while (locals_initializers_stack_.size() > previous_stack_height) { 21311cb0ef41Sopenharmony_ci uint32_t local_index = locals_initializers_stack_.back(); 21321cb0ef41Sopenharmony_ci locals_initializers_stack_.pop_back(); 21331cb0ef41Sopenharmony_ci initialized_locals_[local_index] = false; 21341cb0ef41Sopenharmony_ci } 21351cb0ef41Sopenharmony_ci } 21361cb0ef41Sopenharmony_ci 21371cb0ef41Sopenharmony_ci void InitializeInitializedLocalsTracking(int non_defaultable_locals) { 21381cb0ef41Sopenharmony_ci initialized_locals_.assign(num_locals_, false); 21391cb0ef41Sopenharmony_ci // Parameters count as initialized... 21401cb0ef41Sopenharmony_ci const uint32_t num_params = static_cast<uint32_t>(sig_->parameter_count()); 21411cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < num_params; i++) { 21421cb0ef41Sopenharmony_ci initialized_locals_[i] = true; 21431cb0ef41Sopenharmony_ci } 21441cb0ef41Sopenharmony_ci // ...and so do defaultable locals. 21451cb0ef41Sopenharmony_ci for (uint32_t i = num_params; i < num_locals_; i++) { 21461cb0ef41Sopenharmony_ci if (local_types_[i].is_defaultable()) initialized_locals_[i] = true; 21471cb0ef41Sopenharmony_ci } 21481cb0ef41Sopenharmony_ci if (non_defaultable_locals == 0) return; 21491cb0ef41Sopenharmony_ci locals_initializers_stack_.reserve(non_defaultable_locals); 21501cb0ef41Sopenharmony_ci } 21511cb0ef41Sopenharmony_ci 21521cb0ef41Sopenharmony_ci // The {Zone} is implicitly stored in the {ZoneAllocator} which is part of 21531cb0ef41Sopenharmony_ci // this {ZoneVector}. Hence save one field and just get it from there if 21541cb0ef41Sopenharmony_ci // needed (see {zone()} accessor below). 21551cb0ef41Sopenharmony_ci ZoneVector<ValueType> local_types_; 21561cb0ef41Sopenharmony_ci 21571cb0ef41Sopenharmony_ci // Cached value, for speed (yes, it's measurably faster to load this value 21581cb0ef41Sopenharmony_ci // than to load the start and end pointer from a vector, subtract and shift). 21591cb0ef41Sopenharmony_ci uint32_t num_locals_ = 0; 21601cb0ef41Sopenharmony_ci 21611cb0ef41Sopenharmony_ci // Indicates whether the local with the given index is currently initialized. 21621cb0ef41Sopenharmony_ci // Entries for defaultable locals are meaningless; we have a bit for each 21631cb0ef41Sopenharmony_ci // local because we expect that the effort required to densify this bit 21641cb0ef41Sopenharmony_ci // vector would more than offset the memory savings. 21651cb0ef41Sopenharmony_ci ZoneVector<bool> initialized_locals_; 21661cb0ef41Sopenharmony_ci // Keeps track of initializing assignments to non-defaultable locals that 21671cb0ef41Sopenharmony_ci // happened, so they can be discarded at the end of the current block. 21681cb0ef41Sopenharmony_ci // Contains no duplicates, so the size of this stack is bounded (and pre- 21691cb0ef41Sopenharmony_ci // allocated) to the number of non-defaultable locals in the function. 21701cb0ef41Sopenharmony_ci ZoneVector<uint32_t> locals_initializers_stack_; 21711cb0ef41Sopenharmony_ci 21721cb0ef41Sopenharmony_ci const WasmModule* module_; 21731cb0ef41Sopenharmony_ci const WasmFeatures enabled_; 21741cb0ef41Sopenharmony_ci WasmFeatures* detected_; 21751cb0ef41Sopenharmony_ci const FunctionSig* sig_; 21761cb0ef41Sopenharmony_ci}; 21771cb0ef41Sopenharmony_ci 21781cb0ef41Sopenharmony_ci// Only call this in contexts where {current_code_reachable_and_ok_} is known to 21791cb0ef41Sopenharmony_ci// hold. 21801cb0ef41Sopenharmony_ci#define CALL_INTERFACE(name, ...) \ 21811cb0ef41Sopenharmony_ci do { \ 21821cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); \ 21831cb0ef41Sopenharmony_ci DCHECK(current_code_reachable_and_ok_); \ 21841cb0ef41Sopenharmony_ci DCHECK_EQ(current_code_reachable_and_ok_, \ 21851cb0ef41Sopenharmony_ci this->ok() && control_.back().reachable()); \ 21861cb0ef41Sopenharmony_ci interface_.name(this, ##__VA_ARGS__); \ 21871cb0ef41Sopenharmony_ci } while (false) 21881cb0ef41Sopenharmony_ci#define CALL_INTERFACE_IF_OK_AND_REACHABLE(name, ...) \ 21891cb0ef41Sopenharmony_ci do { \ 21901cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); \ 21911cb0ef41Sopenharmony_ci DCHECK_EQ(current_code_reachable_and_ok_, \ 21921cb0ef41Sopenharmony_ci this->ok() && control_.back().reachable()); \ 21931cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { \ 21941cb0ef41Sopenharmony_ci interface_.name(this, ##__VA_ARGS__); \ 21951cb0ef41Sopenharmony_ci } \ 21961cb0ef41Sopenharmony_ci } while (false) 21971cb0ef41Sopenharmony_ci#define CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(name, ...) \ 21981cb0ef41Sopenharmony_ci do { \ 21991cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); \ 22001cb0ef41Sopenharmony_ci if (VALIDATE(this->ok()) && \ 22011cb0ef41Sopenharmony_ci (control_.size() == 1 || control_at(1)->reachable())) { \ 22021cb0ef41Sopenharmony_ci interface_.name(this, ##__VA_ARGS__); \ 22031cb0ef41Sopenharmony_ci } \ 22041cb0ef41Sopenharmony_ci } while (false) 22051cb0ef41Sopenharmony_ci 22061cb0ef41Sopenharmony_citemplate <Decoder::ValidateFlag validate, typename Interface, 22071cb0ef41Sopenharmony_ci DecodingMode decoding_mode = kFunctionBody> 22081cb0ef41Sopenharmony_ciclass WasmFullDecoder : public WasmDecoder<validate, decoding_mode> { 22091cb0ef41Sopenharmony_ci using Value = typename Interface::Value; 22101cb0ef41Sopenharmony_ci using Control = typename Interface::Control; 22111cb0ef41Sopenharmony_ci using ArgVector = base::Vector<Value>; 22121cb0ef41Sopenharmony_ci using ReturnVector = base::SmallVector<Value, 2>; 22131cb0ef41Sopenharmony_ci 22141cb0ef41Sopenharmony_ci // All Value types should be trivially copyable for performance. We push, pop, 22151cb0ef41Sopenharmony_ci // and store them in local variables. 22161cb0ef41Sopenharmony_ci ASSERT_TRIVIALLY_COPYABLE(Value); 22171cb0ef41Sopenharmony_ci 22181cb0ef41Sopenharmony_ci public: 22191cb0ef41Sopenharmony_ci template <typename... InterfaceArgs> 22201cb0ef41Sopenharmony_ci WasmFullDecoder(Zone* zone, const WasmModule* module, 22211cb0ef41Sopenharmony_ci const WasmFeatures& enabled, WasmFeatures* detected, 22221cb0ef41Sopenharmony_ci const FunctionBody& body, InterfaceArgs&&... interface_args) 22231cb0ef41Sopenharmony_ci : WasmDecoder<validate, decoding_mode>(zone, module, enabled, detected, 22241cb0ef41Sopenharmony_ci body.sig, body.start, body.end, 22251cb0ef41Sopenharmony_ci body.offset), 22261cb0ef41Sopenharmony_ci interface_(std::forward<InterfaceArgs>(interface_args)...), 22271cb0ef41Sopenharmony_ci control_(zone) {} 22281cb0ef41Sopenharmony_ci 22291cb0ef41Sopenharmony_ci Interface& interface() { return interface_; } 22301cb0ef41Sopenharmony_ci 22311cb0ef41Sopenharmony_ci bool Decode() { 22321cb0ef41Sopenharmony_ci DCHECK_EQ(stack_end_, stack_); 22331cb0ef41Sopenharmony_ci DCHECK(control_.empty()); 22341cb0ef41Sopenharmony_ci DCHECK_LE(this->pc_, this->end_); 22351cb0ef41Sopenharmony_ci DCHECK_EQ(this->num_locals(), 0); 22361cb0ef41Sopenharmony_ci 22371cb0ef41Sopenharmony_ci locals_offset_ = this->pc_offset(); 22381cb0ef41Sopenharmony_ci this->InitializeLocalsFromSig(); 22391cb0ef41Sopenharmony_ci uint32_t params_count = static_cast<uint32_t>(this->num_locals()); 22401cb0ef41Sopenharmony_ci uint32_t locals_length; 22411cb0ef41Sopenharmony_ci this->DecodeLocals(this->pc(), &locals_length, params_count); 22421cb0ef41Sopenharmony_ci if (this->failed()) return TraceFailed(); 22431cb0ef41Sopenharmony_ci this->consume_bytes(locals_length); 22441cb0ef41Sopenharmony_ci int non_defaultable = 0; 22451cb0ef41Sopenharmony_ci for (uint32_t index = params_count; index < this->num_locals(); index++) { 22461cb0ef41Sopenharmony_ci if (!VALIDATE(this->enabled_.has_nn_locals() || 22471cb0ef41Sopenharmony_ci this->enabled_.has_unsafe_nn_locals() || 22481cb0ef41Sopenharmony_ci this->local_type(index).is_defaultable())) { 22491cb0ef41Sopenharmony_ci this->DecodeError( 22501cb0ef41Sopenharmony_ci "Cannot define function-level local of non-defaultable type %s", 22511cb0ef41Sopenharmony_ci this->local_type(index).name().c_str()); 22521cb0ef41Sopenharmony_ci return this->TraceFailed(); 22531cb0ef41Sopenharmony_ci } 22541cb0ef41Sopenharmony_ci if (!this->local_type(index).is_defaultable()) non_defaultable++; 22551cb0ef41Sopenharmony_ci } 22561cb0ef41Sopenharmony_ci this->InitializeInitializedLocalsTracking(non_defaultable); 22571cb0ef41Sopenharmony_ci 22581cb0ef41Sopenharmony_ci // Cannot use CALL_INTERFACE_* macros because control is empty. 22591cb0ef41Sopenharmony_ci interface().StartFunction(this); 22601cb0ef41Sopenharmony_ci DecodeFunctionBody(); 22611cb0ef41Sopenharmony_ci if (this->failed()) return TraceFailed(); 22621cb0ef41Sopenharmony_ci 22631cb0ef41Sopenharmony_ci if (!VALIDATE(control_.empty())) { 22641cb0ef41Sopenharmony_ci if (control_.size() > 1) { 22651cb0ef41Sopenharmony_ci this->DecodeError(control_.back().pc(), 22661cb0ef41Sopenharmony_ci "unterminated control structure"); 22671cb0ef41Sopenharmony_ci } else { 22681cb0ef41Sopenharmony_ci this->DecodeError("function body must end with \"end\" opcode"); 22691cb0ef41Sopenharmony_ci } 22701cb0ef41Sopenharmony_ci return TraceFailed(); 22711cb0ef41Sopenharmony_ci } 22721cb0ef41Sopenharmony_ci // Cannot use CALL_INTERFACE_* macros because control is empty. 22731cb0ef41Sopenharmony_ci interface().FinishFunction(this); 22741cb0ef41Sopenharmony_ci if (this->failed()) return TraceFailed(); 22751cb0ef41Sopenharmony_ci 22761cb0ef41Sopenharmony_ci TRACE("wasm-decode ok\n\n"); 22771cb0ef41Sopenharmony_ci return true; 22781cb0ef41Sopenharmony_ci } 22791cb0ef41Sopenharmony_ci 22801cb0ef41Sopenharmony_ci bool TraceFailed() { 22811cb0ef41Sopenharmony_ci if (this->error_.offset()) { 22821cb0ef41Sopenharmony_ci TRACE("wasm-error module+%-6d func+%d: %s\n\n", this->error_.offset(), 22831cb0ef41Sopenharmony_ci this->GetBufferRelativeOffset(this->error_.offset()), 22841cb0ef41Sopenharmony_ci this->error_.message().c_str()); 22851cb0ef41Sopenharmony_ci } else { 22861cb0ef41Sopenharmony_ci TRACE("wasm-error: %s\n\n", this->error_.message().c_str()); 22871cb0ef41Sopenharmony_ci } 22881cb0ef41Sopenharmony_ci return false; 22891cb0ef41Sopenharmony_ci } 22901cb0ef41Sopenharmony_ci 22911cb0ef41Sopenharmony_ci const char* SafeOpcodeNameAt(const byte* pc) { 22921cb0ef41Sopenharmony_ci if (!pc) return "<null>"; 22931cb0ef41Sopenharmony_ci if (pc >= this->end_) return "<end>"; 22941cb0ef41Sopenharmony_ci WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 22951cb0ef41Sopenharmony_ci if (!WasmOpcodes::IsPrefixOpcode(opcode)) { 22961cb0ef41Sopenharmony_ci return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(opcode)); 22971cb0ef41Sopenharmony_ci } 22981cb0ef41Sopenharmony_ci opcode = this->template read_prefixed_opcode<Decoder::kFullValidation>(pc); 22991cb0ef41Sopenharmony_ci return WasmOpcodes::OpcodeName(opcode); 23001cb0ef41Sopenharmony_ci } 23011cb0ef41Sopenharmony_ci 23021cb0ef41Sopenharmony_ci WasmCodePosition position() const { 23031cb0ef41Sopenharmony_ci int offset = static_cast<int>(this->pc_ - this->start_); 23041cb0ef41Sopenharmony_ci DCHECK_EQ(this->pc_ - this->start_, offset); // overflows cannot happen 23051cb0ef41Sopenharmony_ci return offset; 23061cb0ef41Sopenharmony_ci } 23071cb0ef41Sopenharmony_ci 23081cb0ef41Sopenharmony_ci uint32_t control_depth() const { 23091cb0ef41Sopenharmony_ci return static_cast<uint32_t>(control_.size()); 23101cb0ef41Sopenharmony_ci } 23111cb0ef41Sopenharmony_ci 23121cb0ef41Sopenharmony_ci Control* control_at(uint32_t depth) { 23131cb0ef41Sopenharmony_ci DCHECK_GT(control_.size(), depth); 23141cb0ef41Sopenharmony_ci return &control_.back() - depth; 23151cb0ef41Sopenharmony_ci } 23161cb0ef41Sopenharmony_ci 23171cb0ef41Sopenharmony_ci uint32_t stack_size() const { 23181cb0ef41Sopenharmony_ci DCHECK_GE(stack_end_, stack_); 23191cb0ef41Sopenharmony_ci DCHECK_GE(kMaxUInt32, stack_end_ - stack_); 23201cb0ef41Sopenharmony_ci return static_cast<uint32_t>(stack_end_ - stack_); 23211cb0ef41Sopenharmony_ci } 23221cb0ef41Sopenharmony_ci 23231cb0ef41Sopenharmony_ci Value* stack_value(uint32_t depth) const { 23241cb0ef41Sopenharmony_ci DCHECK_LT(0, depth); 23251cb0ef41Sopenharmony_ci DCHECK_GE(stack_size(), depth); 23261cb0ef41Sopenharmony_ci return stack_end_ - depth; 23271cb0ef41Sopenharmony_ci } 23281cb0ef41Sopenharmony_ci 23291cb0ef41Sopenharmony_ci int32_t current_catch() const { return current_catch_; } 23301cb0ef41Sopenharmony_ci 23311cb0ef41Sopenharmony_ci uint32_t control_depth_of_current_catch() const { 23321cb0ef41Sopenharmony_ci return control_depth() - 1 - current_catch(); 23331cb0ef41Sopenharmony_ci } 23341cb0ef41Sopenharmony_ci 23351cb0ef41Sopenharmony_ci void SetSucceedingCodeDynamicallyUnreachable() { 23361cb0ef41Sopenharmony_ci Control* current = &control_.back(); 23371cb0ef41Sopenharmony_ci if (current->reachable()) { 23381cb0ef41Sopenharmony_ci current->reachability = kSpecOnlyReachable; 23391cb0ef41Sopenharmony_ci current_code_reachable_and_ok_ = false; 23401cb0ef41Sopenharmony_ci } 23411cb0ef41Sopenharmony_ci } 23421cb0ef41Sopenharmony_ci 23431cb0ef41Sopenharmony_ci uint32_t pc_relative_offset() const { 23441cb0ef41Sopenharmony_ci return this->pc_offset() - locals_offset_; 23451cb0ef41Sopenharmony_ci } 23461cb0ef41Sopenharmony_ci 23471cb0ef41Sopenharmony_ci void DecodeFunctionBody() { 23481cb0ef41Sopenharmony_ci TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n", this->start(), 23491cb0ef41Sopenharmony_ci this->end(), this->pc_offset(), 23501cb0ef41Sopenharmony_ci static_cast<int>(this->end() - this->start())); 23511cb0ef41Sopenharmony_ci 23521cb0ef41Sopenharmony_ci // Set up initial function block. 23531cb0ef41Sopenharmony_ci { 23541cb0ef41Sopenharmony_ci DCHECK(control_.empty()); 23551cb0ef41Sopenharmony_ci constexpr uint32_t kLocalsCount = 0; 23561cb0ef41Sopenharmony_ci constexpr uint32_t kStackDepth = 0; 23571cb0ef41Sopenharmony_ci constexpr uint32_t kInitStackDepth = 0; 23581cb0ef41Sopenharmony_ci control_.emplace_back(kControlBlock, kLocalsCount, kStackDepth, 23591cb0ef41Sopenharmony_ci kInitStackDepth, this->pc_, kReachable); 23601cb0ef41Sopenharmony_ci Control* c = &control_.back(); 23611cb0ef41Sopenharmony_ci if (decoding_mode == kFunctionBody) { 23621cb0ef41Sopenharmony_ci InitMerge(&c->start_merge, 0, [](uint32_t) -> Value { UNREACHABLE(); }); 23631cb0ef41Sopenharmony_ci InitMerge(&c->end_merge, 23641cb0ef41Sopenharmony_ci static_cast<uint32_t>(this->sig_->return_count()), 23651cb0ef41Sopenharmony_ci [&](uint32_t i) { 23661cb0ef41Sopenharmony_ci return Value{this->pc_, this->sig_->GetReturn(i)}; 23671cb0ef41Sopenharmony_ci }); 23681cb0ef41Sopenharmony_ci } else { 23691cb0ef41Sopenharmony_ci DCHECK_EQ(this->sig_->parameter_count(), 0); 23701cb0ef41Sopenharmony_ci DCHECK_EQ(this->sig_->return_count(), 1); 23711cb0ef41Sopenharmony_ci c->start_merge.arity = 0; 23721cb0ef41Sopenharmony_ci c->end_merge.arity = 1; 23731cb0ef41Sopenharmony_ci c->end_merge.vals.first = Value{this->pc_, this->sig_->GetReturn(0)}; 23741cb0ef41Sopenharmony_ci } 23751cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(StartFunctionBody, c); 23761cb0ef41Sopenharmony_ci } 23771cb0ef41Sopenharmony_ci 23781cb0ef41Sopenharmony_ci // Decode the function body. 23791cb0ef41Sopenharmony_ci while (this->pc_ < this->end_) { 23801cb0ef41Sopenharmony_ci // Most operations only grow the stack by at least one element (unary and 23811cb0ef41Sopenharmony_ci // binary operations, local.get, constants, ...). Thus check that there is 23821cb0ef41Sopenharmony_ci // enough space for those operations centrally, and avoid any bounds 23831cb0ef41Sopenharmony_ci // checks in those operations. 23841cb0ef41Sopenharmony_ci EnsureStackSpace(1); 23851cb0ef41Sopenharmony_ci uint8_t first_byte = *this->pc_; 23861cb0ef41Sopenharmony_ci WasmOpcode opcode = static_cast<WasmOpcode>(first_byte); 23871cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(NextInstruction, opcode); 23881cb0ef41Sopenharmony_ci int len; 23891cb0ef41Sopenharmony_ci // Allowing two of the most common decoding functions to get inlined 23901cb0ef41Sopenharmony_ci // appears to be the sweet spot. 23911cb0ef41Sopenharmony_ci // Handling _all_ opcodes via a giant switch-statement has been tried 23921cb0ef41Sopenharmony_ci // and found to be slower than calling through the handler table. 23931cb0ef41Sopenharmony_ci if (opcode == kExprLocalGet) { 23941cb0ef41Sopenharmony_ci len = WasmFullDecoder::DecodeLocalGet(this, opcode); 23951cb0ef41Sopenharmony_ci } else if (opcode == kExprI32Const) { 23961cb0ef41Sopenharmony_ci len = WasmFullDecoder::DecodeI32Const(this, opcode); 23971cb0ef41Sopenharmony_ci } else { 23981cb0ef41Sopenharmony_ci OpcodeHandler handler = GetOpcodeHandler(first_byte); 23991cb0ef41Sopenharmony_ci len = (*handler)(this, opcode); 24001cb0ef41Sopenharmony_ci } 24011cb0ef41Sopenharmony_ci this->pc_ += len; 24021cb0ef41Sopenharmony_ci } 24031cb0ef41Sopenharmony_ci 24041cb0ef41Sopenharmony_ci if (!VALIDATE(this->pc_ == this->end_)) { 24051cb0ef41Sopenharmony_ci this->DecodeError("Beyond end of code"); 24061cb0ef41Sopenharmony_ci } 24071cb0ef41Sopenharmony_ci } 24081cb0ef41Sopenharmony_ci 24091cb0ef41Sopenharmony_ci private: 24101cb0ef41Sopenharmony_ci uint32_t locals_offset_ = 0; 24111cb0ef41Sopenharmony_ci Interface interface_; 24121cb0ef41Sopenharmony_ci 24131cb0ef41Sopenharmony_ci // The value stack, stored as individual pointers for maximum performance. 24141cb0ef41Sopenharmony_ci Value* stack_ = nullptr; 24151cb0ef41Sopenharmony_ci Value* stack_end_ = nullptr; 24161cb0ef41Sopenharmony_ci Value* stack_capacity_end_ = nullptr; 24171cb0ef41Sopenharmony_ci ASSERT_TRIVIALLY_COPYABLE(Value); 24181cb0ef41Sopenharmony_ci 24191cb0ef41Sopenharmony_ci // stack of blocks, loops, and ifs. 24201cb0ef41Sopenharmony_ci ZoneVector<Control> control_; 24211cb0ef41Sopenharmony_ci 24221cb0ef41Sopenharmony_ci // Controls whether code should be generated for the current block (basically 24231cb0ef41Sopenharmony_ci // a cache for {ok() && control_.back().reachable()}). 24241cb0ef41Sopenharmony_ci bool current_code_reachable_and_ok_ = true; 24251cb0ef41Sopenharmony_ci 24261cb0ef41Sopenharmony_ci // Depth of the current try block. 24271cb0ef41Sopenharmony_ci int32_t current_catch_ = -1; 24281cb0ef41Sopenharmony_ci 24291cb0ef41Sopenharmony_ci static Value UnreachableValue(const uint8_t* pc) { 24301cb0ef41Sopenharmony_ci return Value{pc, kWasmBottom}; 24311cb0ef41Sopenharmony_ci } 24321cb0ef41Sopenharmony_ci 24331cb0ef41Sopenharmony_ci bool CheckSimdFeatureFlagOpcode(WasmOpcode opcode) { 24341cb0ef41Sopenharmony_ci if (!FLAG_experimental_wasm_relaxed_simd && 24351cb0ef41Sopenharmony_ci WasmOpcodes::IsRelaxedSimdOpcode(opcode)) { 24361cb0ef41Sopenharmony_ci this->DecodeError( 24371cb0ef41Sopenharmony_ci "simd opcode not available, enable with --experimental-relaxed-simd"); 24381cb0ef41Sopenharmony_ci return false; 24391cb0ef41Sopenharmony_ci } 24401cb0ef41Sopenharmony_ci 24411cb0ef41Sopenharmony_ci return true; 24421cb0ef41Sopenharmony_ci } 24431cb0ef41Sopenharmony_ci 24441cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> MakeMemoryAccessImmediate( 24451cb0ef41Sopenharmony_ci uint32_t pc_offset, uint32_t max_alignment) { 24461cb0ef41Sopenharmony_ci return MemoryAccessImmediate<validate>( 24471cb0ef41Sopenharmony_ci this, this->pc_ + pc_offset, max_alignment, this->module_->is_memory64); 24481cb0ef41Sopenharmony_ci } 24491cb0ef41Sopenharmony_ci 24501cb0ef41Sopenharmony_ci#ifdef DEBUG 24511cb0ef41Sopenharmony_ci class TraceLine { 24521cb0ef41Sopenharmony_ci public: 24531cb0ef41Sopenharmony_ci explicit TraceLine(WasmFullDecoder* decoder) : decoder_(decoder) { 24541cb0ef41Sopenharmony_ci WasmOpcode opcode = static_cast<WasmOpcode>(*decoder->pc()); 24551cb0ef41Sopenharmony_ci if (!WasmOpcodes::IsPrefixOpcode(opcode)) AppendOpcode(opcode); 24561cb0ef41Sopenharmony_ci } 24571cb0ef41Sopenharmony_ci 24581cb0ef41Sopenharmony_ci void AppendOpcode(WasmOpcode opcode) { 24591cb0ef41Sopenharmony_ci DCHECK(!WasmOpcodes::IsPrefixOpcode(opcode)); 24601cb0ef41Sopenharmony_ci Append(TRACE_INST_FORMAT, decoder_->startrel(decoder_->pc_), 24611cb0ef41Sopenharmony_ci WasmOpcodes::OpcodeName(opcode)); 24621cb0ef41Sopenharmony_ci } 24631cb0ef41Sopenharmony_ci 24641cb0ef41Sopenharmony_ci ~TraceLine() { 24651cb0ef41Sopenharmony_ci if (!FLAG_trace_wasm_decoder) return; 24661cb0ef41Sopenharmony_ci AppendStackState(); 24671cb0ef41Sopenharmony_ci PrintF("%.*s\n", len_, buffer_); 24681cb0ef41Sopenharmony_ci } 24691cb0ef41Sopenharmony_ci 24701cb0ef41Sopenharmony_ci // Appends a formatted string. 24711cb0ef41Sopenharmony_ci PRINTF_FORMAT(2, 3) 24721cb0ef41Sopenharmony_ci void Append(const char* format, ...) { 24731cb0ef41Sopenharmony_ci if (!FLAG_trace_wasm_decoder) return; 24741cb0ef41Sopenharmony_ci va_list va_args; 24751cb0ef41Sopenharmony_ci va_start(va_args, format); 24761cb0ef41Sopenharmony_ci size_t remaining_len = kMaxLen - len_; 24771cb0ef41Sopenharmony_ci base::Vector<char> remaining_msg_space(buffer_ + len_, remaining_len); 24781cb0ef41Sopenharmony_ci int len = base::VSNPrintF(remaining_msg_space, format, va_args); 24791cb0ef41Sopenharmony_ci va_end(va_args); 24801cb0ef41Sopenharmony_ci len_ += len < 0 ? remaining_len : len; 24811cb0ef41Sopenharmony_ci } 24821cb0ef41Sopenharmony_ci 24831cb0ef41Sopenharmony_ci private: 24841cb0ef41Sopenharmony_ci void AppendStackState() { 24851cb0ef41Sopenharmony_ci DCHECK(FLAG_trace_wasm_decoder); 24861cb0ef41Sopenharmony_ci Append(" "); 24871cb0ef41Sopenharmony_ci for (Control& c : decoder_->control_) { 24881cb0ef41Sopenharmony_ci switch (c.kind) { 24891cb0ef41Sopenharmony_ci case kControlIf: 24901cb0ef41Sopenharmony_ci Append("I"); 24911cb0ef41Sopenharmony_ci break; 24921cb0ef41Sopenharmony_ci case kControlBlock: 24931cb0ef41Sopenharmony_ci Append("B"); 24941cb0ef41Sopenharmony_ci break; 24951cb0ef41Sopenharmony_ci case kControlLoop: 24961cb0ef41Sopenharmony_ci Append("L"); 24971cb0ef41Sopenharmony_ci break; 24981cb0ef41Sopenharmony_ci case kControlTry: 24991cb0ef41Sopenharmony_ci Append("T"); 25001cb0ef41Sopenharmony_ci break; 25011cb0ef41Sopenharmony_ci case kControlIfElse: 25021cb0ef41Sopenharmony_ci Append("E"); 25031cb0ef41Sopenharmony_ci break; 25041cb0ef41Sopenharmony_ci case kControlTryCatch: 25051cb0ef41Sopenharmony_ci Append("C"); 25061cb0ef41Sopenharmony_ci break; 25071cb0ef41Sopenharmony_ci case kControlTryCatchAll: 25081cb0ef41Sopenharmony_ci Append("A"); 25091cb0ef41Sopenharmony_ci break; 25101cb0ef41Sopenharmony_ci case kControlLet: 25111cb0ef41Sopenharmony_ci Append("D"); 25121cb0ef41Sopenharmony_ci break; 25131cb0ef41Sopenharmony_ci } 25141cb0ef41Sopenharmony_ci if (c.start_merge.arity) Append("%u-", c.start_merge.arity); 25151cb0ef41Sopenharmony_ci Append("%u", c.end_merge.arity); 25161cb0ef41Sopenharmony_ci if (!c.reachable()) Append("%c", c.unreachable() ? '*' : '#'); 25171cb0ef41Sopenharmony_ci } 25181cb0ef41Sopenharmony_ci Append(" | "); 25191cb0ef41Sopenharmony_ci for (size_t i = 0; i < decoder_->stack_size(); ++i) { 25201cb0ef41Sopenharmony_ci Value& val = decoder_->stack_[i]; 25211cb0ef41Sopenharmony_ci Append(" %c", val.type.short_name()); 25221cb0ef41Sopenharmony_ci } 25231cb0ef41Sopenharmony_ci } 25241cb0ef41Sopenharmony_ci 25251cb0ef41Sopenharmony_ci static constexpr int kMaxLen = 512; 25261cb0ef41Sopenharmony_ci 25271cb0ef41Sopenharmony_ci char buffer_[kMaxLen]; 25281cb0ef41Sopenharmony_ci int len_ = 0; 25291cb0ef41Sopenharmony_ci WasmFullDecoder* const decoder_; 25301cb0ef41Sopenharmony_ci }; 25311cb0ef41Sopenharmony_ci#else 25321cb0ef41Sopenharmony_ci class TraceLine { 25331cb0ef41Sopenharmony_ci public: 25341cb0ef41Sopenharmony_ci explicit TraceLine(WasmFullDecoder*) {} 25351cb0ef41Sopenharmony_ci 25361cb0ef41Sopenharmony_ci void AppendOpcode(WasmOpcode) {} 25371cb0ef41Sopenharmony_ci 25381cb0ef41Sopenharmony_ci PRINTF_FORMAT(2, 3) 25391cb0ef41Sopenharmony_ci void Append(const char* format, ...) {} 25401cb0ef41Sopenharmony_ci }; 25411cb0ef41Sopenharmony_ci#endif 25421cb0ef41Sopenharmony_ci 25431cb0ef41Sopenharmony_ci#define DECODE(name) \ 25441cb0ef41Sopenharmony_ci static int Decode##name(WasmFullDecoder* decoder, WasmOpcode opcode) { \ 25451cb0ef41Sopenharmony_ci TraceLine trace_msg(decoder); \ 25461cb0ef41Sopenharmony_ci return decoder->Decode##name##Impl(&trace_msg, opcode); \ 25471cb0ef41Sopenharmony_ci } \ 25481cb0ef41Sopenharmony_ci V8_INLINE int Decode##name##Impl(TraceLine* trace_msg, WasmOpcode opcode) 25491cb0ef41Sopenharmony_ci 25501cb0ef41Sopenharmony_ci DECODE(Nop) { return 1; } 25511cb0ef41Sopenharmony_ci 25521cb0ef41Sopenharmony_ci DECODE(NopForTestingUnsupportedInLiftoff) { 25531cb0ef41Sopenharmony_ci if (!VALIDATE(FLAG_enable_testing_opcode_in_wasm)) { 25541cb0ef41Sopenharmony_ci this->DecodeError("Invalid opcode 0x%x", opcode); 25551cb0ef41Sopenharmony_ci return 0; 25561cb0ef41Sopenharmony_ci } 25571cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(NopForTestingUnsupportedInLiftoff); 25581cb0ef41Sopenharmony_ci return 1; 25591cb0ef41Sopenharmony_ci } 25601cb0ef41Sopenharmony_ci 25611cb0ef41Sopenharmony_ci#define BUILD_SIMPLE_OPCODE(op, _, sig) \ 25621cb0ef41Sopenharmony_ci DECODE(op) { return BuildSimpleOperator_##sig(kExpr##op); } 25631cb0ef41Sopenharmony_ci FOREACH_SIMPLE_NON_CONST_OPCODE(BUILD_SIMPLE_OPCODE) 25641cb0ef41Sopenharmony_ci#undef BUILD_SIMPLE_OPCODE 25651cb0ef41Sopenharmony_ci 25661cb0ef41Sopenharmony_ci#define BUILD_SIMPLE_OPCODE(op, _, sig) \ 25671cb0ef41Sopenharmony_ci DECODE(op) { \ 25681cb0ef41Sopenharmony_ci if (decoding_mode == kInitExpression) { \ 25691cb0ef41Sopenharmony_ci if (!VALIDATE(this->enabled_.has_extended_const())) { \ 25701cb0ef41Sopenharmony_ci NonConstError(this, kExpr##op); \ 25711cb0ef41Sopenharmony_ci return 0; \ 25721cb0ef41Sopenharmony_ci } \ 25731cb0ef41Sopenharmony_ci } \ 25741cb0ef41Sopenharmony_ci return BuildSimpleOperator_##sig(kExpr##op); \ 25751cb0ef41Sopenharmony_ci } 25761cb0ef41Sopenharmony_ci FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(BUILD_SIMPLE_OPCODE) 25771cb0ef41Sopenharmony_ci#undef BUILD_SIMPLE_OPCODE 25781cb0ef41Sopenharmony_ci 25791cb0ef41Sopenharmony_ci DECODE(Block) { 25801cb0ef41Sopenharmony_ci BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 25811cb0ef41Sopenharmony_ci this->module_); 25821cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 25831cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig); 25841cb0ef41Sopenharmony_ci Control* block = PushControl(kControlBlock, 0, args.length()); 25851cb0ef41Sopenharmony_ci SetBlockType(block, imm, args.begin()); 25861cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Block, block); 25871cb0ef41Sopenharmony_ci DropArgs(imm.sig); 25881cb0ef41Sopenharmony_ci PushMergeValues(block, &block->start_merge); 25891cb0ef41Sopenharmony_ci return 1 + imm.length; 25901cb0ef41Sopenharmony_ci } 25911cb0ef41Sopenharmony_ci 25921cb0ef41Sopenharmony_ci DECODE(Rethrow) { 25931cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(eh); 25941cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 25951cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 25961cb0ef41Sopenharmony_ci Control* c = control_at(imm.depth); 25971cb0ef41Sopenharmony_ci if (!VALIDATE(c->is_try_catchall() || c->is_try_catch())) { 25981cb0ef41Sopenharmony_ci this->error("rethrow not targeting catch or catch-all"); 25991cb0ef41Sopenharmony_ci return 0; 26001cb0ef41Sopenharmony_ci } 26011cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Rethrow, c); 26021cb0ef41Sopenharmony_ci EndControl(); 26031cb0ef41Sopenharmony_ci return 1 + imm.length; 26041cb0ef41Sopenharmony_ci } 26051cb0ef41Sopenharmony_ci 26061cb0ef41Sopenharmony_ci DECODE(Throw) { 26071cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(eh); 26081cb0ef41Sopenharmony_ci TagIndexImmediate<validate> imm(this, this->pc_ + 1); 26091cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 26101cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.tag->ToFunctionSig()); 26111cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Throw, imm, base::VectorOf(args)); 26121cb0ef41Sopenharmony_ci DropArgs(imm.tag->ToFunctionSig()); 26131cb0ef41Sopenharmony_ci EndControl(); 26141cb0ef41Sopenharmony_ci return 1 + imm.length; 26151cb0ef41Sopenharmony_ci } 26161cb0ef41Sopenharmony_ci 26171cb0ef41Sopenharmony_ci DECODE(Try) { 26181cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(eh); 26191cb0ef41Sopenharmony_ci BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 26201cb0ef41Sopenharmony_ci this->module_); 26211cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 26221cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig); 26231cb0ef41Sopenharmony_ci Control* try_block = PushControl(kControlTry, 0, args.length()); 26241cb0ef41Sopenharmony_ci SetBlockType(try_block, imm, args.begin()); 26251cb0ef41Sopenharmony_ci try_block->previous_catch = current_catch_; 26261cb0ef41Sopenharmony_ci current_catch_ = static_cast<int>(control_depth() - 1); 26271cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Try, try_block); 26281cb0ef41Sopenharmony_ci DropArgs(imm.sig); 26291cb0ef41Sopenharmony_ci PushMergeValues(try_block, &try_block->start_merge); 26301cb0ef41Sopenharmony_ci return 1 + imm.length; 26311cb0ef41Sopenharmony_ci } 26321cb0ef41Sopenharmony_ci 26331cb0ef41Sopenharmony_ci DECODE(Catch) { 26341cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(eh); 26351cb0ef41Sopenharmony_ci TagIndexImmediate<validate> imm(this, this->pc_ + 1); 26361cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 26371cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); 26381cb0ef41Sopenharmony_ci Control* c = &control_.back(); 26391cb0ef41Sopenharmony_ci if (!VALIDATE(c->is_try())) { 26401cb0ef41Sopenharmony_ci this->DecodeError("catch does not match a try"); 26411cb0ef41Sopenharmony_ci return 0; 26421cb0ef41Sopenharmony_ci } 26431cb0ef41Sopenharmony_ci if (!VALIDATE(!c->is_try_catchall())) { 26441cb0ef41Sopenharmony_ci this->DecodeError("catch after catch-all for try"); 26451cb0ef41Sopenharmony_ci return 0; 26461cb0ef41Sopenharmony_ci } 26471cb0ef41Sopenharmony_ci FallThrough(); 26481cb0ef41Sopenharmony_ci c->kind = kControlTryCatch; 26491cb0ef41Sopenharmony_ci // TODO(jkummerow): Consider moving the stack manipulation after the 26501cb0ef41Sopenharmony_ci // INTERFACE call for consistency. 26511cb0ef41Sopenharmony_ci DCHECK_LE(stack_ + c->stack_depth, stack_end_); 26521cb0ef41Sopenharmony_ci stack_end_ = stack_ + c->stack_depth; 26531cb0ef41Sopenharmony_ci c->reachability = control_at(1)->innerReachability(); 26541cb0ef41Sopenharmony_ci const WasmTagSig* sig = imm.tag->sig; 26551cb0ef41Sopenharmony_ci EnsureStackSpace(static_cast<int>(sig->parameter_count())); 26561cb0ef41Sopenharmony_ci for (ValueType type : sig->parameters()) Push(CreateValue(type)); 26571cb0ef41Sopenharmony_ci base::Vector<Value> values(stack_ + c->stack_depth, sig->parameter_count()); 26581cb0ef41Sopenharmony_ci current_catch_ = c->previous_catch; // Pop try scope. 26591cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(CatchException, imm, c, values); 26601cb0ef41Sopenharmony_ci current_code_reachable_and_ok_ = this->ok() && c->reachable(); 26611cb0ef41Sopenharmony_ci return 1 + imm.length; 26621cb0ef41Sopenharmony_ci } 26631cb0ef41Sopenharmony_ci 26641cb0ef41Sopenharmony_ci DECODE(Delegate) { 26651cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(eh); 26661cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 26671cb0ef41Sopenharmony_ci // -1 because the current try block is not included in the count. 26681cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm, control_depth() - 1)) return 0; 26691cb0ef41Sopenharmony_ci Control* c = &control_.back(); 26701cb0ef41Sopenharmony_ci if (!VALIDATE(c->is_incomplete_try())) { 26711cb0ef41Sopenharmony_ci this->DecodeError("delegate does not match a try"); 26721cb0ef41Sopenharmony_ci return 0; 26731cb0ef41Sopenharmony_ci } 26741cb0ef41Sopenharmony_ci // +1 because the current try block is not included in the count. 26751cb0ef41Sopenharmony_ci uint32_t target_depth = imm.depth + 1; 26761cb0ef41Sopenharmony_ci while (target_depth < control_depth() - 1 && 26771cb0ef41Sopenharmony_ci (!control_at(target_depth)->is_try() || 26781cb0ef41Sopenharmony_ci control_at(target_depth)->is_try_catch() || 26791cb0ef41Sopenharmony_ci control_at(target_depth)->is_try_catchall())) { 26801cb0ef41Sopenharmony_ci target_depth++; 26811cb0ef41Sopenharmony_ci } 26821cb0ef41Sopenharmony_ci FallThrough(); 26831cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(Delegate, target_depth, c); 26841cb0ef41Sopenharmony_ci current_catch_ = c->previous_catch; 26851cb0ef41Sopenharmony_ci EndControl(); 26861cb0ef41Sopenharmony_ci PopControl(); 26871cb0ef41Sopenharmony_ci return 1 + imm.length; 26881cb0ef41Sopenharmony_ci } 26891cb0ef41Sopenharmony_ci 26901cb0ef41Sopenharmony_ci DECODE(CatchAll) { 26911cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(eh); 26921cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); 26931cb0ef41Sopenharmony_ci Control* c = &control_.back(); 26941cb0ef41Sopenharmony_ci if (!VALIDATE(c->is_try())) { 26951cb0ef41Sopenharmony_ci this->DecodeError("catch-all does not match a try"); 26961cb0ef41Sopenharmony_ci return 0; 26971cb0ef41Sopenharmony_ci } 26981cb0ef41Sopenharmony_ci if (!VALIDATE(!c->is_try_catchall())) { 26991cb0ef41Sopenharmony_ci this->error("catch-all already present for try"); 27001cb0ef41Sopenharmony_ci return 0; 27011cb0ef41Sopenharmony_ci } 27021cb0ef41Sopenharmony_ci FallThrough(); 27031cb0ef41Sopenharmony_ci c->kind = kControlTryCatchAll; 27041cb0ef41Sopenharmony_ci c->reachability = control_at(1)->innerReachability(); 27051cb0ef41Sopenharmony_ci current_catch_ = c->previous_catch; // Pop try scope. 27061cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(CatchAll, c); 27071cb0ef41Sopenharmony_ci stack_end_ = stack_ + c->stack_depth; 27081cb0ef41Sopenharmony_ci current_code_reachable_and_ok_ = this->ok() && c->reachable(); 27091cb0ef41Sopenharmony_ci return 1; 27101cb0ef41Sopenharmony_ci } 27111cb0ef41Sopenharmony_ci 27121cb0ef41Sopenharmony_ci DECODE(BrOnNull) { 27131cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(typed_funcref); 27141cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 27151cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 27161cb0ef41Sopenharmony_ci Value ref_object = Peek(0); 27171cb0ef41Sopenharmony_ci Control* c = control_at(imm.depth); 27181cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<true>(c, 1))) return 0; 27191cb0ef41Sopenharmony_ci switch (ref_object.type.kind()) { 27201cb0ef41Sopenharmony_ci case kBottom: 27211cb0ef41Sopenharmony_ci // We are in a polymorphic stack. Leave the stack as it is. 27221cb0ef41Sopenharmony_ci DCHECK(!current_code_reachable_and_ok_); 27231cb0ef41Sopenharmony_ci break; 27241cb0ef41Sopenharmony_ci case kRef: 27251cb0ef41Sopenharmony_ci // For a non-nullable value, we won't take the branch, and can leave 27261cb0ef41Sopenharmony_ci // the stack as it is. 27271cb0ef41Sopenharmony_ci break; 27281cb0ef41Sopenharmony_ci case kOptRef: { 27291cb0ef41Sopenharmony_ci Value result = CreateValue( 27301cb0ef41Sopenharmony_ci ValueType::Ref(ref_object.type.heap_type(), kNonNullable)); 27311cb0ef41Sopenharmony_ci // The result of br_on_null has the same value as the argument (but a 27321cb0ef41Sopenharmony_ci // non-nullable type). 27331cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 27341cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnNull, ref_object, imm.depth, false, &result); 27351cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 27361cb0ef41Sopenharmony_ci } 27371cb0ef41Sopenharmony_ci // In unreachable code, we still have to push a value of the correct 27381cb0ef41Sopenharmony_ci // type onto the stack. 27391cb0ef41Sopenharmony_ci Drop(ref_object); 27401cb0ef41Sopenharmony_ci Push(result); 27411cb0ef41Sopenharmony_ci break; 27421cb0ef41Sopenharmony_ci } 27431cb0ef41Sopenharmony_ci default: 27441cb0ef41Sopenharmony_ci PopTypeError(0, ref_object, "object reference"); 27451cb0ef41Sopenharmony_ci return 0; 27461cb0ef41Sopenharmony_ci } 27471cb0ef41Sopenharmony_ci return 1 + imm.length; 27481cb0ef41Sopenharmony_ci } 27491cb0ef41Sopenharmony_ci 27501cb0ef41Sopenharmony_ci DECODE(BrOnNonNull) { 27511cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(gc); 27521cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 27531cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 27541cb0ef41Sopenharmony_ci Value ref_object = Peek(0, 0, kWasmAnyRef); 27551cb0ef41Sopenharmony_ci Drop(ref_object); 27561cb0ef41Sopenharmony_ci // Typechecking the branch and creating the branch merges requires the 27571cb0ef41Sopenharmony_ci // non-null value on the stack, so we push it temporarily. 27581cb0ef41Sopenharmony_ci Value result = CreateValue(ref_object.type.AsNonNull()); 27591cb0ef41Sopenharmony_ci Push(result); 27601cb0ef41Sopenharmony_ci Control* c = control_at(imm.depth); 27611cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 27621cb0ef41Sopenharmony_ci switch (ref_object.type.kind()) { 27631cb0ef41Sopenharmony_ci case kBottom: 27641cb0ef41Sopenharmony_ci // We are in unreachable code. Do nothing. 27651cb0ef41Sopenharmony_ci DCHECK(!current_code_reachable_and_ok_); 27661cb0ef41Sopenharmony_ci break; 27671cb0ef41Sopenharmony_ci case kRef: 27681cb0ef41Sopenharmony_ci // For a non-nullable value, we always take the branch. 27691cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 27701cb0ef41Sopenharmony_ci CALL_INTERFACE(Forward, ref_object, stack_value(1)); 27711cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOrRet, imm.depth, 0); 27721cb0ef41Sopenharmony_ci // We know that the following code is not reachable, but according 27731cb0ef41Sopenharmony_ci // to the spec it technically is. Set it to spec-only reachable. 27741cb0ef41Sopenharmony_ci SetSucceedingCodeDynamicallyUnreachable(); 27751cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 27761cb0ef41Sopenharmony_ci } 27771cb0ef41Sopenharmony_ci break; 27781cb0ef41Sopenharmony_ci case kOptRef: { 27791cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 27801cb0ef41Sopenharmony_ci CALL_INTERFACE(Forward, ref_object, stack_value(1)); 27811cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnNonNull, ref_object, imm.depth); 27821cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 27831cb0ef41Sopenharmony_ci } 27841cb0ef41Sopenharmony_ci break; 27851cb0ef41Sopenharmony_ci } 27861cb0ef41Sopenharmony_ci default: 27871cb0ef41Sopenharmony_ci PopTypeError(0, ref_object, "object reference"); 27881cb0ef41Sopenharmony_ci return 0; 27891cb0ef41Sopenharmony_ci } 27901cb0ef41Sopenharmony_ci // If we stay in the branch, {ref_object} is null. Drop it from the stack. 27911cb0ef41Sopenharmony_ci Drop(result); 27921cb0ef41Sopenharmony_ci return 1 + imm.length; 27931cb0ef41Sopenharmony_ci } 27941cb0ef41Sopenharmony_ci 27951cb0ef41Sopenharmony_ci DECODE(Let) { 27961cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(typed_funcref); 27971cb0ef41Sopenharmony_ci BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 27981cb0ef41Sopenharmony_ci this->module_); 27991cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 28001cb0ef41Sopenharmony_ci // Temporarily add the let-defined values to the beginning of the function 28011cb0ef41Sopenharmony_ci // locals. 28021cb0ef41Sopenharmony_ci uint32_t locals_length; 28031cb0ef41Sopenharmony_ci int new_locals_count = 28041cb0ef41Sopenharmony_ci this->DecodeLocals(this->pc() + 1 + imm.length, &locals_length, 0); 28051cb0ef41Sopenharmony_ci if (new_locals_count < 0) { 28061cb0ef41Sopenharmony_ci return 0; 28071cb0ef41Sopenharmony_ci } 28081cb0ef41Sopenharmony_ci ArgVector let_local_values = 28091cb0ef41Sopenharmony_ci PeekArgs(base::VectorOf(this->local_types_.data(), new_locals_count)); 28101cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig, new_locals_count); 28111cb0ef41Sopenharmony_ci Control* let_block = PushControl(kControlLet, new_locals_count, 28121cb0ef41Sopenharmony_ci let_local_values.length() + args.length()); 28131cb0ef41Sopenharmony_ci SetBlockType(let_block, imm, args.begin()); 28141cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Block, let_block); 28151cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(AllocateLocals, 28161cb0ef41Sopenharmony_ci base::VectorOf(let_local_values)); 28171cb0ef41Sopenharmony_ci Drop(new_locals_count); // Drop {let_local_values}. 28181cb0ef41Sopenharmony_ci DropArgs(imm.sig); // Drop {args}. 28191cb0ef41Sopenharmony_ci PushMergeValues(let_block, &let_block->start_merge); 28201cb0ef41Sopenharmony_ci return 1 + imm.length + locals_length; 28211cb0ef41Sopenharmony_ci } 28221cb0ef41Sopenharmony_ci 28231cb0ef41Sopenharmony_ci DECODE(Loop) { 28241cb0ef41Sopenharmony_ci BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 28251cb0ef41Sopenharmony_ci this->module_); 28261cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 28271cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig); 28281cb0ef41Sopenharmony_ci Control* block = PushControl(kControlLoop, 0, args.length()); 28291cb0ef41Sopenharmony_ci SetBlockType(&control_.back(), imm, args.begin()); 28301cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Loop, block); 28311cb0ef41Sopenharmony_ci DropArgs(imm.sig); 28321cb0ef41Sopenharmony_ci PushMergeValues(block, &block->start_merge); 28331cb0ef41Sopenharmony_ci return 1 + imm.length; 28341cb0ef41Sopenharmony_ci } 28351cb0ef41Sopenharmony_ci 28361cb0ef41Sopenharmony_ci DECODE(If) { 28371cb0ef41Sopenharmony_ci BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 28381cb0ef41Sopenharmony_ci this->module_); 28391cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 28401cb0ef41Sopenharmony_ci Value cond = Peek(0, 0, kWasmI32); 28411cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig, 1); 28421cb0ef41Sopenharmony_ci if (!VALIDATE(this->ok())) return 0; 28431cb0ef41Sopenharmony_ci Control* if_block = PushControl(kControlIf, 0, 1 + args.length()); 28441cb0ef41Sopenharmony_ci SetBlockType(if_block, imm, args.begin()); 28451cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(If, cond, if_block); 28461cb0ef41Sopenharmony_ci Drop(cond); 28471cb0ef41Sopenharmony_ci DropArgs(imm.sig); // Drop {args}. 28481cb0ef41Sopenharmony_ci PushMergeValues(if_block, &if_block->start_merge); 28491cb0ef41Sopenharmony_ci return 1 + imm.length; 28501cb0ef41Sopenharmony_ci } 28511cb0ef41Sopenharmony_ci 28521cb0ef41Sopenharmony_ci DECODE(Else) { 28531cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); 28541cb0ef41Sopenharmony_ci Control* c = &control_.back(); 28551cb0ef41Sopenharmony_ci if (!VALIDATE(c->is_if())) { 28561cb0ef41Sopenharmony_ci this->DecodeError("else does not match an if"); 28571cb0ef41Sopenharmony_ci return 0; 28581cb0ef41Sopenharmony_ci } 28591cb0ef41Sopenharmony_ci if (!VALIDATE(c->is_onearmed_if())) { 28601cb0ef41Sopenharmony_ci this->DecodeError("else already present for if"); 28611cb0ef41Sopenharmony_ci return 0; 28621cb0ef41Sopenharmony_ci } 28631cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckFallThru())) return 0; 28641cb0ef41Sopenharmony_ci c->kind = kControlIfElse; 28651cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(Else, c); 28661cb0ef41Sopenharmony_ci if (c->reachable()) c->end_merge.reached = true; 28671cb0ef41Sopenharmony_ci PushMergeValues(c, &c->start_merge); 28681cb0ef41Sopenharmony_ci c->reachability = control_at(1)->innerReachability(); 28691cb0ef41Sopenharmony_ci current_code_reachable_and_ok_ = this->ok() && c->reachable(); 28701cb0ef41Sopenharmony_ci return 1; 28711cb0ef41Sopenharmony_ci } 28721cb0ef41Sopenharmony_ci 28731cb0ef41Sopenharmony_ci DECODE(End) { 28741cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); 28751cb0ef41Sopenharmony_ci if (decoding_mode == kFunctionBody) { 28761cb0ef41Sopenharmony_ci Control* c = &control_.back(); 28771cb0ef41Sopenharmony_ci if (c->is_incomplete_try()) { 28781cb0ef41Sopenharmony_ci // Catch-less try, fall through to the implicit catch-all. 28791cb0ef41Sopenharmony_ci c->kind = kControlTryCatch; 28801cb0ef41Sopenharmony_ci current_catch_ = c->previous_catch; // Pop try scope. 28811cb0ef41Sopenharmony_ci } 28821cb0ef41Sopenharmony_ci if (c->is_try_catch()) { 28831cb0ef41Sopenharmony_ci // Emulate catch-all + re-throw. 28841cb0ef41Sopenharmony_ci FallThrough(); 28851cb0ef41Sopenharmony_ci c->reachability = control_at(1)->innerReachability(); 28861cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(CatchAll, c); 28871cb0ef41Sopenharmony_ci current_code_reachable_and_ok_ = 28881cb0ef41Sopenharmony_ci this->ok() && control_.back().reachable(); 28891cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Rethrow, c); 28901cb0ef41Sopenharmony_ci EndControl(); 28911cb0ef41Sopenharmony_ci PopControl(); 28921cb0ef41Sopenharmony_ci return 1; 28931cb0ef41Sopenharmony_ci } 28941cb0ef41Sopenharmony_ci if (c->is_onearmed_if()) { 28951cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckOneArmedIf(c))) return 0; 28961cb0ef41Sopenharmony_ci } 28971cb0ef41Sopenharmony_ci 28981cb0ef41Sopenharmony_ci if (c->is_let()) { 28991cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(DeallocateLocals, c->locals_count); 29001cb0ef41Sopenharmony_ci this->local_types_.erase(this->local_types_.begin(), 29011cb0ef41Sopenharmony_ci this->local_types_.begin() + c->locals_count); 29021cb0ef41Sopenharmony_ci this->num_locals_ -= c->locals_count; 29031cb0ef41Sopenharmony_ci } 29041cb0ef41Sopenharmony_ci } 29051cb0ef41Sopenharmony_ci 29061cb0ef41Sopenharmony_ci if (control_.size() == 1) { 29071cb0ef41Sopenharmony_ci // We need to call this first because the interface might set 29081cb0ef41Sopenharmony_ci // {this->end_}, making the next check pass. 29091cb0ef41Sopenharmony_ci DoReturn<kStrictCounting, decoding_mode == kFunctionBody 29101cb0ef41Sopenharmony_ci ? kFallthroughMerge 29111cb0ef41Sopenharmony_ci : kInitExprMerge>(); 29121cb0ef41Sopenharmony_ci // If at the last (implicit) control, check we are at end. 29131cb0ef41Sopenharmony_ci if (!VALIDATE(this->pc_ + 1 == this->end_)) { 29141cb0ef41Sopenharmony_ci this->DecodeError(this->pc_ + 1, "trailing code after function end"); 29151cb0ef41Sopenharmony_ci return 0; 29161cb0ef41Sopenharmony_ci } 29171cb0ef41Sopenharmony_ci // The result of the block is the return value. 29181cb0ef41Sopenharmony_ci trace_msg->Append("\n" TRACE_INST_FORMAT, startrel(this->pc_), 29191cb0ef41Sopenharmony_ci "(implicit) return"); 29201cb0ef41Sopenharmony_ci control_.clear(); 29211cb0ef41Sopenharmony_ci return 1; 29221cb0ef41Sopenharmony_ci } 29231cb0ef41Sopenharmony_ci 29241cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckFallThru())) return 0; 29251cb0ef41Sopenharmony_ci PopControl(); 29261cb0ef41Sopenharmony_ci return 1; 29271cb0ef41Sopenharmony_ci } 29281cb0ef41Sopenharmony_ci 29291cb0ef41Sopenharmony_ci DECODE(Select) { 29301cb0ef41Sopenharmony_ci Value cond = Peek(0, 2, kWasmI32); 29311cb0ef41Sopenharmony_ci Value fval = Peek(1); 29321cb0ef41Sopenharmony_ci Value tval = Peek(2, 0, fval.type); 29331cb0ef41Sopenharmony_ci ValueType type = tval.type == kWasmBottom ? fval.type : tval.type; 29341cb0ef41Sopenharmony_ci if (!VALIDATE(!type.is_reference())) { 29351cb0ef41Sopenharmony_ci this->DecodeError( 29361cb0ef41Sopenharmony_ci "select without type is only valid for value type inputs"); 29371cb0ef41Sopenharmony_ci return 0; 29381cb0ef41Sopenharmony_ci } 29391cb0ef41Sopenharmony_ci Value result = CreateValue(type); 29401cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Select, cond, fval, tval, &result); 29411cb0ef41Sopenharmony_ci Drop(3); 29421cb0ef41Sopenharmony_ci Push(result); 29431cb0ef41Sopenharmony_ci return 1; 29441cb0ef41Sopenharmony_ci } 29451cb0ef41Sopenharmony_ci 29461cb0ef41Sopenharmony_ci DECODE(SelectWithType) { 29471cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_reftypes); 29481cb0ef41Sopenharmony_ci SelectTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 29491cb0ef41Sopenharmony_ci this->module_); 29501cb0ef41Sopenharmony_ci if (this->failed()) return 0; 29511cb0ef41Sopenharmony_ci Value cond = Peek(0, 2, kWasmI32); 29521cb0ef41Sopenharmony_ci Value fval = Peek(1, 1, imm.type); 29531cb0ef41Sopenharmony_ci Value tval = Peek(2, 0, imm.type); 29541cb0ef41Sopenharmony_ci Value result = CreateValue(imm.type); 29551cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Select, cond, fval, tval, &result); 29561cb0ef41Sopenharmony_ci Drop(3); 29571cb0ef41Sopenharmony_ci Push(result); 29581cb0ef41Sopenharmony_ci return 1 + imm.length; 29591cb0ef41Sopenharmony_ci } 29601cb0ef41Sopenharmony_ci 29611cb0ef41Sopenharmony_ci DECODE(Br) { 29621cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 29631cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 29641cb0ef41Sopenharmony_ci Control* c = control_at(imm.depth); 29651cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<false>(c, 0))) return 0; 29661cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 29671cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOrRet, imm.depth, 0); 29681cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 29691cb0ef41Sopenharmony_ci } 29701cb0ef41Sopenharmony_ci EndControl(); 29711cb0ef41Sopenharmony_ci return 1 + imm.length; 29721cb0ef41Sopenharmony_ci } 29731cb0ef41Sopenharmony_ci 29741cb0ef41Sopenharmony_ci DECODE(BrIf) { 29751cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 29761cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 29771cb0ef41Sopenharmony_ci Value cond = Peek(0, 0, kWasmI32); 29781cb0ef41Sopenharmony_ci Control* c = control_at(imm.depth); 29791cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<true>(c, 1))) return 0; 29801cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 29811cb0ef41Sopenharmony_ci CALL_INTERFACE(BrIf, cond, imm.depth); 29821cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 29831cb0ef41Sopenharmony_ci } 29841cb0ef41Sopenharmony_ci Drop(cond); 29851cb0ef41Sopenharmony_ci return 1 + imm.length; 29861cb0ef41Sopenharmony_ci } 29871cb0ef41Sopenharmony_ci 29881cb0ef41Sopenharmony_ci DECODE(BrTable) { 29891cb0ef41Sopenharmony_ci BranchTableImmediate<validate> imm(this, this->pc_ + 1); 29901cb0ef41Sopenharmony_ci BranchTableIterator<validate> iterator(this, imm); 29911cb0ef41Sopenharmony_ci Value key = Peek(0, 0, kWasmI32); 29921cb0ef41Sopenharmony_ci if (this->failed()) return 0; 29931cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 29941cb0ef41Sopenharmony_ci 29951cb0ef41Sopenharmony_ci // Cache the branch targets during the iteration, so that we can set 29961cb0ef41Sopenharmony_ci // all branch targets as reachable after the {CALL_INTERFACE} call. 29971cb0ef41Sopenharmony_ci std::vector<bool> br_targets(control_.size()); 29981cb0ef41Sopenharmony_ci 29991cb0ef41Sopenharmony_ci uint32_t arity = 0; 30001cb0ef41Sopenharmony_ci 30011cb0ef41Sopenharmony_ci while (iterator.has_next()) { 30021cb0ef41Sopenharmony_ci const uint32_t index = iterator.cur_index(); 30031cb0ef41Sopenharmony_ci const byte* pos = iterator.pc(); 30041cb0ef41Sopenharmony_ci const uint32_t target = iterator.next(); 30051cb0ef41Sopenharmony_ci if (!VALIDATE(target < control_depth())) { 30061cb0ef41Sopenharmony_ci this->DecodeError(pos, "invalid branch depth: %u", target); 30071cb0ef41Sopenharmony_ci return 0; 30081cb0ef41Sopenharmony_ci } 30091cb0ef41Sopenharmony_ci // Avoid redundant branch target checks. 30101cb0ef41Sopenharmony_ci if (br_targets[target]) continue; 30111cb0ef41Sopenharmony_ci br_targets[target] = true; 30121cb0ef41Sopenharmony_ci 30131cb0ef41Sopenharmony_ci if (validate) { 30141cb0ef41Sopenharmony_ci if (index == 0) { 30151cb0ef41Sopenharmony_ci arity = control_at(target)->br_merge()->arity; 30161cb0ef41Sopenharmony_ci } else if (!VALIDATE(control_at(target)->br_merge()->arity == arity)) { 30171cb0ef41Sopenharmony_ci this->DecodeError( 30181cb0ef41Sopenharmony_ci pos, "br_table: label arity inconsistent with previous arity %d", 30191cb0ef41Sopenharmony_ci arity); 30201cb0ef41Sopenharmony_ci return 0; 30211cb0ef41Sopenharmony_ci } 30221cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<false>(control_at(target), 1))) return 0; 30231cb0ef41Sopenharmony_ci } 30241cb0ef41Sopenharmony_ci } 30251cb0ef41Sopenharmony_ci 30261cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 30271cb0ef41Sopenharmony_ci CALL_INTERFACE(BrTable, imm, key); 30281cb0ef41Sopenharmony_ci 30291cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < control_depth(); ++i) { 30301cb0ef41Sopenharmony_ci control_at(i)->br_merge()->reached |= br_targets[i]; 30311cb0ef41Sopenharmony_ci } 30321cb0ef41Sopenharmony_ci } 30331cb0ef41Sopenharmony_ci Drop(key); 30341cb0ef41Sopenharmony_ci EndControl(); 30351cb0ef41Sopenharmony_ci return 1 + iterator.length(); 30361cb0ef41Sopenharmony_ci } 30371cb0ef41Sopenharmony_ci 30381cb0ef41Sopenharmony_ci DECODE(Return) { 30391cb0ef41Sopenharmony_ci return DoReturn<kNonStrictCounting, kReturnMerge>() ? 1 : 0; 30401cb0ef41Sopenharmony_ci } 30411cb0ef41Sopenharmony_ci 30421cb0ef41Sopenharmony_ci DECODE(Unreachable) { 30431cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Trap, TrapReason::kTrapUnreachable); 30441cb0ef41Sopenharmony_ci EndControl(); 30451cb0ef41Sopenharmony_ci return 1; 30461cb0ef41Sopenharmony_ci } 30471cb0ef41Sopenharmony_ci 30481cb0ef41Sopenharmony_ci DECODE(I32Const) { 30491cb0ef41Sopenharmony_ci ImmI32Immediate<validate> imm(this, this->pc_ + 1); 30501cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmI32); 30511cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(I32Const, &value, imm.value); 30521cb0ef41Sopenharmony_ci Push(value); 30531cb0ef41Sopenharmony_ci return 1 + imm.length; 30541cb0ef41Sopenharmony_ci } 30551cb0ef41Sopenharmony_ci 30561cb0ef41Sopenharmony_ci DECODE(I64Const) { 30571cb0ef41Sopenharmony_ci ImmI64Immediate<validate> imm(this, this->pc_ + 1); 30581cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmI64); 30591cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(I64Const, &value, imm.value); 30601cb0ef41Sopenharmony_ci Push(value); 30611cb0ef41Sopenharmony_ci return 1 + imm.length; 30621cb0ef41Sopenharmony_ci } 30631cb0ef41Sopenharmony_ci 30641cb0ef41Sopenharmony_ci DECODE(F32Const) { 30651cb0ef41Sopenharmony_ci ImmF32Immediate<validate> imm(this, this->pc_ + 1); 30661cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmF32); 30671cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(F32Const, &value, imm.value); 30681cb0ef41Sopenharmony_ci Push(value); 30691cb0ef41Sopenharmony_ci return 1 + imm.length; 30701cb0ef41Sopenharmony_ci } 30711cb0ef41Sopenharmony_ci 30721cb0ef41Sopenharmony_ci DECODE(F64Const) { 30731cb0ef41Sopenharmony_ci ImmF64Immediate<validate> imm(this, this->pc_ + 1); 30741cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmF64); 30751cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(F64Const, &value, imm.value); 30761cb0ef41Sopenharmony_ci Push(value); 30771cb0ef41Sopenharmony_ci return 1 + imm.length; 30781cb0ef41Sopenharmony_ci } 30791cb0ef41Sopenharmony_ci 30801cb0ef41Sopenharmony_ci DECODE(RefNull) { 30811cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_reftypes); 30821cb0ef41Sopenharmony_ci HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 30831cb0ef41Sopenharmony_ci this->module_); 30841cb0ef41Sopenharmony_ci if (!VALIDATE(this->ok())) return 0; 30851cb0ef41Sopenharmony_ci ValueType type = ValueType::Ref(imm.type, kNullable); 30861cb0ef41Sopenharmony_ci Value value = CreateValue(type); 30871cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RefNull, type, &value); 30881cb0ef41Sopenharmony_ci Push(value); 30891cb0ef41Sopenharmony_ci return 1 + imm.length; 30901cb0ef41Sopenharmony_ci } 30911cb0ef41Sopenharmony_ci 30921cb0ef41Sopenharmony_ci DECODE(RefIsNull) { 30931cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_reftypes); 30941cb0ef41Sopenharmony_ci Value value = Peek(0); 30951cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmI32); 30961cb0ef41Sopenharmony_ci switch (value.type.kind()) { 30971cb0ef41Sopenharmony_ci case kOptRef: 30981cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(UnOp, kExprRefIsNull, value, 30991cb0ef41Sopenharmony_ci &result); 31001cb0ef41Sopenharmony_ci Drop(value); 31011cb0ef41Sopenharmony_ci Push(result); 31021cb0ef41Sopenharmony_ci return 1; 31031cb0ef41Sopenharmony_ci case kBottom: 31041cb0ef41Sopenharmony_ci // We are in unreachable code, the return value does not matter. 31051cb0ef41Sopenharmony_ci case kRef: 31061cb0ef41Sopenharmony_ci // For non-nullable references, the result is always false. 31071cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Drop); 31081cb0ef41Sopenharmony_ci Drop(value); 31091cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(I32Const, &result, 0); 31101cb0ef41Sopenharmony_ci Push(result); 31111cb0ef41Sopenharmony_ci return 1; 31121cb0ef41Sopenharmony_ci default: 31131cb0ef41Sopenharmony_ci if (validate) { 31141cb0ef41Sopenharmony_ci PopTypeError(0, value, "reference type"); 31151cb0ef41Sopenharmony_ci return 0; 31161cb0ef41Sopenharmony_ci } 31171cb0ef41Sopenharmony_ci UNREACHABLE(); 31181cb0ef41Sopenharmony_ci } 31191cb0ef41Sopenharmony_ci } 31201cb0ef41Sopenharmony_ci 31211cb0ef41Sopenharmony_ci DECODE(RefFunc) { 31221cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_reftypes); 31231cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + 1, "function index"); 31241cb0ef41Sopenharmony_ci if (!this->ValidateFunction(this->pc_ + 1, imm)) return 0; 31251cb0ef41Sopenharmony_ci HeapType heap_type(this->enabled_.has_typed_funcref() 31261cb0ef41Sopenharmony_ci ? this->module_->functions[imm.index].sig_index 31271cb0ef41Sopenharmony_ci : HeapType::kFunc); 31281cb0ef41Sopenharmony_ci Value value = CreateValue(ValueType::Ref(heap_type, kNonNullable)); 31291cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RefFunc, imm.index, &value); 31301cb0ef41Sopenharmony_ci Push(value); 31311cb0ef41Sopenharmony_ci return 1 + imm.length; 31321cb0ef41Sopenharmony_ci } 31331cb0ef41Sopenharmony_ci 31341cb0ef41Sopenharmony_ci DECODE(RefAsNonNull) { 31351cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(typed_funcref); 31361cb0ef41Sopenharmony_ci Value value = Peek(0); 31371cb0ef41Sopenharmony_ci switch (value.type.kind()) { 31381cb0ef41Sopenharmony_ci case kBottom: 31391cb0ef41Sopenharmony_ci // We are in unreachable code. Forward the bottom value. 31401cb0ef41Sopenharmony_ci case kRef: 31411cb0ef41Sopenharmony_ci // A non-nullable value can remain as-is. 31421cb0ef41Sopenharmony_ci return 1; 31431cb0ef41Sopenharmony_ci case kOptRef: { 31441cb0ef41Sopenharmony_ci Value result = 31451cb0ef41Sopenharmony_ci CreateValue(ValueType::Ref(value.type.heap_type(), kNonNullable)); 31461cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RefAsNonNull, value, &result); 31471cb0ef41Sopenharmony_ci Drop(value); 31481cb0ef41Sopenharmony_ci Push(result); 31491cb0ef41Sopenharmony_ci return 1; 31501cb0ef41Sopenharmony_ci } 31511cb0ef41Sopenharmony_ci default: 31521cb0ef41Sopenharmony_ci if (validate) { 31531cb0ef41Sopenharmony_ci PopTypeError(0, value, "reference type"); 31541cb0ef41Sopenharmony_ci } 31551cb0ef41Sopenharmony_ci return 0; 31561cb0ef41Sopenharmony_ci } 31571cb0ef41Sopenharmony_ci } 31581cb0ef41Sopenharmony_ci 31591cb0ef41Sopenharmony_ci V8_INLINE DECODE(LocalGet) { 31601cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + 1, "local index"); 31611cb0ef41Sopenharmony_ci if (!this->ValidateLocal(this->pc_ + 1, imm)) return 0; 31621cb0ef41Sopenharmony_ci if (!VALIDATE(!this->enabled_.has_nn_locals() || 31631cb0ef41Sopenharmony_ci this->is_local_initialized(imm.index))) { 31641cb0ef41Sopenharmony_ci this->DecodeError(this->pc_, "uninitialized non-defaultable local: %u", 31651cb0ef41Sopenharmony_ci imm.index); 31661cb0ef41Sopenharmony_ci return 0; 31671cb0ef41Sopenharmony_ci } 31681cb0ef41Sopenharmony_ci Value value = CreateValue(this->local_type(imm.index)); 31691cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(LocalGet, &value, imm); 31701cb0ef41Sopenharmony_ci Push(value); 31711cb0ef41Sopenharmony_ci return 1 + imm.length; 31721cb0ef41Sopenharmony_ci } 31731cb0ef41Sopenharmony_ci 31741cb0ef41Sopenharmony_ci DECODE(LocalSet) { 31751cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + 1, "local index"); 31761cb0ef41Sopenharmony_ci if (!this->ValidateLocal(this->pc_ + 1, imm)) return 0; 31771cb0ef41Sopenharmony_ci Value value = Peek(0, 0, this->local_type(imm.index)); 31781cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(LocalSet, value, imm); 31791cb0ef41Sopenharmony_ci Drop(value); 31801cb0ef41Sopenharmony_ci this->set_local_initialized(imm.index); 31811cb0ef41Sopenharmony_ci return 1 + imm.length; 31821cb0ef41Sopenharmony_ci } 31831cb0ef41Sopenharmony_ci 31841cb0ef41Sopenharmony_ci DECODE(LocalTee) { 31851cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + 1, "local index"); 31861cb0ef41Sopenharmony_ci if (!this->ValidateLocal(this->pc_ + 1, imm)) return 0; 31871cb0ef41Sopenharmony_ci ValueType local_type = this->local_type(imm.index); 31881cb0ef41Sopenharmony_ci Value value = Peek(0, 0, local_type); 31891cb0ef41Sopenharmony_ci Value result = CreateValue(local_type); 31901cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(LocalTee, value, &result, imm); 31911cb0ef41Sopenharmony_ci Drop(value); 31921cb0ef41Sopenharmony_ci Push(result); 31931cb0ef41Sopenharmony_ci this->set_local_initialized(imm.index); 31941cb0ef41Sopenharmony_ci return 1 + imm.length; 31951cb0ef41Sopenharmony_ci } 31961cb0ef41Sopenharmony_ci 31971cb0ef41Sopenharmony_ci DECODE(Drop) { 31981cb0ef41Sopenharmony_ci Peek(0); 31991cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Drop); 32001cb0ef41Sopenharmony_ci Drop(1); 32011cb0ef41Sopenharmony_ci return 1; 32021cb0ef41Sopenharmony_ci } 32031cb0ef41Sopenharmony_ci 32041cb0ef41Sopenharmony_ci DECODE(GlobalGet) { 32051cb0ef41Sopenharmony_ci GlobalIndexImmediate<validate> imm(this, this->pc_ + 1); 32061cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 32071cb0ef41Sopenharmony_ci Value result = CreateValue(imm.global->type); 32081cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(GlobalGet, &result, imm); 32091cb0ef41Sopenharmony_ci Push(result); 32101cb0ef41Sopenharmony_ci return 1 + imm.length; 32111cb0ef41Sopenharmony_ci } 32121cb0ef41Sopenharmony_ci 32131cb0ef41Sopenharmony_ci DECODE(GlobalSet) { 32141cb0ef41Sopenharmony_ci GlobalIndexImmediate<validate> imm(this, this->pc_ + 1); 32151cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 32161cb0ef41Sopenharmony_ci if (!VALIDATE(imm.global->mutability)) { 32171cb0ef41Sopenharmony_ci this->DecodeError("immutable global #%u cannot be assigned", imm.index); 32181cb0ef41Sopenharmony_ci return 0; 32191cb0ef41Sopenharmony_ci } 32201cb0ef41Sopenharmony_ci Value value = Peek(0, 0, imm.global->type); 32211cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(GlobalSet, value, imm); 32221cb0ef41Sopenharmony_ci Drop(value); 32231cb0ef41Sopenharmony_ci return 1 + imm.length; 32241cb0ef41Sopenharmony_ci } 32251cb0ef41Sopenharmony_ci 32261cb0ef41Sopenharmony_ci DECODE(TableGet) { 32271cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_reftypes); 32281cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + 1, "table index"); 32291cb0ef41Sopenharmony_ci if (!this->ValidateTable(this->pc_ + 1, imm)) return 0; 32301cb0ef41Sopenharmony_ci Value index = Peek(0, 0, kWasmI32); 32311cb0ef41Sopenharmony_ci Value result = CreateValue(this->module_->tables[imm.index].type); 32321cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(TableGet, index, &result, imm); 32331cb0ef41Sopenharmony_ci Drop(index); 32341cb0ef41Sopenharmony_ci Push(result); 32351cb0ef41Sopenharmony_ci return 1 + imm.length; 32361cb0ef41Sopenharmony_ci } 32371cb0ef41Sopenharmony_ci 32381cb0ef41Sopenharmony_ci DECODE(TableSet) { 32391cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_reftypes); 32401cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + 1, "table index"); 32411cb0ef41Sopenharmony_ci if (!this->ValidateTable(this->pc_ + 1, imm)) return 0; 32421cb0ef41Sopenharmony_ci Value value = Peek(0, 1, this->module_->tables[imm.index].type); 32431cb0ef41Sopenharmony_ci Value index = Peek(1, 0, kWasmI32); 32441cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(TableSet, index, value, imm); 32451cb0ef41Sopenharmony_ci Drop(2); 32461cb0ef41Sopenharmony_ci return 1 + imm.length; 32471cb0ef41Sopenharmony_ci } 32481cb0ef41Sopenharmony_ci 32491cb0ef41Sopenharmony_ci DECODE(LoadMem) { 32501cb0ef41Sopenharmony_ci // Hard-code the list of load types. The opcodes are highly unlikely to 32511cb0ef41Sopenharmony_ci // ever change, and we have some checks here to guard against that. 32521cb0ef41Sopenharmony_ci static_assert(sizeof(LoadType) == sizeof(uint8_t), "LoadType is compact"); 32531cb0ef41Sopenharmony_ci static constexpr uint8_t kMinOpcode = kExprI32LoadMem; 32541cb0ef41Sopenharmony_ci static constexpr uint8_t kMaxOpcode = kExprI64LoadMem32U; 32551cb0ef41Sopenharmony_ci static constexpr LoadType kLoadTypes[] = { 32561cb0ef41Sopenharmony_ci LoadType::kI32Load, LoadType::kI64Load, LoadType::kF32Load, 32571cb0ef41Sopenharmony_ci LoadType::kF64Load, LoadType::kI32Load8S, LoadType::kI32Load8U, 32581cb0ef41Sopenharmony_ci LoadType::kI32Load16S, LoadType::kI32Load16U, LoadType::kI64Load8S, 32591cb0ef41Sopenharmony_ci LoadType::kI64Load8U, LoadType::kI64Load16S, LoadType::kI64Load16U, 32601cb0ef41Sopenharmony_ci LoadType::kI64Load32S, LoadType::kI64Load32U}; 32611cb0ef41Sopenharmony_ci STATIC_ASSERT(arraysize(kLoadTypes) == kMaxOpcode - kMinOpcode + 1); 32621cb0ef41Sopenharmony_ci DCHECK_LE(kMinOpcode, opcode); 32631cb0ef41Sopenharmony_ci DCHECK_GE(kMaxOpcode, opcode); 32641cb0ef41Sopenharmony_ci return DecodeLoadMem(kLoadTypes[opcode - kMinOpcode]); 32651cb0ef41Sopenharmony_ci } 32661cb0ef41Sopenharmony_ci 32671cb0ef41Sopenharmony_ci DECODE(StoreMem) { 32681cb0ef41Sopenharmony_ci // Hard-code the list of store types. The opcodes are highly unlikely to 32691cb0ef41Sopenharmony_ci // ever change, and we have some checks here to guard against that. 32701cb0ef41Sopenharmony_ci static_assert(sizeof(StoreType) == sizeof(uint8_t), "StoreType is compact"); 32711cb0ef41Sopenharmony_ci static constexpr uint8_t kMinOpcode = kExprI32StoreMem; 32721cb0ef41Sopenharmony_ci static constexpr uint8_t kMaxOpcode = kExprI64StoreMem32; 32731cb0ef41Sopenharmony_ci static constexpr StoreType kStoreTypes[] = { 32741cb0ef41Sopenharmony_ci StoreType::kI32Store, StoreType::kI64Store, StoreType::kF32Store, 32751cb0ef41Sopenharmony_ci StoreType::kF64Store, StoreType::kI32Store8, StoreType::kI32Store16, 32761cb0ef41Sopenharmony_ci StoreType::kI64Store8, StoreType::kI64Store16, StoreType::kI64Store32}; 32771cb0ef41Sopenharmony_ci STATIC_ASSERT(arraysize(kStoreTypes) == kMaxOpcode - kMinOpcode + 1); 32781cb0ef41Sopenharmony_ci DCHECK_LE(kMinOpcode, opcode); 32791cb0ef41Sopenharmony_ci DCHECK_GE(kMaxOpcode, opcode); 32801cb0ef41Sopenharmony_ci return DecodeStoreMem(kStoreTypes[opcode - kMinOpcode]); 32811cb0ef41Sopenharmony_ci } 32821cb0ef41Sopenharmony_ci 32831cb0ef41Sopenharmony_ci DECODE(MemoryGrow) { 32841cb0ef41Sopenharmony_ci MemoryIndexImmediate<validate> imm(this, this->pc_ + 1); 32851cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 32861cb0ef41Sopenharmony_ci // This opcode will not be emitted by the asm translator. 32871cb0ef41Sopenharmony_ci DCHECK_EQ(kWasmOrigin, this->module_->origin); 32881cb0ef41Sopenharmony_ci ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 32891cb0ef41Sopenharmony_ci Value value = Peek(0, 0, mem_type); 32901cb0ef41Sopenharmony_ci Value result = CreateValue(mem_type); 32911cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryGrow, value, &result); 32921cb0ef41Sopenharmony_ci Drop(value); 32931cb0ef41Sopenharmony_ci Push(result); 32941cb0ef41Sopenharmony_ci return 1 + imm.length; 32951cb0ef41Sopenharmony_ci } 32961cb0ef41Sopenharmony_ci 32971cb0ef41Sopenharmony_ci DECODE(MemorySize) { 32981cb0ef41Sopenharmony_ci MemoryIndexImmediate<validate> imm(this, this->pc_ + 1); 32991cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 33001cb0ef41Sopenharmony_ci ValueType result_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 33011cb0ef41Sopenharmony_ci Value result = CreateValue(result_type); 33021cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(CurrentMemoryPages, &result); 33031cb0ef41Sopenharmony_ci Push(result); 33041cb0ef41Sopenharmony_ci return 1 + imm.length; 33051cb0ef41Sopenharmony_ci } 33061cb0ef41Sopenharmony_ci 33071cb0ef41Sopenharmony_ci DECODE(CallFunction) { 33081cb0ef41Sopenharmony_ci CallFunctionImmediate<validate> imm(this, this->pc_ + 1); 33091cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 33101cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig); 33111cb0ef41Sopenharmony_ci ReturnVector returns = CreateReturnValues(imm.sig); 33121cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(CallDirect, imm, args.begin(), 33131cb0ef41Sopenharmony_ci returns.begin()); 33141cb0ef41Sopenharmony_ci DropArgs(imm.sig); 33151cb0ef41Sopenharmony_ci PushReturns(returns); 33161cb0ef41Sopenharmony_ci return 1 + imm.length; 33171cb0ef41Sopenharmony_ci } 33181cb0ef41Sopenharmony_ci 33191cb0ef41Sopenharmony_ci DECODE(CallIndirect) { 33201cb0ef41Sopenharmony_ci CallIndirectImmediate<validate> imm(this, this->pc_ + 1); 33211cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 33221cb0ef41Sopenharmony_ci Value index = 33231cb0ef41Sopenharmony_ci Peek(0, static_cast<int>(imm.sig->parameter_count()), kWasmI32); 33241cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig, 1); 33251cb0ef41Sopenharmony_ci ReturnVector returns = CreateReturnValues(imm.sig); 33261cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(CallIndirect, index, imm, args.begin(), 33271cb0ef41Sopenharmony_ci returns.begin()); 33281cb0ef41Sopenharmony_ci Drop(index); 33291cb0ef41Sopenharmony_ci DropArgs(imm.sig); 33301cb0ef41Sopenharmony_ci PushReturns(returns); 33311cb0ef41Sopenharmony_ci return 1 + imm.length; 33321cb0ef41Sopenharmony_ci } 33331cb0ef41Sopenharmony_ci 33341cb0ef41Sopenharmony_ci DECODE(ReturnCall) { 33351cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(return_call); 33361cb0ef41Sopenharmony_ci CallFunctionImmediate<validate> imm(this, this->pc_ + 1); 33371cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 33381cb0ef41Sopenharmony_ci if (!VALIDATE(this->CanReturnCall(imm.sig))) { 33391cb0ef41Sopenharmony_ci this->DecodeError("%s: %s", WasmOpcodes::OpcodeName(kExprReturnCall), 33401cb0ef41Sopenharmony_ci "tail call type error"); 33411cb0ef41Sopenharmony_ci return 0; 33421cb0ef41Sopenharmony_ci } 33431cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig); 33441cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ReturnCall, imm, args.begin()); 33451cb0ef41Sopenharmony_ci DropArgs(imm.sig); 33461cb0ef41Sopenharmony_ci EndControl(); 33471cb0ef41Sopenharmony_ci return 1 + imm.length; 33481cb0ef41Sopenharmony_ci } 33491cb0ef41Sopenharmony_ci 33501cb0ef41Sopenharmony_ci DECODE(ReturnCallIndirect) { 33511cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(return_call); 33521cb0ef41Sopenharmony_ci CallIndirectImmediate<validate> imm(this, this->pc_ + 1); 33531cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + 1, imm)) return 0; 33541cb0ef41Sopenharmony_ci if (!VALIDATE(this->CanReturnCall(imm.sig))) { 33551cb0ef41Sopenharmony_ci this->DecodeError("%s: %s", 33561cb0ef41Sopenharmony_ci WasmOpcodes::OpcodeName(kExprReturnCallIndirect), 33571cb0ef41Sopenharmony_ci "tail call return types mismatch"); 33581cb0ef41Sopenharmony_ci return 0; 33591cb0ef41Sopenharmony_ci } 33601cb0ef41Sopenharmony_ci Value index = Peek(0, 0, kWasmI32); 33611cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.sig, 1); 33621cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ReturnCallIndirect, index, imm, 33631cb0ef41Sopenharmony_ci args.begin()); 33641cb0ef41Sopenharmony_ci Drop(index); 33651cb0ef41Sopenharmony_ci DropArgs(imm.sig); 33661cb0ef41Sopenharmony_ci EndControl(); 33671cb0ef41Sopenharmony_ci return 1 + imm.length; 33681cb0ef41Sopenharmony_ci } 33691cb0ef41Sopenharmony_ci 33701cb0ef41Sopenharmony_ci DECODE(CallRef) { 33711cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(typed_funcref); 33721cb0ef41Sopenharmony_ci Value func_ref = Peek(0); 33731cb0ef41Sopenharmony_ci ValueType func_type = func_ref.type; 33741cb0ef41Sopenharmony_ci if (func_type == kWasmBottom) { 33751cb0ef41Sopenharmony_ci // We are in unreachable code, maintain the polymorphic stack. 33761cb0ef41Sopenharmony_ci return 1; 33771cb0ef41Sopenharmony_ci } 33781cb0ef41Sopenharmony_ci if (!VALIDATE(func_type.is_object_reference() && func_type.has_index() && 33791cb0ef41Sopenharmony_ci this->module_->has_signature(func_type.ref_index()))) { 33801cb0ef41Sopenharmony_ci PopTypeError(0, func_ref, "function reference"); 33811cb0ef41Sopenharmony_ci return 0; 33821cb0ef41Sopenharmony_ci } 33831cb0ef41Sopenharmony_ci const FunctionSig* sig = this->module_->signature(func_type.ref_index()); 33841cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(sig, 1); 33851cb0ef41Sopenharmony_ci ReturnVector returns = CreateReturnValues(sig); 33861cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(CallRef, func_ref, sig, 33871cb0ef41Sopenharmony_ci func_type.ref_index(), args.begin(), 33881cb0ef41Sopenharmony_ci returns.begin()); 33891cb0ef41Sopenharmony_ci Drop(func_ref); 33901cb0ef41Sopenharmony_ci DropArgs(sig); 33911cb0ef41Sopenharmony_ci PushReturns(returns); 33921cb0ef41Sopenharmony_ci return 1; 33931cb0ef41Sopenharmony_ci } 33941cb0ef41Sopenharmony_ci 33951cb0ef41Sopenharmony_ci DECODE(ReturnCallRef) { 33961cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(typed_funcref); 33971cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(return_call); 33981cb0ef41Sopenharmony_ci Value func_ref = Peek(0); 33991cb0ef41Sopenharmony_ci ValueType func_type = func_ref.type; 34001cb0ef41Sopenharmony_ci if (func_type == kWasmBottom) { 34011cb0ef41Sopenharmony_ci // We are in unreachable code, maintain the polymorphic stack. 34021cb0ef41Sopenharmony_ci return 1; 34031cb0ef41Sopenharmony_ci } 34041cb0ef41Sopenharmony_ci if (!VALIDATE(func_type.is_object_reference() && func_type.has_index() && 34051cb0ef41Sopenharmony_ci this->module_->has_signature(func_type.ref_index()))) { 34061cb0ef41Sopenharmony_ci PopTypeError(0, func_ref, "function reference"); 34071cb0ef41Sopenharmony_ci return 0; 34081cb0ef41Sopenharmony_ci } 34091cb0ef41Sopenharmony_ci const FunctionSig* sig = this->module_->signature(func_type.ref_index()); 34101cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(sig, 1); 34111cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ReturnCallRef, func_ref, sig, 34121cb0ef41Sopenharmony_ci func_type.ref_index(), args.begin()); 34131cb0ef41Sopenharmony_ci Drop(func_ref); 34141cb0ef41Sopenharmony_ci DropArgs(sig); 34151cb0ef41Sopenharmony_ci EndControl(); 34161cb0ef41Sopenharmony_ci return 1; 34171cb0ef41Sopenharmony_ci } 34181cb0ef41Sopenharmony_ci 34191cb0ef41Sopenharmony_ci DECODE(Numeric) { 34201cb0ef41Sopenharmony_ci uint32_t opcode_length = 0; 34211cb0ef41Sopenharmony_ci WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>( 34221cb0ef41Sopenharmony_ci this->pc_, &opcode_length, "numeric index"); 34231cb0ef41Sopenharmony_ci if (full_opcode == kExprTableGrow || full_opcode == kExprTableSize || 34241cb0ef41Sopenharmony_ci full_opcode == kExprTableFill) { 34251cb0ef41Sopenharmony_ci this->detected_->Add(kFeature_reftypes); 34261cb0ef41Sopenharmony_ci } 34271cb0ef41Sopenharmony_ci trace_msg->AppendOpcode(full_opcode); 34281cb0ef41Sopenharmony_ci return DecodeNumericOpcode(full_opcode, opcode_length); 34291cb0ef41Sopenharmony_ci } 34301cb0ef41Sopenharmony_ci 34311cb0ef41Sopenharmony_ci DECODE(Simd) { 34321cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(simd); 34331cb0ef41Sopenharmony_ci if (!CheckHardwareSupportsSimd()) { 34341cb0ef41Sopenharmony_ci if (FLAG_correctness_fuzzer_suppressions) { 34351cb0ef41Sopenharmony_ci FATAL("Aborting on missing Wasm SIMD support"); 34361cb0ef41Sopenharmony_ci } 34371cb0ef41Sopenharmony_ci this->DecodeError("Wasm SIMD unsupported"); 34381cb0ef41Sopenharmony_ci return 0; 34391cb0ef41Sopenharmony_ci } 34401cb0ef41Sopenharmony_ci uint32_t opcode_length = 0; 34411cb0ef41Sopenharmony_ci WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>( 34421cb0ef41Sopenharmony_ci this->pc_, &opcode_length); 34431cb0ef41Sopenharmony_ci if (!VALIDATE(this->ok())) return 0; 34441cb0ef41Sopenharmony_ci trace_msg->AppendOpcode(full_opcode); 34451cb0ef41Sopenharmony_ci if (!CheckSimdFeatureFlagOpcode(full_opcode)) { 34461cb0ef41Sopenharmony_ci return 0; 34471cb0ef41Sopenharmony_ci } 34481cb0ef41Sopenharmony_ci return DecodeSimdOpcode(full_opcode, opcode_length); 34491cb0ef41Sopenharmony_ci } 34501cb0ef41Sopenharmony_ci 34511cb0ef41Sopenharmony_ci DECODE(Atomic) { 34521cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(threads); 34531cb0ef41Sopenharmony_ci uint32_t opcode_length = 0; 34541cb0ef41Sopenharmony_ci WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>( 34551cb0ef41Sopenharmony_ci this->pc_, &opcode_length, "atomic index"); 34561cb0ef41Sopenharmony_ci trace_msg->AppendOpcode(full_opcode); 34571cb0ef41Sopenharmony_ci return DecodeAtomicOpcode(full_opcode, opcode_length); 34581cb0ef41Sopenharmony_ci } 34591cb0ef41Sopenharmony_ci 34601cb0ef41Sopenharmony_ci DECODE(GC) { 34611cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(gc); 34621cb0ef41Sopenharmony_ci uint32_t opcode_length = 0; 34631cb0ef41Sopenharmony_ci WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>( 34641cb0ef41Sopenharmony_ci this->pc_, &opcode_length, "gc index"); 34651cb0ef41Sopenharmony_ci trace_msg->AppendOpcode(full_opcode); 34661cb0ef41Sopenharmony_ci return DecodeGCOpcode(full_opcode, opcode_length); 34671cb0ef41Sopenharmony_ci } 34681cb0ef41Sopenharmony_ci 34691cb0ef41Sopenharmony_ci#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \ 34701cb0ef41Sopenharmony_ci DECODE(name) { return BuildSimplePrototypeOperator(opcode); } 34711cb0ef41Sopenharmony_ci FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE) 34721cb0ef41Sopenharmony_ci#undef SIMPLE_PROTOTYPE_CASE 34731cb0ef41Sopenharmony_ci 34741cb0ef41Sopenharmony_ci DECODE(UnknownOrAsmJs) { 34751cb0ef41Sopenharmony_ci // Deal with special asmjs opcodes. 34761cb0ef41Sopenharmony_ci if (!VALIDATE(is_asmjs_module(this->module_))) { 34771cb0ef41Sopenharmony_ci this->DecodeError("Invalid opcode 0x%x", opcode); 34781cb0ef41Sopenharmony_ci return 0; 34791cb0ef41Sopenharmony_ci } 34801cb0ef41Sopenharmony_ci const FunctionSig* sig = WasmOpcodes::AsmjsSignature(opcode); 34811cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(sig); 34821cb0ef41Sopenharmony_ci return BuildSimpleOperator(opcode, sig); 34831cb0ef41Sopenharmony_ci } 34841cb0ef41Sopenharmony_ci 34851cb0ef41Sopenharmony_ci#undef DECODE 34861cb0ef41Sopenharmony_ci 34871cb0ef41Sopenharmony_ci static int NonConstError(WasmFullDecoder* decoder, WasmOpcode opcode) { 34881cb0ef41Sopenharmony_ci decoder->DecodeError("opcode %s is not allowed in init. expressions", 34891cb0ef41Sopenharmony_ci WasmOpcodes::OpcodeName(opcode)); 34901cb0ef41Sopenharmony_ci return 0; 34911cb0ef41Sopenharmony_ci } 34921cb0ef41Sopenharmony_ci 34931cb0ef41Sopenharmony_ci using OpcodeHandler = int (*)(WasmFullDecoder*, WasmOpcode); 34941cb0ef41Sopenharmony_ci 34951cb0ef41Sopenharmony_ci // Ideally we would use template specialization for the different opcodes, but 34961cb0ef41Sopenharmony_ci // GCC does not allow to specialize templates in class scope 34971cb0ef41Sopenharmony_ci // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282), and specializing 34981cb0ef41Sopenharmony_ci // outside the class is not allowed for non-specialized classes. 34991cb0ef41Sopenharmony_ci // Hence just list all implementations explicitly here, which also gives more 35001cb0ef41Sopenharmony_ci // freedom to use the same implementation for different opcodes. 35011cb0ef41Sopenharmony_ci#define DECODE_IMPL(opcode) DECODE_IMPL2(kExpr##opcode, opcode) 35021cb0ef41Sopenharmony_ci#define DECODE_IMPL2(opcode, name) \ 35031cb0ef41Sopenharmony_ci if (idx == opcode) { \ 35041cb0ef41Sopenharmony_ci if (decoding_mode == kInitExpression) { \ 35051cb0ef41Sopenharmony_ci return &WasmFullDecoder::NonConstError; \ 35061cb0ef41Sopenharmony_ci } else { \ 35071cb0ef41Sopenharmony_ci return &WasmFullDecoder::Decode##name; \ 35081cb0ef41Sopenharmony_ci } \ 35091cb0ef41Sopenharmony_ci } 35101cb0ef41Sopenharmony_ci#define DECODE_IMPL_CONST(opcode) DECODE_IMPL_CONST2(kExpr##opcode, opcode) 35111cb0ef41Sopenharmony_ci#define DECODE_IMPL_CONST2(opcode, name) \ 35121cb0ef41Sopenharmony_ci if (idx == opcode) return &WasmFullDecoder::Decode##name 35131cb0ef41Sopenharmony_ci 35141cb0ef41Sopenharmony_ci static constexpr OpcodeHandler GetOpcodeHandlerTableEntry(size_t idx) { 35151cb0ef41Sopenharmony_ci DECODE_IMPL(Nop); 35161cb0ef41Sopenharmony_ci#define BUILD_SIMPLE_OPCODE(op, _, sig) DECODE_IMPL(op); 35171cb0ef41Sopenharmony_ci FOREACH_SIMPLE_NON_CONST_OPCODE(BUILD_SIMPLE_OPCODE) 35181cb0ef41Sopenharmony_ci#undef BUILD_SIMPLE_OPCODE 35191cb0ef41Sopenharmony_ci#define BUILD_SIMPLE_EXTENDED_CONST_OPCODE(op, _, sig) DECODE_IMPL_CONST(op); 35201cb0ef41Sopenharmony_ci FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(BUILD_SIMPLE_EXTENDED_CONST_OPCODE) 35211cb0ef41Sopenharmony_ci#undef BUILD_SIMPLE_EXTENDED_CONST_OPCODE 35221cb0ef41Sopenharmony_ci DECODE_IMPL(Block); 35231cb0ef41Sopenharmony_ci DECODE_IMPL(Rethrow); 35241cb0ef41Sopenharmony_ci DECODE_IMPL(Throw); 35251cb0ef41Sopenharmony_ci DECODE_IMPL(Try); 35261cb0ef41Sopenharmony_ci DECODE_IMPL(Catch); 35271cb0ef41Sopenharmony_ci DECODE_IMPL(Delegate); 35281cb0ef41Sopenharmony_ci DECODE_IMPL(CatchAll); 35291cb0ef41Sopenharmony_ci DECODE_IMPL(BrOnNull); 35301cb0ef41Sopenharmony_ci DECODE_IMPL(BrOnNonNull); 35311cb0ef41Sopenharmony_ci DECODE_IMPL(Let); 35321cb0ef41Sopenharmony_ci DECODE_IMPL(Loop); 35331cb0ef41Sopenharmony_ci DECODE_IMPL(If); 35341cb0ef41Sopenharmony_ci DECODE_IMPL(Else); 35351cb0ef41Sopenharmony_ci DECODE_IMPL_CONST(End); 35361cb0ef41Sopenharmony_ci DECODE_IMPL(Select); 35371cb0ef41Sopenharmony_ci DECODE_IMPL(SelectWithType); 35381cb0ef41Sopenharmony_ci DECODE_IMPL(Br); 35391cb0ef41Sopenharmony_ci DECODE_IMPL(BrIf); 35401cb0ef41Sopenharmony_ci DECODE_IMPL(BrTable); 35411cb0ef41Sopenharmony_ci DECODE_IMPL(Return); 35421cb0ef41Sopenharmony_ci DECODE_IMPL(Unreachable); 35431cb0ef41Sopenharmony_ci DECODE_IMPL(NopForTestingUnsupportedInLiftoff); 35441cb0ef41Sopenharmony_ci DECODE_IMPL_CONST(I32Const); 35451cb0ef41Sopenharmony_ci DECODE_IMPL_CONST(I64Const); 35461cb0ef41Sopenharmony_ci DECODE_IMPL_CONST(F32Const); 35471cb0ef41Sopenharmony_ci DECODE_IMPL_CONST(F64Const); 35481cb0ef41Sopenharmony_ci DECODE_IMPL_CONST(RefNull); 35491cb0ef41Sopenharmony_ci DECODE_IMPL(RefIsNull); 35501cb0ef41Sopenharmony_ci DECODE_IMPL_CONST(RefFunc); 35511cb0ef41Sopenharmony_ci DECODE_IMPL(RefAsNonNull); 35521cb0ef41Sopenharmony_ci DECODE_IMPL(LocalGet); 35531cb0ef41Sopenharmony_ci DECODE_IMPL(LocalSet); 35541cb0ef41Sopenharmony_ci DECODE_IMPL(LocalTee); 35551cb0ef41Sopenharmony_ci DECODE_IMPL(Drop); 35561cb0ef41Sopenharmony_ci DECODE_IMPL_CONST(GlobalGet); 35571cb0ef41Sopenharmony_ci DECODE_IMPL(GlobalSet); 35581cb0ef41Sopenharmony_ci DECODE_IMPL(TableGet); 35591cb0ef41Sopenharmony_ci DECODE_IMPL(TableSet); 35601cb0ef41Sopenharmony_ci#define DECODE_LOAD_MEM(op, ...) DECODE_IMPL2(kExpr##op, LoadMem); 35611cb0ef41Sopenharmony_ci FOREACH_LOAD_MEM_OPCODE(DECODE_LOAD_MEM) 35621cb0ef41Sopenharmony_ci#undef DECODE_LOAD_MEM 35631cb0ef41Sopenharmony_ci#define DECODE_STORE_MEM(op, ...) DECODE_IMPL2(kExpr##op, StoreMem); 35641cb0ef41Sopenharmony_ci FOREACH_STORE_MEM_OPCODE(DECODE_STORE_MEM) 35651cb0ef41Sopenharmony_ci#undef DECODE_LOAD_MEM 35661cb0ef41Sopenharmony_ci DECODE_IMPL(MemoryGrow); 35671cb0ef41Sopenharmony_ci DECODE_IMPL(MemorySize); 35681cb0ef41Sopenharmony_ci DECODE_IMPL(CallFunction); 35691cb0ef41Sopenharmony_ci DECODE_IMPL(CallIndirect); 35701cb0ef41Sopenharmony_ci DECODE_IMPL(ReturnCall); 35711cb0ef41Sopenharmony_ci DECODE_IMPL(ReturnCallIndirect); 35721cb0ef41Sopenharmony_ci DECODE_IMPL(CallRef); 35731cb0ef41Sopenharmony_ci DECODE_IMPL(ReturnCallRef); 35741cb0ef41Sopenharmony_ci DECODE_IMPL2(kNumericPrefix, Numeric); 35751cb0ef41Sopenharmony_ci DECODE_IMPL_CONST2(kSimdPrefix, Simd); 35761cb0ef41Sopenharmony_ci DECODE_IMPL2(kAtomicPrefix, Atomic); 35771cb0ef41Sopenharmony_ci DECODE_IMPL_CONST2(kGCPrefix, GC); 35781cb0ef41Sopenharmony_ci#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) DECODE_IMPL(name); 35791cb0ef41Sopenharmony_ci FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE) 35801cb0ef41Sopenharmony_ci#undef SIMPLE_PROTOTYPE_CASE 35811cb0ef41Sopenharmony_ci return &WasmFullDecoder::DecodeUnknownOrAsmJs; 35821cb0ef41Sopenharmony_ci } 35831cb0ef41Sopenharmony_ci 35841cb0ef41Sopenharmony_ci#undef DECODE_IMPL 35851cb0ef41Sopenharmony_ci#undef DECODE_IMPL2 35861cb0ef41Sopenharmony_ci 35871cb0ef41Sopenharmony_ci OpcodeHandler GetOpcodeHandler(uint8_t opcode) { 35881cb0ef41Sopenharmony_ci static constexpr std::array<OpcodeHandler, 256> kOpcodeHandlers = 35891cb0ef41Sopenharmony_ci base::make_array<256>(GetOpcodeHandlerTableEntry); 35901cb0ef41Sopenharmony_ci return kOpcodeHandlers[opcode]; 35911cb0ef41Sopenharmony_ci } 35921cb0ef41Sopenharmony_ci 35931cb0ef41Sopenharmony_ci void EndControl() { 35941cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); 35951cb0ef41Sopenharmony_ci Control* current = &control_.back(); 35961cb0ef41Sopenharmony_ci DCHECK_LE(stack_ + current->stack_depth, stack_end_); 35971cb0ef41Sopenharmony_ci stack_end_ = stack_ + current->stack_depth; 35981cb0ef41Sopenharmony_ci current->reachability = kUnreachable; 35991cb0ef41Sopenharmony_ci current_code_reachable_and_ok_ = false; 36001cb0ef41Sopenharmony_ci } 36011cb0ef41Sopenharmony_ci 36021cb0ef41Sopenharmony_ci template <typename func> 36031cb0ef41Sopenharmony_ci void InitMerge(Merge<Value>* merge, uint32_t arity, func get_val) { 36041cb0ef41Sopenharmony_ci merge->arity = arity; 36051cb0ef41Sopenharmony_ci if (arity == 1) { 36061cb0ef41Sopenharmony_ci merge->vals.first = get_val(0); 36071cb0ef41Sopenharmony_ci } else if (arity > 1) { 36081cb0ef41Sopenharmony_ci merge->vals.array = this->zone()->template NewArray<Value>(arity); 36091cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < arity; i++) { 36101cb0ef41Sopenharmony_ci merge->vals.array[i] = get_val(i); 36111cb0ef41Sopenharmony_ci } 36121cb0ef41Sopenharmony_ci } 36131cb0ef41Sopenharmony_ci } 36141cb0ef41Sopenharmony_ci 36151cb0ef41Sopenharmony_ci // Initializes start- and end-merges of {c} with values according to the 36161cb0ef41Sopenharmony_ci // in- and out-types of {c} respectively. 36171cb0ef41Sopenharmony_ci void SetBlockType(Control* c, BlockTypeImmediate<validate>& imm, 36181cb0ef41Sopenharmony_ci Value* args) { 36191cb0ef41Sopenharmony_ci const byte* pc = this->pc_; 36201cb0ef41Sopenharmony_ci InitMerge(&c->end_merge, imm.out_arity(), [pc, &imm](uint32_t i) { 36211cb0ef41Sopenharmony_ci return Value{pc, imm.out_type(i)}; 36221cb0ef41Sopenharmony_ci }); 36231cb0ef41Sopenharmony_ci InitMerge(&c->start_merge, imm.in_arity(), [&imm, args](uint32_t i) { 36241cb0ef41Sopenharmony_ci // The merge needs to be instantiated with Values of the correct 36251cb0ef41Sopenharmony_ci // type, even if the actual Value is bottom/unreachable or has 36261cb0ef41Sopenharmony_ci // a subtype of the static type. 36271cb0ef41Sopenharmony_ci // So we copy-construct a new Value, and update its type. 36281cb0ef41Sopenharmony_ci Value value = args[i]; 36291cb0ef41Sopenharmony_ci value.type = imm.in_type(i); 36301cb0ef41Sopenharmony_ci return value; 36311cb0ef41Sopenharmony_ci }); 36321cb0ef41Sopenharmony_ci } 36331cb0ef41Sopenharmony_ci 36341cb0ef41Sopenharmony_ci // In reachable code, check if there are at least {count} values on the stack. 36351cb0ef41Sopenharmony_ci // In unreachable code, if there are less than {count} values on the stack, 36361cb0ef41Sopenharmony_ci // insert a number of unreachable values underneath the current values equal 36371cb0ef41Sopenharmony_ci // to the difference, and return that number. 36381cb0ef41Sopenharmony_ci V8_INLINE int EnsureStackArguments(int count) { 36391cb0ef41Sopenharmony_ci uint32_t limit = control_.back().stack_depth; 36401cb0ef41Sopenharmony_ci if (V8_LIKELY(stack_size() >= count + limit)) return 0; 36411cb0ef41Sopenharmony_ci return EnsureStackArguments_Slow(count, limit); 36421cb0ef41Sopenharmony_ci } 36431cb0ef41Sopenharmony_ci 36441cb0ef41Sopenharmony_ci V8_NOINLINE int EnsureStackArguments_Slow(int count, uint32_t limit) { 36451cb0ef41Sopenharmony_ci if (!VALIDATE(control_.back().unreachable())) { 36461cb0ef41Sopenharmony_ci NotEnoughArgumentsError(count, stack_size() - limit); 36471cb0ef41Sopenharmony_ci } 36481cb0ef41Sopenharmony_ci // Silently create unreachable values out of thin air underneath the 36491cb0ef41Sopenharmony_ci // existing stack values. To do so, we have to move existing stack values 36501cb0ef41Sopenharmony_ci // upwards in the stack, then instantiate the new Values as 36511cb0ef41Sopenharmony_ci // {UnreachableValue}. 36521cb0ef41Sopenharmony_ci int current_values = stack_size() - limit; 36531cb0ef41Sopenharmony_ci int additional_values = count - current_values; 36541cb0ef41Sopenharmony_ci DCHECK_GT(additional_values, 0); 36551cb0ef41Sopenharmony_ci EnsureStackSpace(additional_values); 36561cb0ef41Sopenharmony_ci stack_end_ += additional_values; 36571cb0ef41Sopenharmony_ci Value* stack_base = stack_value(current_values + additional_values); 36581cb0ef41Sopenharmony_ci for (int i = current_values - 1; i >= 0; i--) { 36591cb0ef41Sopenharmony_ci stack_base[additional_values + i] = stack_base[i]; 36601cb0ef41Sopenharmony_ci } 36611cb0ef41Sopenharmony_ci for (int i = 0; i < additional_values; i++) { 36621cb0ef41Sopenharmony_ci stack_base[i] = UnreachableValue(this->pc_); 36631cb0ef41Sopenharmony_ci } 36641cb0ef41Sopenharmony_ci return additional_values; 36651cb0ef41Sopenharmony_ci } 36661cb0ef41Sopenharmony_ci 36671cb0ef41Sopenharmony_ci // Peeks arguments as required by signature. 36681cb0ef41Sopenharmony_ci V8_INLINE ArgVector PeekArgs(const FunctionSig* sig, int depth = 0) { 36691cb0ef41Sopenharmony_ci int count = sig ? static_cast<int>(sig->parameter_count()) : 0; 36701cb0ef41Sopenharmony_ci if (count == 0) return {}; 36711cb0ef41Sopenharmony_ci EnsureStackArguments(depth + count); 36721cb0ef41Sopenharmony_ci ArgVector args(stack_value(depth + count), count); 36731cb0ef41Sopenharmony_ci for (int i = 0; i < count; i++) { 36741cb0ef41Sopenharmony_ci ValidateArgType(args, i, sig->GetParam(i)); 36751cb0ef41Sopenharmony_ci } 36761cb0ef41Sopenharmony_ci return args; 36771cb0ef41Sopenharmony_ci } 36781cb0ef41Sopenharmony_ci // Drops a number of stack elements equal to the {sig}'s parameter count (0 if 36791cb0ef41Sopenharmony_ci // {sig} is null), or all of them if less are present. 36801cb0ef41Sopenharmony_ci V8_INLINE void DropArgs(const FunctionSig* sig) { 36811cb0ef41Sopenharmony_ci int count = sig ? static_cast<int>(sig->parameter_count()) : 0; 36821cb0ef41Sopenharmony_ci Drop(count); 36831cb0ef41Sopenharmony_ci } 36841cb0ef41Sopenharmony_ci 36851cb0ef41Sopenharmony_ci V8_INLINE ArgVector PeekArgs(const StructType* type, int depth = 0) { 36861cb0ef41Sopenharmony_ci int count = static_cast<int>(type->field_count()); 36871cb0ef41Sopenharmony_ci if (count == 0) return {}; 36881cb0ef41Sopenharmony_ci EnsureStackArguments(depth + count); 36891cb0ef41Sopenharmony_ci ArgVector args(stack_value(depth + count), count); 36901cb0ef41Sopenharmony_ci for (int i = 0; i < count; i++) { 36911cb0ef41Sopenharmony_ci ValidateArgType(args, i, type->field(i).Unpacked()); 36921cb0ef41Sopenharmony_ci } 36931cb0ef41Sopenharmony_ci return args; 36941cb0ef41Sopenharmony_ci } 36951cb0ef41Sopenharmony_ci // Drops a number of stack elements equal to the struct's field count, or all 36961cb0ef41Sopenharmony_ci // of them if less are present. 36971cb0ef41Sopenharmony_ci V8_INLINE void DropArgs(const StructType* type) { 36981cb0ef41Sopenharmony_ci Drop(static_cast<int>(type->field_count())); 36991cb0ef41Sopenharmony_ci } 37001cb0ef41Sopenharmony_ci 37011cb0ef41Sopenharmony_ci V8_INLINE ArgVector PeekArgs(base::Vector<ValueType> arg_types) { 37021cb0ef41Sopenharmony_ci int size = static_cast<int>(arg_types.size()); 37031cb0ef41Sopenharmony_ci EnsureStackArguments(size); 37041cb0ef41Sopenharmony_ci ArgVector args(stack_value(size), arg_types.size()); 37051cb0ef41Sopenharmony_ci for (int i = 0; i < size; i++) { 37061cb0ef41Sopenharmony_ci ValidateArgType(args, i, arg_types[i]); 37071cb0ef41Sopenharmony_ci } 37081cb0ef41Sopenharmony_ci return args; 37091cb0ef41Sopenharmony_ci } 37101cb0ef41Sopenharmony_ci 37111cb0ef41Sopenharmony_ci ValueType GetReturnType(const FunctionSig* sig) { 37121cb0ef41Sopenharmony_ci DCHECK_GE(1, sig->return_count()); 37131cb0ef41Sopenharmony_ci return sig->return_count() == 0 ? kWasmVoid : sig->GetReturn(); 37141cb0ef41Sopenharmony_ci } 37151cb0ef41Sopenharmony_ci 37161cb0ef41Sopenharmony_ci // TODO(jkummerow): Consider refactoring control stack management so 37171cb0ef41Sopenharmony_ci // that {drop_values} is never needed. That would require decoupling 37181cb0ef41Sopenharmony_ci // creation of the Control object from setting of its stack depth. 37191cb0ef41Sopenharmony_ci Control* PushControl(ControlKind kind, uint32_t locals_count = 0, 37201cb0ef41Sopenharmony_ci uint32_t drop_values = 0) { 37211cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); 37221cb0ef41Sopenharmony_ci Reachability reachability = control_.back().innerReachability(); 37231cb0ef41Sopenharmony_ci // In unreachable code, we may run out of stack. 37241cb0ef41Sopenharmony_ci uint32_t stack_depth = 37251cb0ef41Sopenharmony_ci stack_size() >= drop_values ? stack_size() - drop_values : 0; 37261cb0ef41Sopenharmony_ci stack_depth = std::max(stack_depth, control_.back().stack_depth); 37271cb0ef41Sopenharmony_ci uint32_t init_stack_depth = this->locals_initialization_stack_depth(); 37281cb0ef41Sopenharmony_ci control_.emplace_back(kind, locals_count, stack_depth, init_stack_depth, 37291cb0ef41Sopenharmony_ci this->pc_, reachability); 37301cb0ef41Sopenharmony_ci current_code_reachable_and_ok_ = this->ok() && reachability == kReachable; 37311cb0ef41Sopenharmony_ci return &control_.back(); 37321cb0ef41Sopenharmony_ci } 37331cb0ef41Sopenharmony_ci 37341cb0ef41Sopenharmony_ci void PopControl() { 37351cb0ef41Sopenharmony_ci // This cannot be the outermost control block. 37361cb0ef41Sopenharmony_ci DCHECK_LT(1, control_.size()); 37371cb0ef41Sopenharmony_ci Control* c = &control_.back(); 37381cb0ef41Sopenharmony_ci DCHECK_LE(stack_ + c->stack_depth, stack_end_); 37391cb0ef41Sopenharmony_ci 37401cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(PopControl, c); 37411cb0ef41Sopenharmony_ci 37421cb0ef41Sopenharmony_ci // - In non-unreachable code, a loop just leaves the values on the stack. 37431cb0ef41Sopenharmony_ci // - In unreachable code, it is not guaranteed that we have Values of the 37441cb0ef41Sopenharmony_ci // correct types on the stack, so we have to make sure we do. Their values 37451cb0ef41Sopenharmony_ci // do not matter, so we might as well push the (uninitialized) values of 37461cb0ef41Sopenharmony_ci // the loop's end merge. 37471cb0ef41Sopenharmony_ci if (!c->is_loop() || c->unreachable()) { 37481cb0ef41Sopenharmony_ci PushMergeValues(c, &c->end_merge); 37491cb0ef41Sopenharmony_ci } 37501cb0ef41Sopenharmony_ci this->RollbackLocalsInitialization(c->init_stack_depth); 37511cb0ef41Sopenharmony_ci 37521cb0ef41Sopenharmony_ci bool parent_reached = 37531cb0ef41Sopenharmony_ci c->reachable() || c->end_merge.reached || c->is_onearmed_if(); 37541cb0ef41Sopenharmony_ci control_.pop_back(); 37551cb0ef41Sopenharmony_ci // If the parent block was reachable before, but the popped control does not 37561cb0ef41Sopenharmony_ci // return to here, this block becomes "spec only reachable". 37571cb0ef41Sopenharmony_ci if (!parent_reached) SetSucceedingCodeDynamicallyUnreachable(); 37581cb0ef41Sopenharmony_ci current_code_reachable_and_ok_ = this->ok() && control_.back().reachable(); 37591cb0ef41Sopenharmony_ci } 37601cb0ef41Sopenharmony_ci 37611cb0ef41Sopenharmony_ci int DecodeLoadMem(LoadType type, int prefix_len = 1) { 37621cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> imm = 37631cb0ef41Sopenharmony_ci MakeMemoryAccessImmediate(prefix_len, type.size_log_2()); 37641cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + prefix_len, imm)) return 0; 37651cb0ef41Sopenharmony_ci ValueType index_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 37661cb0ef41Sopenharmony_ci Value index = Peek(0, 0, index_type); 37671cb0ef41Sopenharmony_ci Value result = CreateValue(type.value_type()); 37681cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(LoadMem, type, imm, index, &result); 37691cb0ef41Sopenharmony_ci Drop(index); 37701cb0ef41Sopenharmony_ci Push(result); 37711cb0ef41Sopenharmony_ci return prefix_len + imm.length; 37721cb0ef41Sopenharmony_ci } 37731cb0ef41Sopenharmony_ci 37741cb0ef41Sopenharmony_ci int DecodeLoadTransformMem(LoadType type, LoadTransformationKind transform, 37751cb0ef41Sopenharmony_ci uint32_t opcode_length) { 37761cb0ef41Sopenharmony_ci // Load extends always load 64-bits. 37771cb0ef41Sopenharmony_ci uint32_t max_alignment = 37781cb0ef41Sopenharmony_ci transform == LoadTransformationKind::kExtend ? 3 : type.size_log_2(); 37791cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> imm = 37801cb0ef41Sopenharmony_ci MakeMemoryAccessImmediate(opcode_length, max_alignment); 37811cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 37821cb0ef41Sopenharmony_ci ValueType index_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 37831cb0ef41Sopenharmony_ci Value index = Peek(0, 0, index_type); 37841cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmS128); 37851cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(LoadTransform, type, transform, imm, 37861cb0ef41Sopenharmony_ci index, &result); 37871cb0ef41Sopenharmony_ci Drop(index); 37881cb0ef41Sopenharmony_ci Push(result); 37891cb0ef41Sopenharmony_ci return opcode_length + imm.length; 37901cb0ef41Sopenharmony_ci } 37911cb0ef41Sopenharmony_ci 37921cb0ef41Sopenharmony_ci int DecodeLoadLane(WasmOpcode opcode, LoadType type, uint32_t opcode_length) { 37931cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> mem_imm = 37941cb0ef41Sopenharmony_ci MakeMemoryAccessImmediate(opcode_length, type.size_log_2()); 37951cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, mem_imm)) return 0; 37961cb0ef41Sopenharmony_ci SimdLaneImmediate<validate> lane_imm( 37971cb0ef41Sopenharmony_ci this, this->pc_ + opcode_length + mem_imm.length); 37981cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, opcode, lane_imm)) return 0; 37991cb0ef41Sopenharmony_ci Value v128 = Peek(0, 1, kWasmS128); 38001cb0ef41Sopenharmony_ci Value index = Peek(1, 0, kWasmI32); 38011cb0ef41Sopenharmony_ci 38021cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmS128); 38031cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(LoadLane, type, v128, index, mem_imm, 38041cb0ef41Sopenharmony_ci lane_imm.lane, &result); 38051cb0ef41Sopenharmony_ci Drop(2); 38061cb0ef41Sopenharmony_ci Push(result); 38071cb0ef41Sopenharmony_ci return opcode_length + mem_imm.length + lane_imm.length; 38081cb0ef41Sopenharmony_ci } 38091cb0ef41Sopenharmony_ci 38101cb0ef41Sopenharmony_ci int DecodeStoreLane(WasmOpcode opcode, StoreType type, 38111cb0ef41Sopenharmony_ci uint32_t opcode_length) { 38121cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> mem_imm = 38131cb0ef41Sopenharmony_ci MakeMemoryAccessImmediate(opcode_length, type.size_log_2()); 38141cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, mem_imm)) return 0; 38151cb0ef41Sopenharmony_ci SimdLaneImmediate<validate> lane_imm( 38161cb0ef41Sopenharmony_ci this, this->pc_ + opcode_length + mem_imm.length); 38171cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, opcode, lane_imm)) return 0; 38181cb0ef41Sopenharmony_ci Value v128 = Peek(0, 1, kWasmS128); 38191cb0ef41Sopenharmony_ci Value index = Peek(1, 0, kWasmI32); 38201cb0ef41Sopenharmony_ci 38211cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(StoreLane, type, mem_imm, index, v128, 38221cb0ef41Sopenharmony_ci lane_imm.lane); 38231cb0ef41Sopenharmony_ci Drop(2); 38241cb0ef41Sopenharmony_ci return opcode_length + mem_imm.length + lane_imm.length; 38251cb0ef41Sopenharmony_ci } 38261cb0ef41Sopenharmony_ci 38271cb0ef41Sopenharmony_ci int DecodeStoreMem(StoreType store, int prefix_len = 1) { 38281cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> imm = 38291cb0ef41Sopenharmony_ci MakeMemoryAccessImmediate(prefix_len, store.size_log_2()); 38301cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + prefix_len, imm)) return 0; 38311cb0ef41Sopenharmony_ci Value value = Peek(0, 1, store.value_type()); 38321cb0ef41Sopenharmony_ci ValueType index_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 38331cb0ef41Sopenharmony_ci Value index = Peek(1, 0, index_type); 38341cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(StoreMem, store, imm, index, value); 38351cb0ef41Sopenharmony_ci Drop(2); 38361cb0ef41Sopenharmony_ci return prefix_len + imm.length; 38371cb0ef41Sopenharmony_ci } 38381cb0ef41Sopenharmony_ci 38391cb0ef41Sopenharmony_ci uint32_t SimdConstOp(uint32_t opcode_length) { 38401cb0ef41Sopenharmony_ci Simd128Immediate<validate> imm(this, this->pc_ + opcode_length); 38411cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmS128); 38421cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(S128Const, imm, &result); 38431cb0ef41Sopenharmony_ci Push(result); 38441cb0ef41Sopenharmony_ci return opcode_length + kSimd128Size; 38451cb0ef41Sopenharmony_ci } 38461cb0ef41Sopenharmony_ci 38471cb0ef41Sopenharmony_ci uint32_t SimdExtractLane(WasmOpcode opcode, ValueType type, 38481cb0ef41Sopenharmony_ci uint32_t opcode_length) { 38491cb0ef41Sopenharmony_ci SimdLaneImmediate<validate> imm(this, this->pc_ + opcode_length); 38501cb0ef41Sopenharmony_ci if (this->Validate(this->pc_ + opcode_length, opcode, imm)) { 38511cb0ef41Sopenharmony_ci Value inputs[] = {Peek(0, 0, kWasmS128)}; 38521cb0ef41Sopenharmony_ci Value result = CreateValue(type); 38531cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(SimdLaneOp, opcode, imm, 38541cb0ef41Sopenharmony_ci base::ArrayVector(inputs), &result); 38551cb0ef41Sopenharmony_ci Drop(1); 38561cb0ef41Sopenharmony_ci Push(result); 38571cb0ef41Sopenharmony_ci } 38581cb0ef41Sopenharmony_ci return opcode_length + imm.length; 38591cb0ef41Sopenharmony_ci } 38601cb0ef41Sopenharmony_ci 38611cb0ef41Sopenharmony_ci uint32_t SimdReplaceLane(WasmOpcode opcode, ValueType type, 38621cb0ef41Sopenharmony_ci uint32_t opcode_length) { 38631cb0ef41Sopenharmony_ci SimdLaneImmediate<validate> imm(this, this->pc_ + opcode_length); 38641cb0ef41Sopenharmony_ci if (this->Validate(this->pc_ + opcode_length, opcode, imm)) { 38651cb0ef41Sopenharmony_ci Value inputs[2] = {Peek(1, 0, kWasmS128), Peek(0, 1, type)}; 38661cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmS128); 38671cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(SimdLaneOp, opcode, imm, 38681cb0ef41Sopenharmony_ci base::ArrayVector(inputs), &result); 38691cb0ef41Sopenharmony_ci Drop(2); 38701cb0ef41Sopenharmony_ci Push(result); 38711cb0ef41Sopenharmony_ci } 38721cb0ef41Sopenharmony_ci return opcode_length + imm.length; 38731cb0ef41Sopenharmony_ci } 38741cb0ef41Sopenharmony_ci 38751cb0ef41Sopenharmony_ci uint32_t Simd8x16ShuffleOp(uint32_t opcode_length) { 38761cb0ef41Sopenharmony_ci Simd128Immediate<validate> imm(this, this->pc_ + opcode_length); 38771cb0ef41Sopenharmony_ci if (this->Validate(this->pc_ + opcode_length, imm)) { 38781cb0ef41Sopenharmony_ci Value input1 = Peek(0, 1, kWasmS128); 38791cb0ef41Sopenharmony_ci Value input0 = Peek(1, 0, kWasmS128); 38801cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmS128); 38811cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(Simd8x16ShuffleOp, imm, input0, input1, 38821cb0ef41Sopenharmony_ci &result); 38831cb0ef41Sopenharmony_ci Drop(2); 38841cb0ef41Sopenharmony_ci Push(result); 38851cb0ef41Sopenharmony_ci } 38861cb0ef41Sopenharmony_ci return opcode_length + 16; 38871cb0ef41Sopenharmony_ci } 38881cb0ef41Sopenharmony_ci 38891cb0ef41Sopenharmony_ci uint32_t DecodeSimdOpcode(WasmOpcode opcode, uint32_t opcode_length) { 38901cb0ef41Sopenharmony_ci if (decoding_mode == kInitExpression) { 38911cb0ef41Sopenharmony_ci // Currently, only s128.const is allowed in initializer expressions. 38921cb0ef41Sopenharmony_ci if (opcode != kExprS128Const) { 38931cb0ef41Sopenharmony_ci this->DecodeError("opcode %s is not allowed in init. expressions", 38941cb0ef41Sopenharmony_ci this->SafeOpcodeNameAt(this->pc())); 38951cb0ef41Sopenharmony_ci return 0; 38961cb0ef41Sopenharmony_ci } 38971cb0ef41Sopenharmony_ci return SimdConstOp(opcode_length); 38981cb0ef41Sopenharmony_ci } 38991cb0ef41Sopenharmony_ci // opcode_length is the number of bytes that this SIMD-specific opcode takes 39001cb0ef41Sopenharmony_ci // up in the LEB128 encoded form. 39011cb0ef41Sopenharmony_ci switch (opcode) { 39021cb0ef41Sopenharmony_ci case kExprF64x2ExtractLane: 39031cb0ef41Sopenharmony_ci return SimdExtractLane(opcode, kWasmF64, opcode_length); 39041cb0ef41Sopenharmony_ci case kExprF32x4ExtractLane: 39051cb0ef41Sopenharmony_ci return SimdExtractLane(opcode, kWasmF32, opcode_length); 39061cb0ef41Sopenharmony_ci case kExprI64x2ExtractLane: 39071cb0ef41Sopenharmony_ci return SimdExtractLane(opcode, kWasmI64, opcode_length); 39081cb0ef41Sopenharmony_ci case kExprI32x4ExtractLane: 39091cb0ef41Sopenharmony_ci case kExprI16x8ExtractLaneS: 39101cb0ef41Sopenharmony_ci case kExprI16x8ExtractLaneU: 39111cb0ef41Sopenharmony_ci case kExprI8x16ExtractLaneS: 39121cb0ef41Sopenharmony_ci case kExprI8x16ExtractLaneU: 39131cb0ef41Sopenharmony_ci return SimdExtractLane(opcode, kWasmI32, opcode_length); 39141cb0ef41Sopenharmony_ci case kExprF64x2ReplaceLane: 39151cb0ef41Sopenharmony_ci return SimdReplaceLane(opcode, kWasmF64, opcode_length); 39161cb0ef41Sopenharmony_ci case kExprF32x4ReplaceLane: 39171cb0ef41Sopenharmony_ci return SimdReplaceLane(opcode, kWasmF32, opcode_length); 39181cb0ef41Sopenharmony_ci case kExprI64x2ReplaceLane: 39191cb0ef41Sopenharmony_ci return SimdReplaceLane(opcode, kWasmI64, opcode_length); 39201cb0ef41Sopenharmony_ci case kExprI32x4ReplaceLane: 39211cb0ef41Sopenharmony_ci case kExprI16x8ReplaceLane: 39221cb0ef41Sopenharmony_ci case kExprI8x16ReplaceLane: 39231cb0ef41Sopenharmony_ci return SimdReplaceLane(opcode, kWasmI32, opcode_length); 39241cb0ef41Sopenharmony_ci case kExprI8x16Shuffle: 39251cb0ef41Sopenharmony_ci return Simd8x16ShuffleOp(opcode_length); 39261cb0ef41Sopenharmony_ci case kExprS128LoadMem: 39271cb0ef41Sopenharmony_ci return DecodeLoadMem(LoadType::kS128Load, opcode_length); 39281cb0ef41Sopenharmony_ci case kExprS128StoreMem: 39291cb0ef41Sopenharmony_ci return DecodeStoreMem(StoreType::kS128Store, opcode_length); 39301cb0ef41Sopenharmony_ci case kExprS128Load32Zero: 39311cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI32Load, 39321cb0ef41Sopenharmony_ci LoadTransformationKind::kZeroExtend, 39331cb0ef41Sopenharmony_ci opcode_length); 39341cb0ef41Sopenharmony_ci case kExprS128Load64Zero: 39351cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI64Load, 39361cb0ef41Sopenharmony_ci LoadTransformationKind::kZeroExtend, 39371cb0ef41Sopenharmony_ci opcode_length); 39381cb0ef41Sopenharmony_ci case kExprS128Load8Splat: 39391cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI32Load8S, 39401cb0ef41Sopenharmony_ci LoadTransformationKind::kSplat, 39411cb0ef41Sopenharmony_ci opcode_length); 39421cb0ef41Sopenharmony_ci case kExprS128Load16Splat: 39431cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI32Load16S, 39441cb0ef41Sopenharmony_ci LoadTransformationKind::kSplat, 39451cb0ef41Sopenharmony_ci opcode_length); 39461cb0ef41Sopenharmony_ci case kExprS128Load32Splat: 39471cb0ef41Sopenharmony_ci return DecodeLoadTransformMem( 39481cb0ef41Sopenharmony_ci LoadType::kI32Load, LoadTransformationKind::kSplat, opcode_length); 39491cb0ef41Sopenharmony_ci case kExprS128Load64Splat: 39501cb0ef41Sopenharmony_ci return DecodeLoadTransformMem( 39511cb0ef41Sopenharmony_ci LoadType::kI64Load, LoadTransformationKind::kSplat, opcode_length); 39521cb0ef41Sopenharmony_ci case kExprS128Load8x8S: 39531cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI32Load8S, 39541cb0ef41Sopenharmony_ci LoadTransformationKind::kExtend, 39551cb0ef41Sopenharmony_ci opcode_length); 39561cb0ef41Sopenharmony_ci case kExprS128Load8x8U: 39571cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI32Load8U, 39581cb0ef41Sopenharmony_ci LoadTransformationKind::kExtend, 39591cb0ef41Sopenharmony_ci opcode_length); 39601cb0ef41Sopenharmony_ci case kExprS128Load16x4S: 39611cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI32Load16S, 39621cb0ef41Sopenharmony_ci LoadTransformationKind::kExtend, 39631cb0ef41Sopenharmony_ci opcode_length); 39641cb0ef41Sopenharmony_ci case kExprS128Load16x4U: 39651cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI32Load16U, 39661cb0ef41Sopenharmony_ci LoadTransformationKind::kExtend, 39671cb0ef41Sopenharmony_ci opcode_length); 39681cb0ef41Sopenharmony_ci case kExprS128Load32x2S: 39691cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI64Load32S, 39701cb0ef41Sopenharmony_ci LoadTransformationKind::kExtend, 39711cb0ef41Sopenharmony_ci opcode_length); 39721cb0ef41Sopenharmony_ci case kExprS128Load32x2U: 39731cb0ef41Sopenharmony_ci return DecodeLoadTransformMem(LoadType::kI64Load32U, 39741cb0ef41Sopenharmony_ci LoadTransformationKind::kExtend, 39751cb0ef41Sopenharmony_ci opcode_length); 39761cb0ef41Sopenharmony_ci case kExprS128Load8Lane: { 39771cb0ef41Sopenharmony_ci return DecodeLoadLane(opcode, LoadType::kI32Load8S, opcode_length); 39781cb0ef41Sopenharmony_ci } 39791cb0ef41Sopenharmony_ci case kExprS128Load16Lane: { 39801cb0ef41Sopenharmony_ci return DecodeLoadLane(opcode, LoadType::kI32Load16S, opcode_length); 39811cb0ef41Sopenharmony_ci } 39821cb0ef41Sopenharmony_ci case kExprS128Load32Lane: { 39831cb0ef41Sopenharmony_ci return DecodeLoadLane(opcode, LoadType::kI32Load, opcode_length); 39841cb0ef41Sopenharmony_ci } 39851cb0ef41Sopenharmony_ci case kExprS128Load64Lane: { 39861cb0ef41Sopenharmony_ci return DecodeLoadLane(opcode, LoadType::kI64Load, opcode_length); 39871cb0ef41Sopenharmony_ci } 39881cb0ef41Sopenharmony_ci case kExprS128Store8Lane: { 39891cb0ef41Sopenharmony_ci return DecodeStoreLane(opcode, StoreType::kI32Store8, opcode_length); 39901cb0ef41Sopenharmony_ci } 39911cb0ef41Sopenharmony_ci case kExprS128Store16Lane: { 39921cb0ef41Sopenharmony_ci return DecodeStoreLane(opcode, StoreType::kI32Store16, opcode_length); 39931cb0ef41Sopenharmony_ci } 39941cb0ef41Sopenharmony_ci case kExprS128Store32Lane: { 39951cb0ef41Sopenharmony_ci return DecodeStoreLane(opcode, StoreType::kI32Store, opcode_length); 39961cb0ef41Sopenharmony_ci } 39971cb0ef41Sopenharmony_ci case kExprS128Store64Lane: { 39981cb0ef41Sopenharmony_ci return DecodeStoreLane(opcode, StoreType::kI64Store, opcode_length); 39991cb0ef41Sopenharmony_ci } 40001cb0ef41Sopenharmony_ci case kExprS128Const: 40011cb0ef41Sopenharmony_ci return SimdConstOp(opcode_length); 40021cb0ef41Sopenharmony_ci default: { 40031cb0ef41Sopenharmony_ci const FunctionSig* sig = WasmOpcodes::Signature(opcode); 40041cb0ef41Sopenharmony_ci if (!VALIDATE(sig != nullptr)) { 40051cb0ef41Sopenharmony_ci this->DecodeError("invalid simd opcode"); 40061cb0ef41Sopenharmony_ci return 0; 40071cb0ef41Sopenharmony_ci } 40081cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(sig); 40091cb0ef41Sopenharmony_ci if (sig->return_count() == 0) { 40101cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(SimdOp, opcode, 40111cb0ef41Sopenharmony_ci base::VectorOf(args), nullptr); 40121cb0ef41Sopenharmony_ci DropArgs(sig); 40131cb0ef41Sopenharmony_ci } else { 40141cb0ef41Sopenharmony_ci ReturnVector results = CreateReturnValues(sig); 40151cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE( 40161cb0ef41Sopenharmony_ci SimdOp, opcode, base::VectorOf(args), results.begin()); 40171cb0ef41Sopenharmony_ci DropArgs(sig); 40181cb0ef41Sopenharmony_ci PushReturns(results); 40191cb0ef41Sopenharmony_ci } 40201cb0ef41Sopenharmony_ci return opcode_length; 40211cb0ef41Sopenharmony_ci } 40221cb0ef41Sopenharmony_ci } 40231cb0ef41Sopenharmony_ci } 40241cb0ef41Sopenharmony_ci 40251cb0ef41Sopenharmony_ci // Checks if types are unrelated, thus type checking will always fail. Does 40261cb0ef41Sopenharmony_ci // not account for nullability. 40271cb0ef41Sopenharmony_ci bool TypeCheckAlwaysFails(Value obj, Value rtt) { 40281cb0ef41Sopenharmony_ci return !IsSubtypeOf(ValueType::Ref(rtt.type.ref_index(), kNonNullable), 40291cb0ef41Sopenharmony_ci obj.type, this->module_) && 40301cb0ef41Sopenharmony_ci !IsSubtypeOf(obj.type, 40311cb0ef41Sopenharmony_ci ValueType::Ref(rtt.type.ref_index(), kNullable), 40321cb0ef41Sopenharmony_ci this->module_); 40331cb0ef41Sopenharmony_ci } 40341cb0ef41Sopenharmony_ci 40351cb0ef41Sopenharmony_ci // Checks it {obj} is a nominal type which is a subtype of {rtt}'s index, thus 40361cb0ef41Sopenharmony_ci // checking will always succeed. Does not account for nullability. 40371cb0ef41Sopenharmony_ci bool TypeCheckAlwaysSucceeds(Value obj, Value rtt) { 40381cb0ef41Sopenharmony_ci return obj.type.has_index() && 40391cb0ef41Sopenharmony_ci this->module_->has_supertype(obj.type.ref_index()) && 40401cb0ef41Sopenharmony_ci IsSubtypeOf(obj.type, 40411cb0ef41Sopenharmony_ci ValueType::Ref(rtt.type.ref_index(), kNullable), 40421cb0ef41Sopenharmony_ci this->module_); 40431cb0ef41Sopenharmony_ci } 40441cb0ef41Sopenharmony_ci 40451cb0ef41Sopenharmony_ci#define NON_CONST_ONLY \ 40461cb0ef41Sopenharmony_ci if (decoding_mode == kInitExpression) { \ 40471cb0ef41Sopenharmony_ci this->DecodeError("opcode %s is not allowed in init. expressions", \ 40481cb0ef41Sopenharmony_ci this->SafeOpcodeNameAt(this->pc())); \ 40491cb0ef41Sopenharmony_ci return 0; \ 40501cb0ef41Sopenharmony_ci } 40511cb0ef41Sopenharmony_ci 40521cb0ef41Sopenharmony_ci int DecodeGCOpcode(WasmOpcode opcode, uint32_t opcode_length) { 40531cb0ef41Sopenharmony_ci switch (opcode) { 40541cb0ef41Sopenharmony_ci case kExprStructNew: 40551cb0ef41Sopenharmony_ci case kExprStructNewWithRtt: { 40561cb0ef41Sopenharmony_ci StructIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 40571cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 40581cb0ef41Sopenharmony_ci ValueType rtt_type = ValueType::Rtt(imm.index); 40591cb0ef41Sopenharmony_ci Value rtt = opcode == kExprStructNew 40601cb0ef41Sopenharmony_ci ? CreateValue(rtt_type) 40611cb0ef41Sopenharmony_ci : Peek(0, imm.struct_type->field_count(), rtt_type); 40621cb0ef41Sopenharmony_ci if (opcode == kExprStructNew) { 40631cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 40641cb0ef41Sopenharmony_ci Push(rtt); 40651cb0ef41Sopenharmony_ci } 40661cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(imm.struct_type, 1); 40671cb0ef41Sopenharmony_ci Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable)); 40681cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(StructNewWithRtt, imm, rtt, 40691cb0ef41Sopenharmony_ci args.begin(), &value); 40701cb0ef41Sopenharmony_ci Drop(rtt); 40711cb0ef41Sopenharmony_ci DropArgs(imm.struct_type); 40721cb0ef41Sopenharmony_ci Push(value); 40731cb0ef41Sopenharmony_ci return opcode_length + imm.length; 40741cb0ef41Sopenharmony_ci } 40751cb0ef41Sopenharmony_ci case kExprStructNewDefault: 40761cb0ef41Sopenharmony_ci case kExprStructNewDefaultWithRtt: { 40771cb0ef41Sopenharmony_ci StructIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 40781cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 40791cb0ef41Sopenharmony_ci if (validate) { 40801cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < imm.struct_type->field_count(); i++) { 40811cb0ef41Sopenharmony_ci ValueType ftype = imm.struct_type->field(i); 40821cb0ef41Sopenharmony_ci if (!VALIDATE(ftype.is_defaultable())) { 40831cb0ef41Sopenharmony_ci this->DecodeError( 40841cb0ef41Sopenharmony_ci "%s: struct type %d has field %d of non-defaultable type %s", 40851cb0ef41Sopenharmony_ci WasmOpcodes::OpcodeName(opcode), imm.index, i, 40861cb0ef41Sopenharmony_ci ftype.name().c_str()); 40871cb0ef41Sopenharmony_ci return 0; 40881cb0ef41Sopenharmony_ci } 40891cb0ef41Sopenharmony_ci } 40901cb0ef41Sopenharmony_ci } 40911cb0ef41Sopenharmony_ci ValueType rtt_type = ValueType::Rtt(imm.index); 40921cb0ef41Sopenharmony_ci Value rtt = opcode == kExprStructNewDefault ? CreateValue(rtt_type) 40931cb0ef41Sopenharmony_ci : Peek(0, 0, rtt_type); 40941cb0ef41Sopenharmony_ci if (opcode == kExprStructNewDefault) { 40951cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 40961cb0ef41Sopenharmony_ci Push(rtt); 40971cb0ef41Sopenharmony_ci } 40981cb0ef41Sopenharmony_ci Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable)); 40991cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(StructNewDefault, imm, rtt, &value); 41001cb0ef41Sopenharmony_ci Drop(rtt); 41011cb0ef41Sopenharmony_ci Push(value); 41021cb0ef41Sopenharmony_ci return opcode_length + imm.length; 41031cb0ef41Sopenharmony_ci } 41041cb0ef41Sopenharmony_ci case kExprStructGet: { 41051cb0ef41Sopenharmony_ci NON_CONST_ONLY 41061cb0ef41Sopenharmony_ci FieldImmediate<validate> field(this, this->pc_ + opcode_length); 41071cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, field)) return 0; 41081cb0ef41Sopenharmony_ci ValueType field_type = 41091cb0ef41Sopenharmony_ci field.struct_imm.struct_type->field(field.field_imm.index); 41101cb0ef41Sopenharmony_ci if (!VALIDATE(!field_type.is_packed())) { 41111cb0ef41Sopenharmony_ci this->DecodeError( 41121cb0ef41Sopenharmony_ci "struct.get: Immediate field %d of type %d has packed type %s. " 41131cb0ef41Sopenharmony_ci "Use struct.get_s or struct.get_u instead.", 41141cb0ef41Sopenharmony_ci field.field_imm.index, field.struct_imm.index, 41151cb0ef41Sopenharmony_ci field_type.name().c_str()); 41161cb0ef41Sopenharmony_ci return 0; 41171cb0ef41Sopenharmony_ci } 41181cb0ef41Sopenharmony_ci Value struct_obj = 41191cb0ef41Sopenharmony_ci Peek(0, 0, ValueType::Ref(field.struct_imm.index, kNullable)); 41201cb0ef41Sopenharmony_ci Value value = CreateValue(field_type); 41211cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(StructGet, struct_obj, field, true, 41221cb0ef41Sopenharmony_ci &value); 41231cb0ef41Sopenharmony_ci Drop(struct_obj); 41241cb0ef41Sopenharmony_ci Push(value); 41251cb0ef41Sopenharmony_ci return opcode_length + field.length; 41261cb0ef41Sopenharmony_ci } 41271cb0ef41Sopenharmony_ci case kExprStructGetU: 41281cb0ef41Sopenharmony_ci case kExprStructGetS: { 41291cb0ef41Sopenharmony_ci NON_CONST_ONLY 41301cb0ef41Sopenharmony_ci FieldImmediate<validate> field(this, this->pc_ + opcode_length); 41311cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, field)) return 0; 41321cb0ef41Sopenharmony_ci ValueType field_type = 41331cb0ef41Sopenharmony_ci field.struct_imm.struct_type->field(field.field_imm.index); 41341cb0ef41Sopenharmony_ci if (!VALIDATE(field_type.is_packed())) { 41351cb0ef41Sopenharmony_ci this->DecodeError( 41361cb0ef41Sopenharmony_ci "%s: Immediate field %d of type %d has non-packed type %s. Use " 41371cb0ef41Sopenharmony_ci "struct.get instead.", 41381cb0ef41Sopenharmony_ci WasmOpcodes::OpcodeName(opcode), field.field_imm.index, 41391cb0ef41Sopenharmony_ci field.struct_imm.index, field_type.name().c_str()); 41401cb0ef41Sopenharmony_ci return 0; 41411cb0ef41Sopenharmony_ci } 41421cb0ef41Sopenharmony_ci Value struct_obj = 41431cb0ef41Sopenharmony_ci Peek(0, 0, ValueType::Ref(field.struct_imm.index, kNullable)); 41441cb0ef41Sopenharmony_ci Value value = CreateValue(field_type.Unpacked()); 41451cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(StructGet, struct_obj, field, 41461cb0ef41Sopenharmony_ci opcode == kExprStructGetS, &value); 41471cb0ef41Sopenharmony_ci Drop(struct_obj); 41481cb0ef41Sopenharmony_ci Push(value); 41491cb0ef41Sopenharmony_ci return opcode_length + field.length; 41501cb0ef41Sopenharmony_ci } 41511cb0ef41Sopenharmony_ci case kExprStructSet: { 41521cb0ef41Sopenharmony_ci NON_CONST_ONLY 41531cb0ef41Sopenharmony_ci FieldImmediate<validate> field(this, this->pc_ + opcode_length); 41541cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, field)) return 0; 41551cb0ef41Sopenharmony_ci const StructType* struct_type = field.struct_imm.struct_type; 41561cb0ef41Sopenharmony_ci if (!VALIDATE(struct_type->mutability(field.field_imm.index))) { 41571cb0ef41Sopenharmony_ci this->DecodeError("struct.set: Field %d of type %d is immutable.", 41581cb0ef41Sopenharmony_ci field.field_imm.index, field.struct_imm.index); 41591cb0ef41Sopenharmony_ci return 0; 41601cb0ef41Sopenharmony_ci } 41611cb0ef41Sopenharmony_ci Value field_value = 41621cb0ef41Sopenharmony_ci Peek(0, 1, struct_type->field(field.field_imm.index).Unpacked()); 41631cb0ef41Sopenharmony_ci Value struct_obj = 41641cb0ef41Sopenharmony_ci Peek(1, 0, ValueType::Ref(field.struct_imm.index, kNullable)); 41651cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(StructSet, struct_obj, field, 41661cb0ef41Sopenharmony_ci field_value); 41671cb0ef41Sopenharmony_ci Drop(2); 41681cb0ef41Sopenharmony_ci return opcode_length + field.length; 41691cb0ef41Sopenharmony_ci } 41701cb0ef41Sopenharmony_ci case kExprArrayNew: 41711cb0ef41Sopenharmony_ci case kExprArrayNewWithRtt: { 41721cb0ef41Sopenharmony_ci NON_CONST_ONLY 41731cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 41741cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 41751cb0ef41Sopenharmony_ci ValueType rtt_type = ValueType::Rtt(imm.index); 41761cb0ef41Sopenharmony_ci Value rtt = opcode == kExprArrayNew ? CreateValue(rtt_type) 41771cb0ef41Sopenharmony_ci : Peek(0, 2, rtt_type); 41781cb0ef41Sopenharmony_ci if (opcode == kExprArrayNew) { 41791cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 41801cb0ef41Sopenharmony_ci Push(rtt); 41811cb0ef41Sopenharmony_ci } 41821cb0ef41Sopenharmony_ci Value length = Peek(1, 1, kWasmI32); 41831cb0ef41Sopenharmony_ci Value initial_value = 41841cb0ef41Sopenharmony_ci Peek(2, 0, imm.array_type->element_type().Unpacked()); 41851cb0ef41Sopenharmony_ci Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable)); 41861cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayNewWithRtt, imm, length, 41871cb0ef41Sopenharmony_ci initial_value, rtt, &value); 41881cb0ef41Sopenharmony_ci Drop(3); // rtt, length, initial_value. 41891cb0ef41Sopenharmony_ci Push(value); 41901cb0ef41Sopenharmony_ci return opcode_length + imm.length; 41911cb0ef41Sopenharmony_ci } 41921cb0ef41Sopenharmony_ci case kExprArrayNewDefault: 41931cb0ef41Sopenharmony_ci case kExprArrayNewDefaultWithRtt: { 41941cb0ef41Sopenharmony_ci NON_CONST_ONLY 41951cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 41961cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 41971cb0ef41Sopenharmony_ci if (!VALIDATE(imm.array_type->element_type().is_defaultable())) { 41981cb0ef41Sopenharmony_ci this->DecodeError( 41991cb0ef41Sopenharmony_ci "%s: array type %d has non-defaultable element type %s", 42001cb0ef41Sopenharmony_ci WasmOpcodes::OpcodeName(opcode), imm.index, 42011cb0ef41Sopenharmony_ci imm.array_type->element_type().name().c_str()); 42021cb0ef41Sopenharmony_ci return 0; 42031cb0ef41Sopenharmony_ci } 42041cb0ef41Sopenharmony_ci ValueType rtt_type = ValueType::Rtt(imm.index); 42051cb0ef41Sopenharmony_ci Value rtt = opcode == kExprArrayNewDefault ? CreateValue(rtt_type) 42061cb0ef41Sopenharmony_ci : Peek(0, 1, rtt_type); 42071cb0ef41Sopenharmony_ci if (opcode == kExprArrayNewDefault) { 42081cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 42091cb0ef41Sopenharmony_ci Push(rtt); 42101cb0ef41Sopenharmony_ci } 42111cb0ef41Sopenharmony_ci Value length = Peek(1, 0, kWasmI32); 42121cb0ef41Sopenharmony_ci Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable)); 42131cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayNewDefault, imm, length, rtt, 42141cb0ef41Sopenharmony_ci &value); 42151cb0ef41Sopenharmony_ci Drop(2); // rtt, length 42161cb0ef41Sopenharmony_ci Push(value); 42171cb0ef41Sopenharmony_ci return opcode_length + imm.length; 42181cb0ef41Sopenharmony_ci } 42191cb0ef41Sopenharmony_ci case kExprArrayInitFromData: 42201cb0ef41Sopenharmony_ci case kExprArrayInitFromDataStatic: { 42211cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> array_imm(this, 42221cb0ef41Sopenharmony_ci this->pc_ + opcode_length); 42231cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, array_imm)) return 0; 42241cb0ef41Sopenharmony_ci ValueType element_type = array_imm.array_type->element_type(); 42251cb0ef41Sopenharmony_ci if (element_type.is_reference()) { 42261cb0ef41Sopenharmony_ci this->DecodeError( 42271cb0ef41Sopenharmony_ci "array.init_from_data can only be used with value-type arrays, " 42281cb0ef41Sopenharmony_ci "found array type #%d instead", 42291cb0ef41Sopenharmony_ci array_imm.index); 42301cb0ef41Sopenharmony_ci return 0; 42311cb0ef41Sopenharmony_ci } 42321cb0ef41Sopenharmony_ci#if V8_TARGET_BIG_ENDIAN 42331cb0ef41Sopenharmony_ci // Byte sequences in data segments are interpreted as little endian for 42341cb0ef41Sopenharmony_ci // the purposes of this instruction. This means that those will have to 42351cb0ef41Sopenharmony_ci // be transformed in big endian architectures. TODO(7748): Implement. 42361cb0ef41Sopenharmony_ci if (element_type.value_kind_size() > 1) { 42371cb0ef41Sopenharmony_ci UNIMPLEMENTED(); 42381cb0ef41Sopenharmony_ci } 42391cb0ef41Sopenharmony_ci#endif 42401cb0ef41Sopenharmony_ci const byte* data_index_pc = 42411cb0ef41Sopenharmony_ci this->pc_ + opcode_length + array_imm.length; 42421cb0ef41Sopenharmony_ci IndexImmediate<validate> data_segment(this, data_index_pc, 42431cb0ef41Sopenharmony_ci "data segment"); 42441cb0ef41Sopenharmony_ci if (!this->ValidateDataSegment(data_index_pc, data_segment)) return 0; 42451cb0ef41Sopenharmony_ci 42461cb0ef41Sopenharmony_ci ValueType rtt_type = ValueType::Rtt(array_imm.index); 42471cb0ef41Sopenharmony_ci Value rtt = opcode == kExprArrayInitFromDataStatic 42481cb0ef41Sopenharmony_ci ? CreateValue(rtt_type) 42491cb0ef41Sopenharmony_ci : Peek(0, 2, rtt_type); 42501cb0ef41Sopenharmony_ci if (opcode == kExprArrayInitFromDataStatic) { 42511cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, array_imm.index, &rtt); 42521cb0ef41Sopenharmony_ci Push(rtt); 42531cb0ef41Sopenharmony_ci } 42541cb0ef41Sopenharmony_ci 42551cb0ef41Sopenharmony_ci Value length = Peek(1, 1, kWasmI32); 42561cb0ef41Sopenharmony_ci Value offset = Peek(2, 0, kWasmI32); 42571cb0ef41Sopenharmony_ci 42581cb0ef41Sopenharmony_ci Value array = 42591cb0ef41Sopenharmony_ci CreateValue(ValueType::Ref(array_imm.index, kNonNullable)); 42601cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayInitFromData, array_imm, 42611cb0ef41Sopenharmony_ci data_segment, offset, length, rtt, 42621cb0ef41Sopenharmony_ci &array); 42631cb0ef41Sopenharmony_ci Drop(3); // rtt, length, offset 42641cb0ef41Sopenharmony_ci Push(array); 42651cb0ef41Sopenharmony_ci return opcode_length + array_imm.length + data_segment.length; 42661cb0ef41Sopenharmony_ci } 42671cb0ef41Sopenharmony_ci case kExprArrayGetS: 42681cb0ef41Sopenharmony_ci case kExprArrayGetU: { 42691cb0ef41Sopenharmony_ci NON_CONST_ONLY 42701cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 42711cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 42721cb0ef41Sopenharmony_ci if (!VALIDATE(imm.array_type->element_type().is_packed())) { 42731cb0ef41Sopenharmony_ci this->DecodeError( 42741cb0ef41Sopenharmony_ci "%s: Immediate array type %d has non-packed type %s. Use " 42751cb0ef41Sopenharmony_ci "array.get instead.", 42761cb0ef41Sopenharmony_ci WasmOpcodes::OpcodeName(opcode), imm.index, 42771cb0ef41Sopenharmony_ci imm.array_type->element_type().name().c_str()); 42781cb0ef41Sopenharmony_ci return 0; 42791cb0ef41Sopenharmony_ci } 42801cb0ef41Sopenharmony_ci Value index = Peek(0, 1, kWasmI32); 42811cb0ef41Sopenharmony_ci Value array_obj = Peek(1, 0, ValueType::Ref(imm.index, kNullable)); 42821cb0ef41Sopenharmony_ci Value value = CreateValue(imm.array_type->element_type().Unpacked()); 42831cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayGet, array_obj, imm, index, 42841cb0ef41Sopenharmony_ci opcode == kExprArrayGetS, &value); 42851cb0ef41Sopenharmony_ci Drop(2); // index, array_obj 42861cb0ef41Sopenharmony_ci Push(value); 42871cb0ef41Sopenharmony_ci return opcode_length + imm.length; 42881cb0ef41Sopenharmony_ci } 42891cb0ef41Sopenharmony_ci case kExprArrayGet: { 42901cb0ef41Sopenharmony_ci NON_CONST_ONLY 42911cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 42921cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 42931cb0ef41Sopenharmony_ci if (!VALIDATE(!imm.array_type->element_type().is_packed())) { 42941cb0ef41Sopenharmony_ci this->DecodeError( 42951cb0ef41Sopenharmony_ci "array.get: Immediate array type %d has packed type %s. Use " 42961cb0ef41Sopenharmony_ci "array.get_s or array.get_u instead.", 42971cb0ef41Sopenharmony_ci imm.index, imm.array_type->element_type().name().c_str()); 42981cb0ef41Sopenharmony_ci return 0; 42991cb0ef41Sopenharmony_ci } 43001cb0ef41Sopenharmony_ci Value index = Peek(0, 1, kWasmI32); 43011cb0ef41Sopenharmony_ci Value array_obj = Peek(1, 0, ValueType::Ref(imm.index, kNullable)); 43021cb0ef41Sopenharmony_ci Value value = CreateValue(imm.array_type->element_type()); 43031cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayGet, array_obj, imm, index, 43041cb0ef41Sopenharmony_ci true, &value); 43051cb0ef41Sopenharmony_ci Drop(2); // index, array_obj 43061cb0ef41Sopenharmony_ci Push(value); 43071cb0ef41Sopenharmony_ci return opcode_length + imm.length; 43081cb0ef41Sopenharmony_ci } 43091cb0ef41Sopenharmony_ci case kExprArraySet: { 43101cb0ef41Sopenharmony_ci NON_CONST_ONLY 43111cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 43121cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 43131cb0ef41Sopenharmony_ci if (!VALIDATE(imm.array_type->mutability())) { 43141cb0ef41Sopenharmony_ci this->DecodeError("array.set: immediate array type %d is immutable", 43151cb0ef41Sopenharmony_ci imm.index); 43161cb0ef41Sopenharmony_ci return 0; 43171cb0ef41Sopenharmony_ci } 43181cb0ef41Sopenharmony_ci Value value = Peek(0, 2, imm.array_type->element_type().Unpacked()); 43191cb0ef41Sopenharmony_ci Value index = Peek(1, 1, kWasmI32); 43201cb0ef41Sopenharmony_ci Value array_obj = Peek(2, 0, ValueType::Ref(imm.index, kNullable)); 43211cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArraySet, array_obj, imm, index, 43221cb0ef41Sopenharmony_ci value); 43231cb0ef41Sopenharmony_ci Drop(3); 43241cb0ef41Sopenharmony_ci return opcode_length + imm.length; 43251cb0ef41Sopenharmony_ci } 43261cb0ef41Sopenharmony_ci case kExprArrayLen: { 43271cb0ef41Sopenharmony_ci NON_CONST_ONLY 43281cb0ef41Sopenharmony_ci // Read but ignore an immediate array type index. 43291cb0ef41Sopenharmony_ci // TODO(7748): Remove this once we are ready to make breaking changes. 43301cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 43311cb0ef41Sopenharmony_ci Value array_obj = 43321cb0ef41Sopenharmony_ci Peek(0, 0, ValueType::Ref(HeapType::kArray, kNullable)); 43331cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmI32); 43341cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayLen, array_obj, &value); 43351cb0ef41Sopenharmony_ci Drop(array_obj); 43361cb0ef41Sopenharmony_ci Push(value); 43371cb0ef41Sopenharmony_ci return opcode_length + imm.length; 43381cb0ef41Sopenharmony_ci } 43391cb0ef41Sopenharmony_ci case kExprArrayCopy: { 43401cb0ef41Sopenharmony_ci NON_CONST_ONLY 43411cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> dst_imm(this, this->pc_ + opcode_length); 43421cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, dst_imm)) return 0; 43431cb0ef41Sopenharmony_ci if (!VALIDATE(dst_imm.array_type->mutability())) { 43441cb0ef41Sopenharmony_ci this->DecodeError( 43451cb0ef41Sopenharmony_ci "array.copy: immediate destination array type #%d is immutable", 43461cb0ef41Sopenharmony_ci dst_imm.index); 43471cb0ef41Sopenharmony_ci return 0; 43481cb0ef41Sopenharmony_ci } 43491cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> src_imm( 43501cb0ef41Sopenharmony_ci this, this->pc_ + opcode_length + dst_imm.length); 43511cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length + dst_imm.length, 43521cb0ef41Sopenharmony_ci src_imm)) { 43531cb0ef41Sopenharmony_ci return 0; 43541cb0ef41Sopenharmony_ci } 43551cb0ef41Sopenharmony_ci if (!IsSubtypeOf(src_imm.array_type->element_type(), 43561cb0ef41Sopenharmony_ci dst_imm.array_type->element_type(), this->module_)) { 43571cb0ef41Sopenharmony_ci this->DecodeError( 43581cb0ef41Sopenharmony_ci "array.copy: source array's #%d element type is not a subtype of " 43591cb0ef41Sopenharmony_ci "destination array's #%d element type", 43601cb0ef41Sopenharmony_ci src_imm.index, dst_imm.index); 43611cb0ef41Sopenharmony_ci return 0; 43621cb0ef41Sopenharmony_ci } 43631cb0ef41Sopenharmony_ci // [dst, dst_index, src, src_index, length] 43641cb0ef41Sopenharmony_ci Value dst = Peek(4, 0, ValueType::Ref(dst_imm.index, kNullable)); 43651cb0ef41Sopenharmony_ci Value dst_index = Peek(3, 1, kWasmI32); 43661cb0ef41Sopenharmony_ci Value src = Peek(2, 2, ValueType::Ref(src_imm.index, kNullable)); 43671cb0ef41Sopenharmony_ci Value src_index = Peek(1, 3, kWasmI32); 43681cb0ef41Sopenharmony_ci Value length = Peek(0, 4, kWasmI32); 43691cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayCopy, dst, dst_index, src, 43701cb0ef41Sopenharmony_ci src_index, length); 43711cb0ef41Sopenharmony_ci Drop(5); 43721cb0ef41Sopenharmony_ci return opcode_length + dst_imm.length + src_imm.length; 43731cb0ef41Sopenharmony_ci } 43741cb0ef41Sopenharmony_ci case kExprArrayInit: 43751cb0ef41Sopenharmony_ci case kExprArrayInitStatic: { 43761cb0ef41Sopenharmony_ci ArrayIndexImmediate<validate> array_imm(this, 43771cb0ef41Sopenharmony_ci this->pc_ + opcode_length); 43781cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, array_imm)) return 0; 43791cb0ef41Sopenharmony_ci IndexImmediate<validate> length_imm( 43801cb0ef41Sopenharmony_ci this, this->pc_ + opcode_length + array_imm.length, 43811cb0ef41Sopenharmony_ci "array.init length"); 43821cb0ef41Sopenharmony_ci uint32_t elem_count = length_imm.index; 43831cb0ef41Sopenharmony_ci if (!VALIDATE(elem_count <= kV8MaxWasmArrayInitLength)) { 43841cb0ef41Sopenharmony_ci this->DecodeError( 43851cb0ef41Sopenharmony_ci "Requested length %u for array.init too large, maximum is %zu", 43861cb0ef41Sopenharmony_ci length_imm.index, kV8MaxWasmArrayInitLength); 43871cb0ef41Sopenharmony_ci return 0; 43881cb0ef41Sopenharmony_ci } 43891cb0ef41Sopenharmony_ci Value rtt = opcode == kExprArrayInit 43901cb0ef41Sopenharmony_ci ? Peek(0, elem_count, ValueType::Rtt(array_imm.index)) 43911cb0ef41Sopenharmony_ci : CreateValue(ValueType::Rtt(array_imm.index)); 43921cb0ef41Sopenharmony_ci if (opcode == kExprArrayInitStatic) { 43931cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, array_imm.index, &rtt); 43941cb0ef41Sopenharmony_ci Push(rtt); 43951cb0ef41Sopenharmony_ci } 43961cb0ef41Sopenharmony_ci ValueType element_type = array_imm.array_type->element_type(); 43971cb0ef41Sopenharmony_ci std::vector<ValueType> element_types(elem_count, 43981cb0ef41Sopenharmony_ci element_type.Unpacked()); 43991cb0ef41Sopenharmony_ci FunctionSig element_sig(0, elem_count, element_types.data()); 44001cb0ef41Sopenharmony_ci ArgVector elements = PeekArgs(&element_sig, 1); 44011cb0ef41Sopenharmony_ci Value result = 44021cb0ef41Sopenharmony_ci CreateValue(ValueType::Ref(array_imm.index, kNonNullable)); 44031cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayInit, array_imm, elements, rtt, 44041cb0ef41Sopenharmony_ci &result); 44051cb0ef41Sopenharmony_ci Drop(elem_count + 1); 44061cb0ef41Sopenharmony_ci Push(result); 44071cb0ef41Sopenharmony_ci return opcode_length + array_imm.length + length_imm.length; 44081cb0ef41Sopenharmony_ci } 44091cb0ef41Sopenharmony_ci case kExprI31New: { 44101cb0ef41Sopenharmony_ci NON_CONST_ONLY 44111cb0ef41Sopenharmony_ci Value input = Peek(0, 0, kWasmI32); 44121cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmI31Ref); 44131cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(I31New, input, &value); 44141cb0ef41Sopenharmony_ci Drop(input); 44151cb0ef41Sopenharmony_ci Push(value); 44161cb0ef41Sopenharmony_ci return opcode_length; 44171cb0ef41Sopenharmony_ci } 44181cb0ef41Sopenharmony_ci case kExprI31GetS: { 44191cb0ef41Sopenharmony_ci NON_CONST_ONLY 44201cb0ef41Sopenharmony_ci Value i31 = Peek(0, 0, kWasmI31Ref); 44211cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmI32); 44221cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(I31GetS, i31, &value); 44231cb0ef41Sopenharmony_ci Drop(i31); 44241cb0ef41Sopenharmony_ci Push(value); 44251cb0ef41Sopenharmony_ci return opcode_length; 44261cb0ef41Sopenharmony_ci } 44271cb0ef41Sopenharmony_ci case kExprI31GetU: { 44281cb0ef41Sopenharmony_ci NON_CONST_ONLY 44291cb0ef41Sopenharmony_ci Value i31 = Peek(0, 0, kWasmI31Ref); 44301cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmI32); 44311cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(I31GetU, i31, &value); 44321cb0ef41Sopenharmony_ci Drop(i31); 44331cb0ef41Sopenharmony_ci Push(value); 44341cb0ef41Sopenharmony_ci return opcode_length; 44351cb0ef41Sopenharmony_ci } 44361cb0ef41Sopenharmony_ci case kExprRttCanon: { 44371cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 44381cb0ef41Sopenharmony_ci "type index"); 44391cb0ef41Sopenharmony_ci if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 44401cb0ef41Sopenharmony_ci Value value = CreateValue(ValueType::Rtt(imm.index)); 44411cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &value); 44421cb0ef41Sopenharmony_ci Push(value); 44431cb0ef41Sopenharmony_ci return opcode_length + imm.length; 44441cb0ef41Sopenharmony_ci } 44451cb0ef41Sopenharmony_ci case kExprRefTest: 44461cb0ef41Sopenharmony_ci case kExprRefTestStatic: { 44471cb0ef41Sopenharmony_ci NON_CONST_ONLY 44481cb0ef41Sopenharmony_ci // "Tests whether {obj}'s runtime type is a runtime subtype of {rtt}." 44491cb0ef41Sopenharmony_ci Value rtt = Peek(0); // This is safe for the ...Static instruction. 44501cb0ef41Sopenharmony_ci if (opcode == kExprRefTestStatic) { 44511cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 44521cb0ef41Sopenharmony_ci "type index"); 44531cb0ef41Sopenharmony_ci if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 44541cb0ef41Sopenharmony_ci opcode_length += imm.length; 44551cb0ef41Sopenharmony_ci rtt = CreateValue(ValueType::Rtt(imm.index)); 44561cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 44571cb0ef41Sopenharmony_ci Push(rtt); 44581cb0ef41Sopenharmony_ci } else { 44591cb0ef41Sopenharmony_ci DCHECK_EQ(opcode, kExprRefTest); 44601cb0ef41Sopenharmony_ci if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) { 44611cb0ef41Sopenharmony_ci PopTypeError(1, rtt, "rtt"); 44621cb0ef41Sopenharmony_ci return 0; 44631cb0ef41Sopenharmony_ci } 44641cb0ef41Sopenharmony_ci } 44651cb0ef41Sopenharmony_ci Value obj = Peek(1); 44661cb0ef41Sopenharmony_ci Value value = CreateValue(kWasmI32); 44671cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) || 44681cb0ef41Sopenharmony_ci IsSubtypeOf(obj.type, 44691cb0ef41Sopenharmony_ci ValueType::Ref(HeapType::kData, kNullable), 44701cb0ef41Sopenharmony_ci this->module_) || 44711cb0ef41Sopenharmony_ci obj.type.is_bottom())) { 44721cb0ef41Sopenharmony_ci PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)"); 44731cb0ef41Sopenharmony_ci return 0; 44741cb0ef41Sopenharmony_ci } 44751cb0ef41Sopenharmony_ci if (current_code_reachable_and_ok_) { 44761cb0ef41Sopenharmony_ci // This logic ensures that code generation can assume that functions 44771cb0ef41Sopenharmony_ci // can only be cast to function types, and data objects to data types. 44781cb0ef41Sopenharmony_ci if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) { 44791cb0ef41Sopenharmony_ci // Drop rtt. 44801cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 44811cb0ef41Sopenharmony_ci // Type checking can still fail for null. 44821cb0ef41Sopenharmony_ci if (obj.type.is_nullable()) { 44831cb0ef41Sopenharmony_ci // We abuse ref.as_non_null, which isn't otherwise used as a unary 44841cb0ef41Sopenharmony_ci // operator, as a sentinel for the negation of ref.is_null. 44851cb0ef41Sopenharmony_ci CALL_INTERFACE(UnOp, kExprRefAsNonNull, obj, &value); 44861cb0ef41Sopenharmony_ci } else { 44871cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 44881cb0ef41Sopenharmony_ci CALL_INTERFACE(I32Const, &value, 1); 44891cb0ef41Sopenharmony_ci } 44901cb0ef41Sopenharmony_ci } else if (V8_UNLIKELY(TypeCheckAlwaysFails(obj, rtt))) { 44911cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 44921cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 44931cb0ef41Sopenharmony_ci CALL_INTERFACE(I32Const, &value, 0); 44941cb0ef41Sopenharmony_ci } else { 44951cb0ef41Sopenharmony_ci CALL_INTERFACE(RefTest, obj, rtt, &value); 44961cb0ef41Sopenharmony_ci } 44971cb0ef41Sopenharmony_ci } 44981cb0ef41Sopenharmony_ci Drop(2); 44991cb0ef41Sopenharmony_ci Push(value); 45001cb0ef41Sopenharmony_ci return opcode_length; 45011cb0ef41Sopenharmony_ci } 45021cb0ef41Sopenharmony_ci case kExprRefCast: 45031cb0ef41Sopenharmony_ci case kExprRefCastStatic: { 45041cb0ef41Sopenharmony_ci NON_CONST_ONLY 45051cb0ef41Sopenharmony_ci Value rtt = Peek(0); // This is safe for the ...Static instruction. 45061cb0ef41Sopenharmony_ci if (opcode == kExprRefCastStatic) { 45071cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 45081cb0ef41Sopenharmony_ci "type index"); 45091cb0ef41Sopenharmony_ci if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 45101cb0ef41Sopenharmony_ci opcode_length += imm.length; 45111cb0ef41Sopenharmony_ci rtt = CreateValue(ValueType::Rtt(imm.index)); 45121cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 45131cb0ef41Sopenharmony_ci Push(rtt); 45141cb0ef41Sopenharmony_ci } else { 45151cb0ef41Sopenharmony_ci DCHECK_EQ(opcode, kExprRefCast); 45161cb0ef41Sopenharmony_ci if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) { 45171cb0ef41Sopenharmony_ci PopTypeError(1, rtt, "rtt"); 45181cb0ef41Sopenharmony_ci return 0; 45191cb0ef41Sopenharmony_ci } 45201cb0ef41Sopenharmony_ci } 45211cb0ef41Sopenharmony_ci Value obj = Peek(1); 45221cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) || 45231cb0ef41Sopenharmony_ci IsSubtypeOf(obj.type, 45241cb0ef41Sopenharmony_ci ValueType::Ref(HeapType::kData, kNullable), 45251cb0ef41Sopenharmony_ci this->module_) || 45261cb0ef41Sopenharmony_ci obj.type.is_bottom())) { 45271cb0ef41Sopenharmony_ci PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)"); 45281cb0ef41Sopenharmony_ci return 0; 45291cb0ef41Sopenharmony_ci } 45301cb0ef41Sopenharmony_ci // If either value is bottom, we emit the most specific type possible. 45311cb0ef41Sopenharmony_ci Value value = 45321cb0ef41Sopenharmony_ci CreateValue(rtt.type.is_bottom() 45331cb0ef41Sopenharmony_ci ? kWasmBottom 45341cb0ef41Sopenharmony_ci : ValueType::Ref(rtt.type.ref_index(), 45351cb0ef41Sopenharmony_ci obj.type.is_bottom() 45361cb0ef41Sopenharmony_ci ? kNonNullable 45371cb0ef41Sopenharmony_ci : obj.type.nullability())); 45381cb0ef41Sopenharmony_ci if (current_code_reachable_and_ok_) { 45391cb0ef41Sopenharmony_ci // This logic ensures that code generation can assume that functions 45401cb0ef41Sopenharmony_ci // can only be cast to function types, and data objects to data types. 45411cb0ef41Sopenharmony_ci if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) { 45421cb0ef41Sopenharmony_ci // Drop the rtt from the stack, then forward the object value to the 45431cb0ef41Sopenharmony_ci // result. 45441cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 45451cb0ef41Sopenharmony_ci CALL_INTERFACE(Forward, obj, &value); 45461cb0ef41Sopenharmony_ci } else if (V8_UNLIKELY(TypeCheckAlwaysFails(obj, rtt))) { 45471cb0ef41Sopenharmony_ci // Unrelated types. The only way this will not trap is if the object 45481cb0ef41Sopenharmony_ci // is null. 45491cb0ef41Sopenharmony_ci if (obj.type.is_nullable()) { 45501cb0ef41Sopenharmony_ci // Drop rtt from the stack, then assert that obj is null. 45511cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 45521cb0ef41Sopenharmony_ci CALL_INTERFACE(AssertNull, obj, &value); 45531cb0ef41Sopenharmony_ci } else { 45541cb0ef41Sopenharmony_ci CALL_INTERFACE(Trap, TrapReason::kTrapIllegalCast); 45551cb0ef41Sopenharmony_ci // We know that the following code is not reachable, but according 45561cb0ef41Sopenharmony_ci // to the spec it technically is. Set it to spec-only reachable. 45571cb0ef41Sopenharmony_ci SetSucceedingCodeDynamicallyUnreachable(); 45581cb0ef41Sopenharmony_ci } 45591cb0ef41Sopenharmony_ci } else { 45601cb0ef41Sopenharmony_ci CALL_INTERFACE(RefCast, obj, rtt, &value); 45611cb0ef41Sopenharmony_ci } 45621cb0ef41Sopenharmony_ci } 45631cb0ef41Sopenharmony_ci Drop(2); 45641cb0ef41Sopenharmony_ci Push(value); 45651cb0ef41Sopenharmony_ci return opcode_length; 45661cb0ef41Sopenharmony_ci } 45671cb0ef41Sopenharmony_ci case kExprBrOnCast: 45681cb0ef41Sopenharmony_ci case kExprBrOnCastStatic: { 45691cb0ef41Sopenharmony_ci NON_CONST_ONLY 45701cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> branch_depth(this, 45711cb0ef41Sopenharmony_ci this->pc_ + opcode_length); 45721cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, branch_depth, 45731cb0ef41Sopenharmony_ci control_.size())) { 45741cb0ef41Sopenharmony_ci return 0; 45751cb0ef41Sopenharmony_ci } 45761cb0ef41Sopenharmony_ci uint32_t pc_offset = opcode_length + branch_depth.length; 45771cb0ef41Sopenharmony_ci Value rtt = Peek(0); // This is safe for the ...Static instruction. 45781cb0ef41Sopenharmony_ci if (opcode == kExprBrOnCastStatic) { 45791cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + pc_offset, 45801cb0ef41Sopenharmony_ci "type index"); 45811cb0ef41Sopenharmony_ci if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 45821cb0ef41Sopenharmony_ci pc_offset += imm.length; 45831cb0ef41Sopenharmony_ci rtt = CreateValue(ValueType::Rtt(imm.index)); 45841cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 45851cb0ef41Sopenharmony_ci Push(rtt); 45861cb0ef41Sopenharmony_ci } else { 45871cb0ef41Sopenharmony_ci DCHECK_EQ(opcode, kExprBrOnCast); 45881cb0ef41Sopenharmony_ci if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) { 45891cb0ef41Sopenharmony_ci PopTypeError(1, rtt, "rtt"); 45901cb0ef41Sopenharmony_ci return 0; 45911cb0ef41Sopenharmony_ci } 45921cb0ef41Sopenharmony_ci } 45931cb0ef41Sopenharmony_ci Value obj = Peek(1); 45941cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) || 45951cb0ef41Sopenharmony_ci IsSubtypeOf(obj.type, 45961cb0ef41Sopenharmony_ci ValueType::Ref(HeapType::kData, kNullable), 45971cb0ef41Sopenharmony_ci this->module_) || 45981cb0ef41Sopenharmony_ci obj.type.is_bottom())) { 45991cb0ef41Sopenharmony_ci PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)"); 46001cb0ef41Sopenharmony_ci return 0; 46011cb0ef41Sopenharmony_ci } 46021cb0ef41Sopenharmony_ci Control* c = control_at(branch_depth.depth); 46031cb0ef41Sopenharmony_ci if (c->br_merge()->arity == 0) { 46041cb0ef41Sopenharmony_ci this->DecodeError( 46051cb0ef41Sopenharmony_ci "br_on_cast must target a branch of arity at least 1"); 46061cb0ef41Sopenharmony_ci return 0; 46071cb0ef41Sopenharmony_ci } 46081cb0ef41Sopenharmony_ci // Attention: contrary to most other instructions, we modify the 46091cb0ef41Sopenharmony_ci // stack before calling the interface function. This makes it 46101cb0ef41Sopenharmony_ci // significantly more convenient to pass around the values that 46111cb0ef41Sopenharmony_ci // will be on the stack when the branch is taken. 46121cb0ef41Sopenharmony_ci // TODO(jkummerow): Reconsider this choice. 46131cb0ef41Sopenharmony_ci Drop(2); // {obj} and {rtt}. 46141cb0ef41Sopenharmony_ci Value result_on_branch = CreateValue( 46151cb0ef41Sopenharmony_ci rtt.type.is_bottom() 46161cb0ef41Sopenharmony_ci ? kWasmBottom 46171cb0ef41Sopenharmony_ci : ValueType::Ref(rtt.type.ref_index(), kNonNullable)); 46181cb0ef41Sopenharmony_ci Push(result_on_branch); 46191cb0ef41Sopenharmony_ci // The {value_on_branch} parameter we pass to the interface must 46201cb0ef41Sopenharmony_ci // be pointer-identical to the object on the stack, so we can't 46211cb0ef41Sopenharmony_ci // reuse {result_on_branch} which was passed-by-value to {Push}. 46221cb0ef41Sopenharmony_ci Value* value_on_branch = stack_value(1); 46231cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 46241cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 46251cb0ef41Sopenharmony_ci // This logic ensures that code generation can assume that functions 46261cb0ef41Sopenharmony_ci // can only be cast to function types, and data objects to data types. 46271cb0ef41Sopenharmony_ci if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) { 46281cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); // rtt 46291cb0ef41Sopenharmony_ci CALL_INTERFACE(Forward, obj, value_on_branch); 46301cb0ef41Sopenharmony_ci // The branch will still not be taken on null. 46311cb0ef41Sopenharmony_ci if (obj.type.is_nullable()) { 46321cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnNonNull, obj, branch_depth.depth); 46331cb0ef41Sopenharmony_ci } else { 46341cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOrRet, branch_depth.depth, 0); 46351cb0ef41Sopenharmony_ci // We know that the following code is not reachable, but according 46361cb0ef41Sopenharmony_ci // to the spec it technically is. Set it to spec-only reachable. 46371cb0ef41Sopenharmony_ci SetSucceedingCodeDynamicallyUnreachable(); 46381cb0ef41Sopenharmony_ci } 46391cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 46401cb0ef41Sopenharmony_ci } else if (V8_LIKELY(!TypeCheckAlwaysFails(obj, rtt))) { 46411cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnCast, obj, rtt, value_on_branch, 46421cb0ef41Sopenharmony_ci branch_depth.depth); 46431cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 46441cb0ef41Sopenharmony_ci } 46451cb0ef41Sopenharmony_ci // Otherwise the types are unrelated. Do not branch. 46461cb0ef41Sopenharmony_ci } 46471cb0ef41Sopenharmony_ci 46481cb0ef41Sopenharmony_ci Drop(result_on_branch); 46491cb0ef41Sopenharmony_ci Push(obj); // Restore stack state on fallthrough. 46501cb0ef41Sopenharmony_ci return pc_offset; 46511cb0ef41Sopenharmony_ci } 46521cb0ef41Sopenharmony_ci case kExprBrOnCastFail: 46531cb0ef41Sopenharmony_ci case kExprBrOnCastStaticFail: { 46541cb0ef41Sopenharmony_ci NON_CONST_ONLY 46551cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> branch_depth(this, 46561cb0ef41Sopenharmony_ci this->pc_ + opcode_length); 46571cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, branch_depth, 46581cb0ef41Sopenharmony_ci control_.size())) { 46591cb0ef41Sopenharmony_ci return 0; 46601cb0ef41Sopenharmony_ci } 46611cb0ef41Sopenharmony_ci uint32_t pc_offset = opcode_length + branch_depth.length; 46621cb0ef41Sopenharmony_ci Value rtt = Peek(0); // This is safe for the ...Static instruction. 46631cb0ef41Sopenharmony_ci if (opcode == kExprBrOnCastStaticFail) { 46641cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + pc_offset, 46651cb0ef41Sopenharmony_ci "type index"); 46661cb0ef41Sopenharmony_ci if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 46671cb0ef41Sopenharmony_ci pc_offset += imm.length; 46681cb0ef41Sopenharmony_ci rtt = CreateValue(ValueType::Rtt(imm.index)); 46691cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 46701cb0ef41Sopenharmony_ci Push(rtt); 46711cb0ef41Sopenharmony_ci } else { 46721cb0ef41Sopenharmony_ci DCHECK_EQ(opcode, kExprBrOnCastFail); 46731cb0ef41Sopenharmony_ci if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) { 46741cb0ef41Sopenharmony_ci PopTypeError(1, rtt, "rtt"); 46751cb0ef41Sopenharmony_ci return 0; 46761cb0ef41Sopenharmony_ci } 46771cb0ef41Sopenharmony_ci } 46781cb0ef41Sopenharmony_ci Value obj = Peek(1); 46791cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) || 46801cb0ef41Sopenharmony_ci IsSubtypeOf(obj.type, 46811cb0ef41Sopenharmony_ci ValueType::Ref(HeapType::kData, kNullable), 46821cb0ef41Sopenharmony_ci this->module_) || 46831cb0ef41Sopenharmony_ci obj.type.is_bottom())) { 46841cb0ef41Sopenharmony_ci PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)"); 46851cb0ef41Sopenharmony_ci return 0; 46861cb0ef41Sopenharmony_ci } 46871cb0ef41Sopenharmony_ci Control* c = control_at(branch_depth.depth); 46881cb0ef41Sopenharmony_ci if (c->br_merge()->arity == 0) { 46891cb0ef41Sopenharmony_ci this->DecodeError( 46901cb0ef41Sopenharmony_ci "br_on_cast_fail must target a branch of arity at least 1"); 46911cb0ef41Sopenharmony_ci return 0; 46921cb0ef41Sopenharmony_ci } 46931cb0ef41Sopenharmony_ci // Attention: contrary to most other instructions, we modify the stack 46941cb0ef41Sopenharmony_ci // before calling the interface function. This makes it significantly 46951cb0ef41Sopenharmony_ci // more convenient to pass around the values that will be on the stack 46961cb0ef41Sopenharmony_ci // when the branch is taken. In this case, we leave {obj} on the stack 46971cb0ef41Sopenharmony_ci // to type check the branch. 46981cb0ef41Sopenharmony_ci // TODO(jkummerow): Reconsider this choice. 46991cb0ef41Sopenharmony_ci Drop(rtt); 47001cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 47011cb0ef41Sopenharmony_ci Value result_on_fallthrough = CreateValue( 47021cb0ef41Sopenharmony_ci rtt.type.is_bottom() 47031cb0ef41Sopenharmony_ci ? kWasmBottom 47041cb0ef41Sopenharmony_ci : ValueType::Ref(rtt.type.ref_index(), kNonNullable)); 47051cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 47061cb0ef41Sopenharmony_ci // This logic ensures that code generation can assume that functions 47071cb0ef41Sopenharmony_ci // can only be cast to function types, and data objects to data types. 47081cb0ef41Sopenharmony_ci if (V8_UNLIKELY(TypeCheckAlwaysFails(obj, rtt))) { 47091cb0ef41Sopenharmony_ci // Drop {rtt} in the interface. 47101cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 47111cb0ef41Sopenharmony_ci // Otherwise the types are unrelated. Always branch. 47121cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOrRet, branch_depth.depth, 0); 47131cb0ef41Sopenharmony_ci // We know that the following code is not reachable, but according 47141cb0ef41Sopenharmony_ci // to the spec it technically is. Set it to spec-only reachable. 47151cb0ef41Sopenharmony_ci SetSucceedingCodeDynamicallyUnreachable(); 47161cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 47171cb0ef41Sopenharmony_ci } else if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) { 47181cb0ef41Sopenharmony_ci // Drop {rtt} in the interface. 47191cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 47201cb0ef41Sopenharmony_ci // The branch can still be taken on null. 47211cb0ef41Sopenharmony_ci if (obj.type.is_nullable()) { 47221cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnNull, obj, branch_depth.depth, true, 47231cb0ef41Sopenharmony_ci &result_on_fallthrough); 47241cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 47251cb0ef41Sopenharmony_ci } else { 47261cb0ef41Sopenharmony_ci // Drop {obj} in the interface. 47271cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); 47281cb0ef41Sopenharmony_ci } 47291cb0ef41Sopenharmony_ci } else { 47301cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnCastFail, obj, rtt, &result_on_fallthrough, 47311cb0ef41Sopenharmony_ci branch_depth.depth); 47321cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 47331cb0ef41Sopenharmony_ci } 47341cb0ef41Sopenharmony_ci // Otherwise, the type check always succeeds. Do not branch. 47351cb0ef41Sopenharmony_ci } 47361cb0ef41Sopenharmony_ci // Make sure the correct value is on the stack state on fallthrough. 47371cb0ef41Sopenharmony_ci Drop(obj); 47381cb0ef41Sopenharmony_ci Push(result_on_fallthrough); 47391cb0ef41Sopenharmony_ci return pc_offset; 47401cb0ef41Sopenharmony_ci } 47411cb0ef41Sopenharmony_ci#define ABSTRACT_TYPE_CHECK(h_type) \ 47421cb0ef41Sopenharmony_ci case kExprRefIs##h_type: { \ 47431cb0ef41Sopenharmony_ci NON_CONST_ONLY \ 47441cb0ef41Sopenharmony_ci Value arg = Peek(0, 0, kWasmAnyRef); \ 47451cb0ef41Sopenharmony_ci if (this->failed()) return 0; \ 47461cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmI32); \ 47471cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { \ 47481cb0ef41Sopenharmony_ci if (IsHeapSubtypeOf(arg.type.heap_representation(), HeapType::k##h_type, \ 47491cb0ef41Sopenharmony_ci this->module_)) { \ 47501cb0ef41Sopenharmony_ci if (arg.type.is_nullable()) { \ 47511cb0ef41Sopenharmony_ci /* We abuse ref.as_non_null, which isn't otherwise used as a unary \ 47521cb0ef41Sopenharmony_ci * operator, as a sentinel for the negation of ref.is_null. */ \ 47531cb0ef41Sopenharmony_ci CALL_INTERFACE(UnOp, kExprRefAsNonNull, arg, &result); \ 47541cb0ef41Sopenharmony_ci } else { \ 47551cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); \ 47561cb0ef41Sopenharmony_ci CALL_INTERFACE(I32Const, &result, 1); \ 47571cb0ef41Sopenharmony_ci } \ 47581cb0ef41Sopenharmony_ci } else if (!IsHeapSubtypeOf(HeapType::k##h_type, \ 47591cb0ef41Sopenharmony_ci arg.type.heap_representation(), \ 47601cb0ef41Sopenharmony_ci this->module_)) { \ 47611cb0ef41Sopenharmony_ci CALL_INTERFACE(Drop); \ 47621cb0ef41Sopenharmony_ci CALL_INTERFACE(I32Const, &result, 0); \ 47631cb0ef41Sopenharmony_ci } else { \ 47641cb0ef41Sopenharmony_ci CALL_INTERFACE(RefIs##h_type, arg, &result); \ 47651cb0ef41Sopenharmony_ci } \ 47661cb0ef41Sopenharmony_ci } \ 47671cb0ef41Sopenharmony_ci Drop(arg); \ 47681cb0ef41Sopenharmony_ci Push(result); \ 47691cb0ef41Sopenharmony_ci return opcode_length; \ 47701cb0ef41Sopenharmony_ci } 47711cb0ef41Sopenharmony_ci ABSTRACT_TYPE_CHECK(Data) 47721cb0ef41Sopenharmony_ci ABSTRACT_TYPE_CHECK(Func) 47731cb0ef41Sopenharmony_ci ABSTRACT_TYPE_CHECK(I31) 47741cb0ef41Sopenharmony_ci ABSTRACT_TYPE_CHECK(Array) 47751cb0ef41Sopenharmony_ci#undef ABSTRACT_TYPE_CHECK 47761cb0ef41Sopenharmony_ci 47771cb0ef41Sopenharmony_ci#define ABSTRACT_TYPE_CAST(h_type) \ 47781cb0ef41Sopenharmony_ci case kExprRefAs##h_type: { \ 47791cb0ef41Sopenharmony_ci NON_CONST_ONLY \ 47801cb0ef41Sopenharmony_ci Value arg = Peek(0, 0, kWasmAnyRef); \ 47811cb0ef41Sopenharmony_ci ValueType non_nullable_abstract_type = \ 47821cb0ef41Sopenharmony_ci ValueType::Ref(HeapType::k##h_type, kNonNullable); \ 47831cb0ef41Sopenharmony_ci Value result = CreateValue(non_nullable_abstract_type); \ 47841cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { \ 47851cb0ef41Sopenharmony_ci if (IsHeapSubtypeOf(arg.type.heap_representation(), HeapType::k##h_type, \ 47861cb0ef41Sopenharmony_ci this->module_)) { \ 47871cb0ef41Sopenharmony_ci if (arg.type.is_nullable()) { \ 47881cb0ef41Sopenharmony_ci CALL_INTERFACE(RefAsNonNull, arg, &result); \ 47891cb0ef41Sopenharmony_ci } else { \ 47901cb0ef41Sopenharmony_ci CALL_INTERFACE(Forward, arg, &result); \ 47911cb0ef41Sopenharmony_ci } \ 47921cb0ef41Sopenharmony_ci } else if (!IsHeapSubtypeOf(HeapType::k##h_type, \ 47931cb0ef41Sopenharmony_ci arg.type.heap_representation(), \ 47941cb0ef41Sopenharmony_ci this->module_)) { \ 47951cb0ef41Sopenharmony_ci CALL_INTERFACE(Trap, TrapReason::kTrapIllegalCast); \ 47961cb0ef41Sopenharmony_ci /* We know that the following code is not reachable, but according */ \ 47971cb0ef41Sopenharmony_ci /* to the spec it technically is. Set it to spec-only reachable. */ \ 47981cb0ef41Sopenharmony_ci SetSucceedingCodeDynamicallyUnreachable(); \ 47991cb0ef41Sopenharmony_ci } else { \ 48001cb0ef41Sopenharmony_ci CALL_INTERFACE(RefAs##h_type, arg, &result); \ 48011cb0ef41Sopenharmony_ci } \ 48021cb0ef41Sopenharmony_ci } \ 48031cb0ef41Sopenharmony_ci Drop(arg); \ 48041cb0ef41Sopenharmony_ci Push(result); \ 48051cb0ef41Sopenharmony_ci return opcode_length; \ 48061cb0ef41Sopenharmony_ci } 48071cb0ef41Sopenharmony_ci ABSTRACT_TYPE_CAST(Data) 48081cb0ef41Sopenharmony_ci ABSTRACT_TYPE_CAST(Func) 48091cb0ef41Sopenharmony_ci ABSTRACT_TYPE_CAST(I31) 48101cb0ef41Sopenharmony_ci ABSTRACT_TYPE_CAST(Array) 48111cb0ef41Sopenharmony_ci#undef ABSTRACT_TYPE_CAST 48121cb0ef41Sopenharmony_ci 48131cb0ef41Sopenharmony_ci case kExprBrOnData: 48141cb0ef41Sopenharmony_ci case kExprBrOnFunc: 48151cb0ef41Sopenharmony_ci case kExprBrOnArray: 48161cb0ef41Sopenharmony_ci case kExprBrOnI31: { 48171cb0ef41Sopenharmony_ci NON_CONST_ONLY 48181cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> branch_depth(this, 48191cb0ef41Sopenharmony_ci this->pc_ + opcode_length); 48201cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, branch_depth, 48211cb0ef41Sopenharmony_ci control_.size())) { 48221cb0ef41Sopenharmony_ci return 0; 48231cb0ef41Sopenharmony_ci } 48241cb0ef41Sopenharmony_ci 48251cb0ef41Sopenharmony_ci Control* c = control_at(branch_depth.depth); 48261cb0ef41Sopenharmony_ci if (c->br_merge()->arity == 0) { 48271cb0ef41Sopenharmony_ci this->DecodeError("%s must target a branch of arity at least 1", 48281cb0ef41Sopenharmony_ci SafeOpcodeNameAt(this->pc_)); 48291cb0ef41Sopenharmony_ci return 0; 48301cb0ef41Sopenharmony_ci } 48311cb0ef41Sopenharmony_ci 48321cb0ef41Sopenharmony_ci // Attention: contrary to most other instructions, we modify the 48331cb0ef41Sopenharmony_ci // stack before calling the interface function. This makes it 48341cb0ef41Sopenharmony_ci // significantly more convenient to pass around the values that 48351cb0ef41Sopenharmony_ci // will be on the stack when the branch is taken. 48361cb0ef41Sopenharmony_ci // TODO(jkummerow): Reconsider this choice. 48371cb0ef41Sopenharmony_ci Value obj = Peek(0, 0, kWasmAnyRef); 48381cb0ef41Sopenharmony_ci Drop(obj); 48391cb0ef41Sopenharmony_ci HeapType::Representation heap_type = 48401cb0ef41Sopenharmony_ci opcode == kExprBrOnFunc 48411cb0ef41Sopenharmony_ci ? HeapType::kFunc 48421cb0ef41Sopenharmony_ci : opcode == kExprBrOnData 48431cb0ef41Sopenharmony_ci ? HeapType::kData 48441cb0ef41Sopenharmony_ci : opcode == kExprBrOnArray ? HeapType::kArray 48451cb0ef41Sopenharmony_ci : HeapType::kI31; 48461cb0ef41Sopenharmony_ci Value result_on_branch = 48471cb0ef41Sopenharmony_ci CreateValue(ValueType::Ref(heap_type, kNonNullable)); 48481cb0ef41Sopenharmony_ci Push(result_on_branch); 48491cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 48501cb0ef41Sopenharmony_ci // The {value_on_branch} parameter we pass to the interface must be 48511cb0ef41Sopenharmony_ci // pointer-identical to the object on the stack, so we can't reuse 48521cb0ef41Sopenharmony_ci // {result_on_branch} which was passed-by-value to {Push}. 48531cb0ef41Sopenharmony_ci Value* value_on_branch = stack_value(1); 48541cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 48551cb0ef41Sopenharmony_ci if (opcode == kExprBrOnFunc) { 48561cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnFunc, obj, value_on_branch, branch_depth.depth); 48571cb0ef41Sopenharmony_ci } else if (opcode == kExprBrOnData) { 48581cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnData, obj, value_on_branch, branch_depth.depth); 48591cb0ef41Sopenharmony_ci } else if (opcode == kExprBrOnArray) { 48601cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnArray, obj, value_on_branch, branch_depth.depth); 48611cb0ef41Sopenharmony_ci } else { 48621cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnI31, obj, value_on_branch, branch_depth.depth); 48631cb0ef41Sopenharmony_ci } 48641cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 48651cb0ef41Sopenharmony_ci } 48661cb0ef41Sopenharmony_ci Drop(result_on_branch); 48671cb0ef41Sopenharmony_ci Push(obj); // Restore stack state on fallthrough. 48681cb0ef41Sopenharmony_ci return opcode_length + branch_depth.length; 48691cb0ef41Sopenharmony_ci } 48701cb0ef41Sopenharmony_ci case kExprBrOnNonData: 48711cb0ef41Sopenharmony_ci case kExprBrOnNonFunc: 48721cb0ef41Sopenharmony_ci case kExprBrOnNonArray: 48731cb0ef41Sopenharmony_ci case kExprBrOnNonI31: { 48741cb0ef41Sopenharmony_ci NON_CONST_ONLY 48751cb0ef41Sopenharmony_ci BranchDepthImmediate<validate> branch_depth(this, 48761cb0ef41Sopenharmony_ci this->pc_ + opcode_length); 48771cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, branch_depth, 48781cb0ef41Sopenharmony_ci control_.size())) { 48791cb0ef41Sopenharmony_ci return 0; 48801cb0ef41Sopenharmony_ci } 48811cb0ef41Sopenharmony_ci 48821cb0ef41Sopenharmony_ci Control* c = control_at(branch_depth.depth); 48831cb0ef41Sopenharmony_ci if (c->br_merge()->arity == 0) { 48841cb0ef41Sopenharmony_ci this->DecodeError("%s must target a branch of arity at least 1", 48851cb0ef41Sopenharmony_ci SafeOpcodeNameAt(this->pc_)); 48861cb0ef41Sopenharmony_ci return 0; 48871cb0ef41Sopenharmony_ci } 48881cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 48891cb0ef41Sopenharmony_ci 48901cb0ef41Sopenharmony_ci Value obj = Peek(0, 0, kWasmAnyRef); 48911cb0ef41Sopenharmony_ci HeapType::Representation heap_type = 48921cb0ef41Sopenharmony_ci opcode == kExprBrOnNonFunc 48931cb0ef41Sopenharmony_ci ? HeapType::kFunc 48941cb0ef41Sopenharmony_ci : opcode == kExprBrOnNonData 48951cb0ef41Sopenharmony_ci ? HeapType::kData 48961cb0ef41Sopenharmony_ci : opcode == kExprBrOnNonArray ? HeapType::kArray 48971cb0ef41Sopenharmony_ci : HeapType::kI31; 48981cb0ef41Sopenharmony_ci Value value_on_fallthrough = 48991cb0ef41Sopenharmony_ci CreateValue(ValueType::Ref(heap_type, kNonNullable)); 49001cb0ef41Sopenharmony_ci 49011cb0ef41Sopenharmony_ci if (V8_LIKELY(current_code_reachable_and_ok_)) { 49021cb0ef41Sopenharmony_ci if (opcode == kExprBrOnNonFunc) { 49031cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnNonFunc, obj, &value_on_fallthrough, 49041cb0ef41Sopenharmony_ci branch_depth.depth); 49051cb0ef41Sopenharmony_ci } else if (opcode == kExprBrOnNonData) { 49061cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnNonData, obj, &value_on_fallthrough, 49071cb0ef41Sopenharmony_ci branch_depth.depth); 49081cb0ef41Sopenharmony_ci } else if (opcode == kExprBrOnNonArray) { 49091cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnNonArray, obj, &value_on_fallthrough, 49101cb0ef41Sopenharmony_ci branch_depth.depth); 49111cb0ef41Sopenharmony_ci } else { 49121cb0ef41Sopenharmony_ci CALL_INTERFACE(BrOnNonI31, obj, &value_on_fallthrough, 49131cb0ef41Sopenharmony_ci branch_depth.depth); 49141cb0ef41Sopenharmony_ci } 49151cb0ef41Sopenharmony_ci c->br_merge()->reached = true; 49161cb0ef41Sopenharmony_ci } 49171cb0ef41Sopenharmony_ci Drop(obj); 49181cb0ef41Sopenharmony_ci Push(value_on_fallthrough); 49191cb0ef41Sopenharmony_ci return opcode_length + branch_depth.length; 49201cb0ef41Sopenharmony_ci } 49211cb0ef41Sopenharmony_ci default: 49221cb0ef41Sopenharmony_ci this->DecodeError("invalid gc opcode: %x", opcode); 49231cb0ef41Sopenharmony_ci return 0; 49241cb0ef41Sopenharmony_ci } 49251cb0ef41Sopenharmony_ci } 49261cb0ef41Sopenharmony_ci#undef NON_CONST_ONLY 49271cb0ef41Sopenharmony_ci 49281cb0ef41Sopenharmony_ci uint32_t DecodeAtomicOpcode(WasmOpcode opcode, uint32_t opcode_length) { 49291cb0ef41Sopenharmony_ci ValueType ret_type; 49301cb0ef41Sopenharmony_ci const FunctionSig* sig = WasmOpcodes::Signature(opcode); 49311cb0ef41Sopenharmony_ci if (!VALIDATE(sig != nullptr)) { 49321cb0ef41Sopenharmony_ci this->DecodeError("invalid atomic opcode"); 49331cb0ef41Sopenharmony_ci return 0; 49341cb0ef41Sopenharmony_ci } 49351cb0ef41Sopenharmony_ci MachineType memtype; 49361cb0ef41Sopenharmony_ci switch (opcode) { 49371cb0ef41Sopenharmony_ci#define CASE_ATOMIC_STORE_OP(Name, Type) \ 49381cb0ef41Sopenharmony_ci case kExpr##Name: { \ 49391cb0ef41Sopenharmony_ci memtype = MachineType::Type(); \ 49401cb0ef41Sopenharmony_ci ret_type = kWasmVoid; \ 49411cb0ef41Sopenharmony_ci break; /* to generic mem access code below */ \ 49421cb0ef41Sopenharmony_ci } 49431cb0ef41Sopenharmony_ci ATOMIC_STORE_OP_LIST(CASE_ATOMIC_STORE_OP) 49441cb0ef41Sopenharmony_ci#undef CASE_ATOMIC_OP 49451cb0ef41Sopenharmony_ci#define CASE_ATOMIC_OP(Name, Type) \ 49461cb0ef41Sopenharmony_ci case kExpr##Name: { \ 49471cb0ef41Sopenharmony_ci memtype = MachineType::Type(); \ 49481cb0ef41Sopenharmony_ci ret_type = GetReturnType(sig); \ 49491cb0ef41Sopenharmony_ci break; /* to generic mem access code below */ \ 49501cb0ef41Sopenharmony_ci } 49511cb0ef41Sopenharmony_ci ATOMIC_OP_LIST(CASE_ATOMIC_OP) 49521cb0ef41Sopenharmony_ci#undef CASE_ATOMIC_OP 49531cb0ef41Sopenharmony_ci case kExprAtomicFence: { 49541cb0ef41Sopenharmony_ci byte zero = 49551cb0ef41Sopenharmony_ci this->template read_u8<validate>(this->pc_ + opcode_length, "zero"); 49561cb0ef41Sopenharmony_ci if (!VALIDATE(zero == 0)) { 49571cb0ef41Sopenharmony_ci this->DecodeError(this->pc_ + opcode_length, 49581cb0ef41Sopenharmony_ci "invalid atomic operand"); 49591cb0ef41Sopenharmony_ci return 0; 49601cb0ef41Sopenharmony_ci } 49611cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(AtomicFence); 49621cb0ef41Sopenharmony_ci return 1 + opcode_length; 49631cb0ef41Sopenharmony_ci } 49641cb0ef41Sopenharmony_ci default: 49651cb0ef41Sopenharmony_ci this->DecodeError("invalid atomic opcode"); 49661cb0ef41Sopenharmony_ci return 0; 49671cb0ef41Sopenharmony_ci } 49681cb0ef41Sopenharmony_ci 49691cb0ef41Sopenharmony_ci MemoryAccessImmediate<validate> imm = MakeMemoryAccessImmediate( 49701cb0ef41Sopenharmony_ci opcode_length, ElementSizeLog2Of(memtype.representation())); 49711cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return false; 49721cb0ef41Sopenharmony_ci 49731cb0ef41Sopenharmony_ci // TODO(10949): Fix this for memory64 (index type should be kWasmI64 49741cb0ef41Sopenharmony_ci // then). 49751cb0ef41Sopenharmony_ci CHECK(!this->module_->is_memory64); 49761cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(sig); 49771cb0ef41Sopenharmony_ci if (ret_type == kWasmVoid) { 49781cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(AtomicOp, opcode, base::VectorOf(args), 49791cb0ef41Sopenharmony_ci imm, nullptr); 49801cb0ef41Sopenharmony_ci DropArgs(sig); 49811cb0ef41Sopenharmony_ci } else { 49821cb0ef41Sopenharmony_ci Value result = CreateValue(GetReturnType(sig)); 49831cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(AtomicOp, opcode, base::VectorOf(args), 49841cb0ef41Sopenharmony_ci imm, &result); 49851cb0ef41Sopenharmony_ci DropArgs(sig); 49861cb0ef41Sopenharmony_ci Push(result); 49871cb0ef41Sopenharmony_ci } 49881cb0ef41Sopenharmony_ci return opcode_length + imm.length; 49891cb0ef41Sopenharmony_ci } 49901cb0ef41Sopenharmony_ci 49911cb0ef41Sopenharmony_ci unsigned DecodeNumericOpcode(WasmOpcode opcode, uint32_t opcode_length) { 49921cb0ef41Sopenharmony_ci const FunctionSig* sig = WasmOpcodes::Signature(opcode); 49931cb0ef41Sopenharmony_ci switch (opcode) { 49941cb0ef41Sopenharmony_ci case kExprI32SConvertSatF32: 49951cb0ef41Sopenharmony_ci case kExprI32UConvertSatF32: 49961cb0ef41Sopenharmony_ci case kExprI32SConvertSatF64: 49971cb0ef41Sopenharmony_ci case kExprI32UConvertSatF64: 49981cb0ef41Sopenharmony_ci case kExprI64SConvertSatF32: 49991cb0ef41Sopenharmony_ci case kExprI64UConvertSatF32: 50001cb0ef41Sopenharmony_ci case kExprI64SConvertSatF64: 50011cb0ef41Sopenharmony_ci case kExprI64UConvertSatF64: { 50021cb0ef41Sopenharmony_ci BuildSimpleOperator(opcode, sig); 50031cb0ef41Sopenharmony_ci return opcode_length; 50041cb0ef41Sopenharmony_ci } 50051cb0ef41Sopenharmony_ci case kExprMemoryInit: { 50061cb0ef41Sopenharmony_ci MemoryInitImmediate<validate> imm(this, this->pc_ + opcode_length); 50071cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 50081cb0ef41Sopenharmony_ci ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 50091cb0ef41Sopenharmony_ci Value size = Peek(0, 2, kWasmI32); 50101cb0ef41Sopenharmony_ci Value offset = Peek(1, 1, kWasmI32); 50111cb0ef41Sopenharmony_ci Value dst = Peek(2, 0, mem_type); 50121cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryInit, imm, dst, offset, size); 50131cb0ef41Sopenharmony_ci Drop(3); 50141cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50151cb0ef41Sopenharmony_ci } 50161cb0ef41Sopenharmony_ci case kExprDataDrop: { 50171cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 50181cb0ef41Sopenharmony_ci "data segment index"); 50191cb0ef41Sopenharmony_ci if (!this->ValidateDataSegment(this->pc_ + opcode_length, imm)) { 50201cb0ef41Sopenharmony_ci return 0; 50211cb0ef41Sopenharmony_ci } 50221cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(DataDrop, imm); 50231cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50241cb0ef41Sopenharmony_ci } 50251cb0ef41Sopenharmony_ci case kExprMemoryCopy: { 50261cb0ef41Sopenharmony_ci MemoryCopyImmediate<validate> imm(this, this->pc_ + opcode_length); 50271cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 50281cb0ef41Sopenharmony_ci ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 50291cb0ef41Sopenharmony_ci Value size = Peek(0, 2, mem_type); 50301cb0ef41Sopenharmony_ci Value src = Peek(1, 1, mem_type); 50311cb0ef41Sopenharmony_ci Value dst = Peek(2, 0, mem_type); 50321cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryCopy, imm, dst, src, size); 50331cb0ef41Sopenharmony_ci Drop(3); 50341cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50351cb0ef41Sopenharmony_ci } 50361cb0ef41Sopenharmony_ci case kExprMemoryFill: { 50371cb0ef41Sopenharmony_ci MemoryIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 50381cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 50391cb0ef41Sopenharmony_ci ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 50401cb0ef41Sopenharmony_ci Value size = Peek(0, 2, mem_type); 50411cb0ef41Sopenharmony_ci Value value = Peek(1, 1, kWasmI32); 50421cb0ef41Sopenharmony_ci Value dst = Peek(2, 0, mem_type); 50431cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryFill, imm, dst, value, size); 50441cb0ef41Sopenharmony_ci Drop(3); 50451cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50461cb0ef41Sopenharmony_ci } 50471cb0ef41Sopenharmony_ci case kExprTableInit: { 50481cb0ef41Sopenharmony_ci TableInitImmediate<validate> imm(this, this->pc_ + opcode_length); 50491cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 50501cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(sig); 50511cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(TableInit, imm, 50521cb0ef41Sopenharmony_ci base::VectorOf(args)); 50531cb0ef41Sopenharmony_ci DropArgs(sig); 50541cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50551cb0ef41Sopenharmony_ci } 50561cb0ef41Sopenharmony_ci case kExprElemDrop: { 50571cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 50581cb0ef41Sopenharmony_ci "element segment index"); 50591cb0ef41Sopenharmony_ci if (!this->ValidateElementSegment(this->pc_ + opcode_length, imm)) { 50601cb0ef41Sopenharmony_ci return 0; 50611cb0ef41Sopenharmony_ci } 50621cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(ElemDrop, imm); 50631cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50641cb0ef41Sopenharmony_ci } 50651cb0ef41Sopenharmony_ci case kExprTableCopy: { 50661cb0ef41Sopenharmony_ci TableCopyImmediate<validate> imm(this, this->pc_ + opcode_length); 50671cb0ef41Sopenharmony_ci if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 50681cb0ef41Sopenharmony_ci ArgVector args = PeekArgs(sig); 50691cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(TableCopy, imm, 50701cb0ef41Sopenharmony_ci base::VectorOf(args)); 50711cb0ef41Sopenharmony_ci DropArgs(sig); 50721cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50731cb0ef41Sopenharmony_ci } 50741cb0ef41Sopenharmony_ci case kExprTableGrow: { 50751cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 50761cb0ef41Sopenharmony_ci "table index"); 50771cb0ef41Sopenharmony_ci if (!this->ValidateTable(this->pc_ + opcode_length, imm)) return 0; 50781cb0ef41Sopenharmony_ci Value delta = Peek(0, 1, kWasmI32); 50791cb0ef41Sopenharmony_ci Value value = Peek(1, 0, this->module_->tables[imm.index].type); 50801cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmI32); 50811cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(TableGrow, imm, value, delta, 50821cb0ef41Sopenharmony_ci &result); 50831cb0ef41Sopenharmony_ci Drop(2); 50841cb0ef41Sopenharmony_ci Push(result); 50851cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50861cb0ef41Sopenharmony_ci } 50871cb0ef41Sopenharmony_ci case kExprTableSize: { 50881cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 50891cb0ef41Sopenharmony_ci "table index"); 50901cb0ef41Sopenharmony_ci if (!this->ValidateTable(this->pc_ + opcode_length, imm)) return 0; 50911cb0ef41Sopenharmony_ci Value result = CreateValue(kWasmI32); 50921cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(TableSize, imm, &result); 50931cb0ef41Sopenharmony_ci Push(result); 50941cb0ef41Sopenharmony_ci return opcode_length + imm.length; 50951cb0ef41Sopenharmony_ci } 50961cb0ef41Sopenharmony_ci case kExprTableFill: { 50971cb0ef41Sopenharmony_ci IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 50981cb0ef41Sopenharmony_ci "table index"); 50991cb0ef41Sopenharmony_ci if (!this->ValidateTable(this->pc_ + opcode_length, imm)) return 0; 51001cb0ef41Sopenharmony_ci Value count = Peek(0, 2, kWasmI32); 51011cb0ef41Sopenharmony_ci Value value = Peek(1, 1, this->module_->tables[imm.index].type); 51021cb0ef41Sopenharmony_ci Value start = Peek(2, 0, kWasmI32); 51031cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(TableFill, imm, start, value, count); 51041cb0ef41Sopenharmony_ci Drop(3); 51051cb0ef41Sopenharmony_ci return opcode_length + imm.length; 51061cb0ef41Sopenharmony_ci } 51071cb0ef41Sopenharmony_ci default: 51081cb0ef41Sopenharmony_ci this->DecodeError("invalid numeric opcode"); 51091cb0ef41Sopenharmony_ci return 0; 51101cb0ef41Sopenharmony_ci } 51111cb0ef41Sopenharmony_ci } 51121cb0ef41Sopenharmony_ci 51131cb0ef41Sopenharmony_ci V8_INLINE void EnsureStackSpace(int slots_needed) { 51141cb0ef41Sopenharmony_ci if (V8_LIKELY(stack_capacity_end_ - stack_end_ >= slots_needed)) return; 51151cb0ef41Sopenharmony_ci GrowStackSpace(slots_needed); 51161cb0ef41Sopenharmony_ci } 51171cb0ef41Sopenharmony_ci 51181cb0ef41Sopenharmony_ci V8_NOINLINE void GrowStackSpace(int slots_needed) { 51191cb0ef41Sopenharmony_ci size_t new_stack_capacity = 51201cb0ef41Sopenharmony_ci std::max(size_t{8}, 51211cb0ef41Sopenharmony_ci base::bits::RoundUpToPowerOfTwo(stack_size() + slots_needed)); 51221cb0ef41Sopenharmony_ci Value* new_stack = 51231cb0ef41Sopenharmony_ci this->zone()->template NewArray<Value>(new_stack_capacity); 51241cb0ef41Sopenharmony_ci if (stack_) { 51251cb0ef41Sopenharmony_ci std::copy(stack_, stack_end_, new_stack); 51261cb0ef41Sopenharmony_ci this->zone()->DeleteArray(stack_, stack_capacity_end_ - stack_); 51271cb0ef41Sopenharmony_ci } 51281cb0ef41Sopenharmony_ci stack_end_ = new_stack + (stack_end_ - stack_); 51291cb0ef41Sopenharmony_ci stack_ = new_stack; 51301cb0ef41Sopenharmony_ci stack_capacity_end_ = new_stack + new_stack_capacity; 51311cb0ef41Sopenharmony_ci } 51321cb0ef41Sopenharmony_ci 51331cb0ef41Sopenharmony_ci V8_INLINE Value CreateValue(ValueType type) { return Value{this->pc_, type}; } 51341cb0ef41Sopenharmony_ci V8_INLINE void Push(Value value) { 51351cb0ef41Sopenharmony_ci DCHECK_NE(kWasmVoid, value.type); 51361cb0ef41Sopenharmony_ci // {EnsureStackSpace} should have been called before, either in the central 51371cb0ef41Sopenharmony_ci // decoding loop, or individually if more than one element is pushed. 51381cb0ef41Sopenharmony_ci DCHECK_GT(stack_capacity_end_, stack_end_); 51391cb0ef41Sopenharmony_ci *stack_end_ = value; 51401cb0ef41Sopenharmony_ci ++stack_end_; 51411cb0ef41Sopenharmony_ci } 51421cb0ef41Sopenharmony_ci 51431cb0ef41Sopenharmony_ci void PushMergeValues(Control* c, Merge<Value>* merge) { 51441cb0ef41Sopenharmony_ci if (decoding_mode == kInitExpression) return; 51451cb0ef41Sopenharmony_ci DCHECK_EQ(c, &control_.back()); 51461cb0ef41Sopenharmony_ci DCHECK(merge == &c->start_merge || merge == &c->end_merge); 51471cb0ef41Sopenharmony_ci DCHECK_LE(stack_ + c->stack_depth, stack_end_); 51481cb0ef41Sopenharmony_ci stack_end_ = stack_ + c->stack_depth; 51491cb0ef41Sopenharmony_ci if (merge->arity == 1) { 51501cb0ef41Sopenharmony_ci // {EnsureStackSpace} should have been called before in the central 51511cb0ef41Sopenharmony_ci // decoding loop. 51521cb0ef41Sopenharmony_ci DCHECK_GT(stack_capacity_end_, stack_end_); 51531cb0ef41Sopenharmony_ci *stack_end_++ = merge->vals.first; 51541cb0ef41Sopenharmony_ci } else { 51551cb0ef41Sopenharmony_ci EnsureStackSpace(merge->arity); 51561cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < merge->arity; i++) { 51571cb0ef41Sopenharmony_ci *stack_end_++ = merge->vals.array[i]; 51581cb0ef41Sopenharmony_ci } 51591cb0ef41Sopenharmony_ci } 51601cb0ef41Sopenharmony_ci DCHECK_EQ(c->stack_depth + merge->arity, stack_size()); 51611cb0ef41Sopenharmony_ci } 51621cb0ef41Sopenharmony_ci 51631cb0ef41Sopenharmony_ci V8_INLINE ReturnVector CreateReturnValues(const FunctionSig* sig) { 51641cb0ef41Sopenharmony_ci size_t return_count = sig->return_count(); 51651cb0ef41Sopenharmony_ci ReturnVector values(return_count); 51661cb0ef41Sopenharmony_ci std::transform(sig->returns().begin(), sig->returns().end(), values.begin(), 51671cb0ef41Sopenharmony_ci [this](ValueType type) { return CreateValue(type); }); 51681cb0ef41Sopenharmony_ci return values; 51691cb0ef41Sopenharmony_ci } 51701cb0ef41Sopenharmony_ci V8_INLINE void PushReturns(ReturnVector values) { 51711cb0ef41Sopenharmony_ci EnsureStackSpace(static_cast<int>(values.size())); 51721cb0ef41Sopenharmony_ci for (Value& value : values) Push(value); 51731cb0ef41Sopenharmony_ci } 51741cb0ef41Sopenharmony_ci 51751cb0ef41Sopenharmony_ci // We do not inline these functions because doing so causes a large binary 51761cb0ef41Sopenharmony_ci // size increase. Not inlining them should not create a performance 51771cb0ef41Sopenharmony_ci // degradation, because their invocations are guarded by V8_LIKELY. 51781cb0ef41Sopenharmony_ci V8_NOINLINE void PopTypeError(int index, Value val, const char* expected) { 51791cb0ef41Sopenharmony_ci this->DecodeError(val.pc(), "%s[%d] expected %s, found %s of type %s", 51801cb0ef41Sopenharmony_ci SafeOpcodeNameAt(this->pc_), index, expected, 51811cb0ef41Sopenharmony_ci SafeOpcodeNameAt(val.pc()), val.type.name().c_str()); 51821cb0ef41Sopenharmony_ci } 51831cb0ef41Sopenharmony_ci 51841cb0ef41Sopenharmony_ci V8_NOINLINE void PopTypeError(int index, Value val, std::string expected) { 51851cb0ef41Sopenharmony_ci PopTypeError(index, val, expected.c_str()); 51861cb0ef41Sopenharmony_ci } 51871cb0ef41Sopenharmony_ci 51881cb0ef41Sopenharmony_ci V8_NOINLINE void PopTypeError(int index, Value val, ValueType expected) { 51891cb0ef41Sopenharmony_ci PopTypeError(index, val, ("type " + expected.name()).c_str()); 51901cb0ef41Sopenharmony_ci } 51911cb0ef41Sopenharmony_ci 51921cb0ef41Sopenharmony_ci V8_NOINLINE void NotEnoughArgumentsError(int needed, int actual) { 51931cb0ef41Sopenharmony_ci DCHECK_LT(0, needed); 51941cb0ef41Sopenharmony_ci DCHECK_LE(0, actual); 51951cb0ef41Sopenharmony_ci DCHECK_LT(actual, needed); 51961cb0ef41Sopenharmony_ci this->DecodeError( 51971cb0ef41Sopenharmony_ci "not enough arguments on the stack for %s (need %d, got %d)", 51981cb0ef41Sopenharmony_ci SafeOpcodeNameAt(this->pc_), needed, actual); 51991cb0ef41Sopenharmony_ci } 52001cb0ef41Sopenharmony_ci 52011cb0ef41Sopenharmony_ci V8_INLINE Value Peek(int depth, int index, ValueType expected) { 52021cb0ef41Sopenharmony_ci Value val = Peek(depth); 52031cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(val.type, expected, this->module_) || 52041cb0ef41Sopenharmony_ci val.type == kWasmBottom || expected == kWasmBottom)) { 52051cb0ef41Sopenharmony_ci PopTypeError(index, val, expected); 52061cb0ef41Sopenharmony_ci } 52071cb0ef41Sopenharmony_ci return val; 52081cb0ef41Sopenharmony_ci } 52091cb0ef41Sopenharmony_ci 52101cb0ef41Sopenharmony_ci V8_INLINE Value Peek(int depth) { 52111cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); 52121cb0ef41Sopenharmony_ci uint32_t limit = control_.back().stack_depth; 52131cb0ef41Sopenharmony_ci if (V8_UNLIKELY(stack_size() <= limit + depth)) { 52141cb0ef41Sopenharmony_ci // Peeking past the current control start in reachable code. 52151cb0ef41Sopenharmony_ci if (!VALIDATE(decoding_mode == kFunctionBody && 52161cb0ef41Sopenharmony_ci control_.back().unreachable())) { 52171cb0ef41Sopenharmony_ci NotEnoughArgumentsError(depth + 1, stack_size() - limit); 52181cb0ef41Sopenharmony_ci } 52191cb0ef41Sopenharmony_ci return UnreachableValue(this->pc_); 52201cb0ef41Sopenharmony_ci } 52211cb0ef41Sopenharmony_ci DCHECK_LE(stack_, stack_end_ - depth - 1); 52221cb0ef41Sopenharmony_ci return *(stack_end_ - depth - 1); 52231cb0ef41Sopenharmony_ci } 52241cb0ef41Sopenharmony_ci 52251cb0ef41Sopenharmony_ci V8_INLINE void ValidateArgType(ArgVector args, int index, 52261cb0ef41Sopenharmony_ci ValueType expected) { 52271cb0ef41Sopenharmony_ci Value val = args[index]; 52281cb0ef41Sopenharmony_ci if (!VALIDATE(IsSubtypeOf(val.type, expected, this->module_) || 52291cb0ef41Sopenharmony_ci val.type == kWasmBottom || expected == kWasmBottom)) { 52301cb0ef41Sopenharmony_ci PopTypeError(index, val, expected); 52311cb0ef41Sopenharmony_ci } 52321cb0ef41Sopenharmony_ci } 52331cb0ef41Sopenharmony_ci 52341cb0ef41Sopenharmony_ci // Drop the top {count} stack elements, or all of them if less than {count} 52351cb0ef41Sopenharmony_ci // are present. 52361cb0ef41Sopenharmony_ci V8_INLINE void Drop(int count = 1) { 52371cb0ef41Sopenharmony_ci DCHECK(!control_.empty()); 52381cb0ef41Sopenharmony_ci uint32_t limit = control_.back().stack_depth; 52391cb0ef41Sopenharmony_ci if (V8_UNLIKELY(stack_size() < limit + count)) { 52401cb0ef41Sopenharmony_ci // Pop what we can. 52411cb0ef41Sopenharmony_ci count = std::min(count, static_cast<int>(stack_size() - limit)); 52421cb0ef41Sopenharmony_ci } 52431cb0ef41Sopenharmony_ci DCHECK_LE(stack_, stack_end_ - count); 52441cb0ef41Sopenharmony_ci stack_end_ -= count; 52451cb0ef41Sopenharmony_ci } 52461cb0ef41Sopenharmony_ci // Drop the top stack element if present. Takes a Value input for more 52471cb0ef41Sopenharmony_ci // descriptive call sites. 52481cb0ef41Sopenharmony_ci V8_INLINE void Drop(const Value& /* unused */) { Drop(1); } 52491cb0ef41Sopenharmony_ci 52501cb0ef41Sopenharmony_ci enum StackElementsCountMode : bool { 52511cb0ef41Sopenharmony_ci kNonStrictCounting = false, 52521cb0ef41Sopenharmony_ci kStrictCounting = true 52531cb0ef41Sopenharmony_ci }; 52541cb0ef41Sopenharmony_ci 52551cb0ef41Sopenharmony_ci enum MergeType { 52561cb0ef41Sopenharmony_ci kBranchMerge, 52571cb0ef41Sopenharmony_ci kReturnMerge, 52581cb0ef41Sopenharmony_ci kFallthroughMerge, 52591cb0ef41Sopenharmony_ci kInitExprMerge 52601cb0ef41Sopenharmony_ci }; 52611cb0ef41Sopenharmony_ci 52621cb0ef41Sopenharmony_ci // - If the current code is reachable, check if the current stack values are 52631cb0ef41Sopenharmony_ci // compatible with {merge} based on their number and types. Disregard the 52641cb0ef41Sopenharmony_ci // first {drop_values} on the stack. If {strict_count}, check that 52651cb0ef41Sopenharmony_ci // #(stack elements) == {merge->arity}, otherwise 52661cb0ef41Sopenharmony_ci // #(stack elements) >= {merge->arity}. 52671cb0ef41Sopenharmony_ci // - If the current code is unreachable, check if any values that may exist on 52681cb0ef41Sopenharmony_ci // top of the stack are compatible with {merge}. If {push_branch_values}, 52691cb0ef41Sopenharmony_ci // push back to the stack values based on the type of {merge} (this is 52701cb0ef41Sopenharmony_ci // needed for conditional branches due to their typing rules, and 52711cb0ef41Sopenharmony_ci // fallthroughs so that the outer control finds the expected values on the 52721cb0ef41Sopenharmony_ci // stack). TODO(manoskouk): We expect the unreachable-code behavior to 52731cb0ef41Sopenharmony_ci // change, either due to relaxation of dead code verification, or the 52741cb0ef41Sopenharmony_ci // introduction of subtyping. 52751cb0ef41Sopenharmony_ci template <StackElementsCountMode strict_count, bool push_branch_values, 52761cb0ef41Sopenharmony_ci MergeType merge_type> 52771cb0ef41Sopenharmony_ci bool TypeCheckStackAgainstMerge(uint32_t drop_values, Merge<Value>* merge) { 52781cb0ef41Sopenharmony_ci static_assert(validate, "Call this function only within VALIDATE"); 52791cb0ef41Sopenharmony_ci constexpr const char* merge_description = 52801cb0ef41Sopenharmony_ci merge_type == kBranchMerge 52811cb0ef41Sopenharmony_ci ? "branch" 52821cb0ef41Sopenharmony_ci : merge_type == kReturnMerge 52831cb0ef41Sopenharmony_ci ? "return" 52841cb0ef41Sopenharmony_ci : merge_type == kInitExprMerge ? "init. expression" 52851cb0ef41Sopenharmony_ci : "fallthru"; 52861cb0ef41Sopenharmony_ci uint32_t arity = merge->arity; 52871cb0ef41Sopenharmony_ci uint32_t actual = stack_size() - control_.back().stack_depth; 52881cb0ef41Sopenharmony_ci // Here we have to check for !unreachable(), because we need to typecheck as 52891cb0ef41Sopenharmony_ci // if the current code is reachable even if it is spec-only reachable. 52901cb0ef41Sopenharmony_ci if (V8_LIKELY(decoding_mode == kInitExpression || 52911cb0ef41Sopenharmony_ci !control_.back().unreachable())) { 52921cb0ef41Sopenharmony_ci if (V8_UNLIKELY(strict_count ? actual != drop_values + arity 52931cb0ef41Sopenharmony_ci : actual < drop_values + arity)) { 52941cb0ef41Sopenharmony_ci this->DecodeError("expected %u elements on the stack for %s, found %u", 52951cb0ef41Sopenharmony_ci arity, merge_description, 52961cb0ef41Sopenharmony_ci actual >= drop_values ? actual - drop_values : 0); 52971cb0ef41Sopenharmony_ci return false; 52981cb0ef41Sopenharmony_ci } 52991cb0ef41Sopenharmony_ci // Typecheck the topmost {merge->arity} values on the stack. 53001cb0ef41Sopenharmony_ci Value* stack_values = stack_end_ - (arity + drop_values); 53011cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < arity; ++i) { 53021cb0ef41Sopenharmony_ci Value& val = stack_values[i]; 53031cb0ef41Sopenharmony_ci Value& old = (*merge)[i]; 53041cb0ef41Sopenharmony_ci if (!IsSubtypeOf(val.type, old.type, this->module_)) { 53051cb0ef41Sopenharmony_ci this->DecodeError("type error in %s[%u] (expected %s, got %s)", 53061cb0ef41Sopenharmony_ci merge_description, i, old.type.name().c_str(), 53071cb0ef41Sopenharmony_ci val.type.name().c_str()); 53081cb0ef41Sopenharmony_ci return false; 53091cb0ef41Sopenharmony_ci } 53101cb0ef41Sopenharmony_ci } 53111cb0ef41Sopenharmony_ci return true; 53121cb0ef41Sopenharmony_ci } 53131cb0ef41Sopenharmony_ci // Unreachable code validation starts here. 53141cb0ef41Sopenharmony_ci if (V8_UNLIKELY(strict_count && actual > drop_values + arity)) { 53151cb0ef41Sopenharmony_ci this->DecodeError("expected %u elements on the stack for %s, found %u", 53161cb0ef41Sopenharmony_ci arity, merge_description, 53171cb0ef41Sopenharmony_ci actual >= drop_values ? actual - drop_values : 0); 53181cb0ef41Sopenharmony_ci return false; 53191cb0ef41Sopenharmony_ci } 53201cb0ef41Sopenharmony_ci // TODO(manoskouk): Use similar code as above if we keep unreachable checks. 53211cb0ef41Sopenharmony_ci for (int i = arity - 1, depth = drop_values; i >= 0; --i, ++depth) { 53221cb0ef41Sopenharmony_ci Peek(depth, i, (*merge)[i].type); 53231cb0ef41Sopenharmony_ci } 53241cb0ef41Sopenharmony_ci if (push_branch_values) { 53251cb0ef41Sopenharmony_ci uint32_t inserted_value_count = 53261cb0ef41Sopenharmony_ci static_cast<uint32_t>(EnsureStackArguments(drop_values + arity)); 53271cb0ef41Sopenharmony_ci if (inserted_value_count > 0) { 53281cb0ef41Sopenharmony_ci // EnsureStackSpace may have inserted unreachable values into the bottom 53291cb0ef41Sopenharmony_ci // of the stack. If so, mark them with the correct type. If drop values 53301cb0ef41Sopenharmony_ci // were also inserted, disregard them, as they will be dropped anyway. 53311cb0ef41Sopenharmony_ci Value* stack_base = stack_value(drop_values + arity); 53321cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < std::min(arity, inserted_value_count); i++) { 53331cb0ef41Sopenharmony_ci if (stack_base[i].type == kWasmBottom) { 53341cb0ef41Sopenharmony_ci stack_base[i].type = (*merge)[i].type; 53351cb0ef41Sopenharmony_ci } 53361cb0ef41Sopenharmony_ci } 53371cb0ef41Sopenharmony_ci } 53381cb0ef41Sopenharmony_ci } 53391cb0ef41Sopenharmony_ci return this->ok(); 53401cb0ef41Sopenharmony_ci } 53411cb0ef41Sopenharmony_ci 53421cb0ef41Sopenharmony_ci template <StackElementsCountMode strict_count, MergeType merge_type> 53431cb0ef41Sopenharmony_ci bool DoReturn() { 53441cb0ef41Sopenharmony_ci if (!VALIDATE((TypeCheckStackAgainstMerge<strict_count, false, merge_type>( 53451cb0ef41Sopenharmony_ci 0, &control_.front().end_merge)))) { 53461cb0ef41Sopenharmony_ci return false; 53471cb0ef41Sopenharmony_ci } 53481cb0ef41Sopenharmony_ci DCHECK_IMPLIES(current_code_reachable_and_ok_, 53491cb0ef41Sopenharmony_ci stack_size() >= this->sig_->return_count()); 53501cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(DoReturn, 0); 53511cb0ef41Sopenharmony_ci EndControl(); 53521cb0ef41Sopenharmony_ci return true; 53531cb0ef41Sopenharmony_ci } 53541cb0ef41Sopenharmony_ci 53551cb0ef41Sopenharmony_ci int startrel(const byte* ptr) { return static_cast<int>(ptr - this->start_); } 53561cb0ef41Sopenharmony_ci 53571cb0ef41Sopenharmony_ci void FallThrough() { 53581cb0ef41Sopenharmony_ci Control* c = &control_.back(); 53591cb0ef41Sopenharmony_ci DCHECK_NE(c->kind, kControlLoop); 53601cb0ef41Sopenharmony_ci if (!VALIDATE(TypeCheckFallThru())) return; 53611cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(FallThruTo, c); 53621cb0ef41Sopenharmony_ci if (c->reachable()) c->end_merge.reached = true; 53631cb0ef41Sopenharmony_ci } 53641cb0ef41Sopenharmony_ci 53651cb0ef41Sopenharmony_ci bool TypeCheckOneArmedIf(Control* c) { 53661cb0ef41Sopenharmony_ci static_assert(validate, "Call this function only within VALIDATE"); 53671cb0ef41Sopenharmony_ci DCHECK(c->is_onearmed_if()); 53681cb0ef41Sopenharmony_ci if (c->end_merge.arity != c->start_merge.arity) { 53691cb0ef41Sopenharmony_ci this->DecodeError(c->pc(), 53701cb0ef41Sopenharmony_ci "start-arity and end-arity of one-armed if must match"); 53711cb0ef41Sopenharmony_ci return false; 53721cb0ef41Sopenharmony_ci } 53731cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < c->start_merge.arity; ++i) { 53741cb0ef41Sopenharmony_ci Value& start = c->start_merge[i]; 53751cb0ef41Sopenharmony_ci Value& end = c->end_merge[i]; 53761cb0ef41Sopenharmony_ci if (!IsSubtypeOf(start.type, end.type, this->module_)) { 53771cb0ef41Sopenharmony_ci this->DecodeError("type error in merge[%u] (expected %s, got %s)", i, 53781cb0ef41Sopenharmony_ci end.type.name().c_str(), start.type.name().c_str()); 53791cb0ef41Sopenharmony_ci return false; 53801cb0ef41Sopenharmony_ci } 53811cb0ef41Sopenharmony_ci } 53821cb0ef41Sopenharmony_ci return true; 53831cb0ef41Sopenharmony_ci } 53841cb0ef41Sopenharmony_ci 53851cb0ef41Sopenharmony_ci bool TypeCheckFallThru() { 53861cb0ef41Sopenharmony_ci static_assert(validate, "Call this function only within VALIDATE"); 53871cb0ef41Sopenharmony_ci return TypeCheckStackAgainstMerge<kStrictCounting, true, kFallthroughMerge>( 53881cb0ef41Sopenharmony_ci 0, &control_.back().end_merge); 53891cb0ef41Sopenharmony_ci } 53901cb0ef41Sopenharmony_ci 53911cb0ef41Sopenharmony_ci // If the current code is reachable, check if the current stack values are 53921cb0ef41Sopenharmony_ci // compatible with a jump to {c}, based on their number and types. 53931cb0ef41Sopenharmony_ci // Otherwise, we have a polymorphic stack: check if any values that may exist 53941cb0ef41Sopenharmony_ci // on top of the stack are compatible with {c}. If {push_branch_values}, 53951cb0ef41Sopenharmony_ci // push back to the stack values based on the type of {c} (this is needed for 53961cb0ef41Sopenharmony_ci // conditional branches due to their typing rules, and fallthroughs so that 53971cb0ef41Sopenharmony_ci // the outer control finds enough values on the stack). 53981cb0ef41Sopenharmony_ci // {drop_values} is the number of stack values that will be dropped before the 53991cb0ef41Sopenharmony_ci // branch is taken. This is currently 1 for for br (condition), br_table 54001cb0ef41Sopenharmony_ci // (index) and br_on_null (reference), and 0 for all other branches. 54011cb0ef41Sopenharmony_ci template <bool push_branch_values> 54021cb0ef41Sopenharmony_ci bool TypeCheckBranch(Control* c, uint32_t drop_values) { 54031cb0ef41Sopenharmony_ci static_assert(validate, "Call this function only within VALIDATE"); 54041cb0ef41Sopenharmony_ci return TypeCheckStackAgainstMerge<kNonStrictCounting, push_branch_values, 54051cb0ef41Sopenharmony_ci kBranchMerge>(drop_values, c->br_merge()); 54061cb0ef41Sopenharmony_ci } 54071cb0ef41Sopenharmony_ci 54081cb0ef41Sopenharmony_ci void onFirstError() override { 54091cb0ef41Sopenharmony_ci this->end_ = this->pc_; // Terminate decoding loop. 54101cb0ef41Sopenharmony_ci this->current_code_reachable_and_ok_ = false; 54111cb0ef41Sopenharmony_ci TRACE(" !%s\n", this->error_.message().c_str()); 54121cb0ef41Sopenharmony_ci // Cannot use CALL_INTERFACE_* macros because we emitted an error. 54131cb0ef41Sopenharmony_ci interface().OnFirstError(this); 54141cb0ef41Sopenharmony_ci } 54151cb0ef41Sopenharmony_ci 54161cb0ef41Sopenharmony_ci int BuildSimplePrototypeOperator(WasmOpcode opcode) { 54171cb0ef41Sopenharmony_ci if (opcode == kExprRefEq) { 54181cb0ef41Sopenharmony_ci CHECK_PROTOTYPE_OPCODE(gc); 54191cb0ef41Sopenharmony_ci } 54201cb0ef41Sopenharmony_ci const FunctionSig* sig = WasmOpcodes::Signature(opcode); 54211cb0ef41Sopenharmony_ci return BuildSimpleOperator(opcode, sig); 54221cb0ef41Sopenharmony_ci } 54231cb0ef41Sopenharmony_ci 54241cb0ef41Sopenharmony_ci int BuildSimpleOperator(WasmOpcode opcode, const FunctionSig* sig) { 54251cb0ef41Sopenharmony_ci DCHECK_GE(1, sig->return_count()); 54261cb0ef41Sopenharmony_ci if (sig->parameter_count() == 1) { 54271cb0ef41Sopenharmony_ci // All current simple unary operators have exactly 1 return value. 54281cb0ef41Sopenharmony_ci DCHECK_EQ(1, sig->return_count()); 54291cb0ef41Sopenharmony_ci return BuildSimpleOperator(opcode, sig->GetReturn(0), sig->GetParam(0)); 54301cb0ef41Sopenharmony_ci } else { 54311cb0ef41Sopenharmony_ci DCHECK_EQ(2, sig->parameter_count()); 54321cb0ef41Sopenharmony_ci ValueType ret = sig->return_count() == 0 ? kWasmVoid : sig->GetReturn(0); 54331cb0ef41Sopenharmony_ci return BuildSimpleOperator(opcode, ret, sig->GetParam(0), 54341cb0ef41Sopenharmony_ci sig->GetParam(1)); 54351cb0ef41Sopenharmony_ci } 54361cb0ef41Sopenharmony_ci } 54371cb0ef41Sopenharmony_ci 54381cb0ef41Sopenharmony_ci int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type, 54391cb0ef41Sopenharmony_ci ValueType arg_type) { 54401cb0ef41Sopenharmony_ci DCHECK_NE(kWasmVoid, return_type); 54411cb0ef41Sopenharmony_ci Value val = Peek(0, 0, arg_type); 54421cb0ef41Sopenharmony_ci Value ret = CreateValue(return_type); 54431cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(UnOp, opcode, val, &ret); 54441cb0ef41Sopenharmony_ci Drop(val); 54451cb0ef41Sopenharmony_ci Push(ret); 54461cb0ef41Sopenharmony_ci return 1; 54471cb0ef41Sopenharmony_ci } 54481cb0ef41Sopenharmony_ci 54491cb0ef41Sopenharmony_ci int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type, 54501cb0ef41Sopenharmony_ci ValueType lhs_type, ValueType rhs_type) { 54511cb0ef41Sopenharmony_ci Value rval = Peek(0, 1, rhs_type); 54521cb0ef41Sopenharmony_ci Value lval = Peek(1, 0, lhs_type); 54531cb0ef41Sopenharmony_ci if (return_type == kWasmVoid) { 54541cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(BinOp, opcode, lval, rval, nullptr); 54551cb0ef41Sopenharmony_ci Drop(2); 54561cb0ef41Sopenharmony_ci } else { 54571cb0ef41Sopenharmony_ci Value ret = CreateValue(return_type); 54581cb0ef41Sopenharmony_ci CALL_INTERFACE_IF_OK_AND_REACHABLE(BinOp, opcode, lval, rval, &ret); 54591cb0ef41Sopenharmony_ci Drop(2); 54601cb0ef41Sopenharmony_ci Push(ret); 54611cb0ef41Sopenharmony_ci } 54621cb0ef41Sopenharmony_ci return 1; 54631cb0ef41Sopenharmony_ci } 54641cb0ef41Sopenharmony_ci 54651cb0ef41Sopenharmony_ci#define DEFINE_SIMPLE_SIG_OPERATOR(sig, ...) \ 54661cb0ef41Sopenharmony_ci int BuildSimpleOperator_##sig(WasmOpcode opcode) { \ 54671cb0ef41Sopenharmony_ci return BuildSimpleOperator(opcode, __VA_ARGS__); \ 54681cb0ef41Sopenharmony_ci } 54691cb0ef41Sopenharmony_ci FOREACH_SIGNATURE(DEFINE_SIMPLE_SIG_OPERATOR) 54701cb0ef41Sopenharmony_ci#undef DEFINE_SIMPLE_SIG_OPERATOR 54711cb0ef41Sopenharmony_ci}; 54721cb0ef41Sopenharmony_ci 54731cb0ef41Sopenharmony_ciclass EmptyInterface { 54741cb0ef41Sopenharmony_ci public: 54751cb0ef41Sopenharmony_ci static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation; 54761cb0ef41Sopenharmony_ci static constexpr DecodingMode decoding_mode = kFunctionBody; 54771cb0ef41Sopenharmony_ci using Value = ValueBase<validate>; 54781cb0ef41Sopenharmony_ci using Control = ControlBase<Value, validate>; 54791cb0ef41Sopenharmony_ci using FullDecoder = WasmFullDecoder<validate, EmptyInterface>; 54801cb0ef41Sopenharmony_ci 54811cb0ef41Sopenharmony_ci#define DEFINE_EMPTY_CALLBACK(name, ...) \ 54821cb0ef41Sopenharmony_ci void name(FullDecoder* decoder, ##__VA_ARGS__) {} 54831cb0ef41Sopenharmony_ci INTERFACE_FUNCTIONS(DEFINE_EMPTY_CALLBACK) 54841cb0ef41Sopenharmony_ci#undef DEFINE_EMPTY_CALLBACK 54851cb0ef41Sopenharmony_ci}; 54861cb0ef41Sopenharmony_ci 54871cb0ef41Sopenharmony_ci#undef CALL_INTERFACE_IF_OK_AND_REACHABLE 54881cb0ef41Sopenharmony_ci#undef CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE 54891cb0ef41Sopenharmony_ci#undef TRACE 54901cb0ef41Sopenharmony_ci#undef TRACE_INST_FORMAT 54911cb0ef41Sopenharmony_ci#undef VALIDATE 54921cb0ef41Sopenharmony_ci#undef CHECK_PROTOTYPE_OPCODE 54931cb0ef41Sopenharmony_ci 54941cb0ef41Sopenharmony_ci} // namespace wasm 54951cb0ef41Sopenharmony_ci} // namespace internal 54961cb0ef41Sopenharmony_ci} // namespace v8 54971cb0ef41Sopenharmony_ci 54981cb0ef41Sopenharmony_ci#endif // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_ 5499