v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
value-type.cc
Go to the documentation of this file.
1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
8#include "src/utils/utils.h"
11
12namespace v8::internal::wasm {
13
14namespace value_type_impl {
15
16// Check that {kGenericKindMask} is defined appropriately.
17#define CHECK_MASK(kind, ...) \
18 static_assert( \
19 static_cast<uint32_t>(GenericKind::k##kind) == \
20 (static_cast<uint32_t>(GenericKind::k##kind) & kGenericKindMask));
22#undef CHECK_MASK
23#define CHECK_MASK(kind, ...) \
24 static_assert( \
25 static_cast<uint32_t>(NumericKind::k##kind) == \
26 (static_cast<uint32_t>(NumericKind::k##kind) & kNumericKindMask));
28#undef CHECK_MASK
29
30// Check correctness of enum conversions.
31static_assert(0 == ToZeroBasedIndex(NumericKind::kI32));
32
33// Some subtyping-related code relies on none-types having the "is_exact" bit.
34#define CHECK_EXACT(kind, ...) \
35 static_assert(IndependentHeapType{GenericKind::k##kind}.is_exact());
37#undef CHECK_EXACT
38
39} // namespace value_type_impl
40
41static_assert(kWasmBottom.is_bottom());
42static_assert(kWasmTop.is_top());
43
45 switch (numeric_kind()) {
46#define NUMERIC_CASE(kind, ...) \
47 case NumericKind::k##kind: \
48 return k##kind##Code;
50#undef NUMERIC_CASE
51 }
53}
54
56 switch (generic_kind()) {
57#define ABSTRACT_TYPE_CASE(name, code, ...) \
58 case GenericKind::k##name: \
59 return k##code##Code;
61#undef ABSTRACT_TYPE_CASE
62 // Among "internal" types, only "void" has a wire bytes encoding.
63#define INTERNAL_TYPE_CASE(name, code, ...) \
64 case GenericKind::k##name: \
65 if constexpr (GenericKind::k##name == GenericKind::kVoid) { \
66 return k##code##Code; \
67 } else { \
68 UNREACHABLE(); \
69 }
71#undef INTERNAL_TYPE_CASE
72 }
74}
75
78 std::ostringstream buf;
79 if (is_shared()) buf << "shared ";
80 switch (generic_kind()) {
81#define GENERIC_CASE(kind, code, typekind, name) \
82 case GenericKind::k##kind: \
83 buf << name; \
84 return buf.str();
86#undef GENERIC_CASE
87 }
89}
90
91namespace {
92
93void PrintGenericHeaptypeName(std::ostringstream& buf, ValueTypeBase type) {
94 DCHECK(type.is_generic());
95 if (type.is_nullable()) {
96 GenericKind kind = type.generic_kind();
97 if (kind == GenericKind::kNone) {
98 // The code below would produce "noneref", and we need to keep it
99 // that way for "(ref none)", so we need this special case.
100 buf << "nullref";
101 return;
102 } else if (kind == GenericKind::kNoExn) {
103 buf << "nullexnref";
104 return;
105 } else if (kind == GenericKind::kNoExtern) {
106 buf << "nullexternref";
107 return;
108 } else if (kind == GenericKind::kNoFunc) {
109 buf << "nullfuncref";
110 return;
111 } else if (kind == GenericKind::kNoCont) {
112 buf << "nullcontref";
113 return;
114 }
115 }
116 buf << type.generic_heaptype_name();
117}
118
119} // namespace
120
121std::string ValueTypeBase::name() const {
122 if (is_numeric()) {
123 switch (numeric_kind()) {
124#define NUMERIC_CASE(kind, log2, code, mtype, shortName, name) \
125 case NumericKind::k##kind: \
126 return name;
128#undef NUMERIC_CASE
129 }
130 UNREACHABLE();
131 }
132 std::ostringstream buf;
133 if (has_index()) {
134 buf << "(ref ";
135 if (is_nullable()) buf << "null ";
136 if (is_exact()) buf << "exact ";
137 buf << raw_index().index << ")";
138 } else {
140 if (is_nullable()) {
142 if (kind == GenericKind::kNone) {
143 // The code below would produce "noneref", and we need to keep it
144 // that way for "(ref none)", so we need this special case.
145 return "nullref";
146 } else if (kind == GenericKind::kNoExn) {
147 return "nullexnref";
148 } else if (kind == GenericKind::kNoExtern) {
149 return "nullexternref";
150 } else if (kind == GenericKind::kNoFunc) {
151 return "nullfuncref";
152 } else if (kind == GenericKind::kNoCont) {
153 return "nullcontref";
154 }
155 }
156 bool shorthand =
158 bool append_ref = is_nullable() && !is_sentinel() && !is_exact();
159 if (!shorthand) buf << "(ref ";
160 if (!shorthand && is_nullable()) buf << "null ";
161 PrintGenericHeaptypeName(buf, *this);
162 if (append_ref) buf << "ref";
163 if (!shorthand) buf << ")";
164 }
165 return buf.str();
166}
167
168std::optional<wasm::ValueKind> WasmReturnTypeFromSignature(
169 const CanonicalSig* wasm_signature) {
170 if (wasm_signature->return_count() == 0) return {};
171
172 DCHECK_EQ(wasm_signature->return_count(), 1);
173 CanonicalValueType return_type = wasm_signature->GetReturn(0);
174 return {return_type.kind()};
175}
176
178 if (a->parameter_count() != b->parameter_count()) return false;
179 if (a->return_count() != b->return_count()) return false;
181 base::Vector<const ValueType> b_types = b->all();
182 for (size_t i = 0; i < a_types.size(); i++) {
183 if (!a_types[i].is_numeric()) return false;
184 if (a_types[i].kind() != b_types[i].kind()) return false;
185 }
186 return true;
187}
188
189#if DEBUG
190V8_EXPORT_PRIVATE extern void PrintFunctionSig(const wasm::FunctionSig* sig) {
191 std::ostringstream os;
192 os << sig->parameter_count() << " parameters:\n";
193 for (size_t i = 0; i < sig->parameter_count(); i++) {
194 os << " " << i << ": " << sig->GetParam(i) << "\n";
195 }
196 os << sig->return_count() << " returns:\n";
197 for (size_t i = 0; i < sig->return_count(); i++) {
198 os << " " << i << ": " << sig->GetReturn() << "\n";
199 }
200 PrintF("%s", os.str().c_str());
201}
202#endif
203
204namespace {
205const wasm::FunctionSig* ReplaceTypeInSig(Zone* zone,
206 const wasm::FunctionSig* sig,
207 wasm::ValueType from,
208 wasm::ValueType to,
209 size_t num_replacements) {
210 size_t param_occurences =
211 std::count(sig->parameters().begin(), sig->parameters().end(), from);
212 size_t return_occurences =
213 std::count(sig->returns().begin(), sig->returns().end(), from);
214 if (param_occurences == 0 && return_occurences == 0) return sig;
215
217 zone, sig->return_count() + return_occurences * (num_replacements - 1),
218 sig->parameter_count() + param_occurences * (num_replacements - 1));
219
220 for (wasm::ValueType ret : sig->returns()) {
221 if (ret == from) {
222 for (size_t i = 0; i < num_replacements; i++) builder.AddReturn(to);
223 } else {
224 builder.AddReturn(ret);
225 }
226 }
227
228 for (wasm::ValueType param : sig->parameters()) {
229 if (param == from) {
230 for (size_t i = 0; i < num_replacements; i++) builder.AddParam(to);
231 } else {
232 builder.AddParam(param);
233 }
234 }
235
236 return builder.Get();
237}
238} // namespace
239
241 return ReplaceTypeInSig(zone, sig, wasm::kWasmI64, wasm::kWasmI32, 2);
242}
243
246 reinterpret_cast<
248 ->Get();
249 sig->signature_hash_ = wasm::SignatureHasher::Hash(sig);
250 return sig;
251}
252
253} // namespace v8::internal::wasm
friend Zone
Definition asm-types.cc:195
Builtins::Kind kind
Definition builtins.cc:40
constexpr size_t size() const
Definition vector.h:70
size_t return_count() const
Definition signature.h:93
T GetReturn(size_t index=0) const
Definition signature.h:103
SignatureBuilder< Signature< T >, T > Builder
Definition signature.h:130
size_t parameter_count() const
Definition signature.h:94
base::Vector< const T > all() const
Definition signature.h:117
static uint64_t Hash(const SigType *sig)
V8_EXPORT_PRIVATE ValueTypeCode value_type_code_numeric() const
Definition value-type.cc:44
V8_EXPORT_PRIVATE std::string generic_heaptype_name() const
Definition value-type.cc:76
V8_EXPORT_PRIVATE ValueTypeCode value_type_code_generic() const
Definition value-type.cc:55
constexpr TypeIndex raw_index() const
Definition value-type.h:699
constexpr bool is_sentinel() const
Definition value-type.h:370
constexpr NumericKind numeric_kind() const
Definition value-type.h:415
constexpr bool is_bottom() const
Definition value-type.h:426
constexpr ValueKind kind() const
Definition value-type.h:631
constexpr bool is_shared() const
Definition value-type.h:403
constexpr bool is_string_view() const
Definition value-type.h:438
constexpr bool has_index() const
Definition value-type.h:367
constexpr bool is_generic() const
Definition value-type.h:384
constexpr bool is_numeric() const
Definition value-type.h:373
constexpr bool is_nullable() const
Definition value-type.h:393
constexpr bool is_exact() const
Definition value-type.h:402
V8_EXPORT_PRIVATE std::string name() const
constexpr bool is_top() const
Definition value-type.h:430
constexpr GenericKind generic_kind() const
Definition value-type.h:420
constexpr uint32_t ToZeroBasedIndex(NumericKind kind)
Definition value-type.h:305
bool EquivalentNumericSig(const CanonicalSig *a, const FunctionSig *b)
std::optional< wasm::ValueKind > WasmReturnTypeFromSignature(const CanonicalSig *wasm_signature)
constexpr IndependentValueType kWasmI32
const wasm::FunctionSig * GetI32Sig(Zone *zone, const wasm::FunctionSig *sig)
constexpr IndependentHeapType kWasmTop
constexpr IndependentHeapType kWasmBottom
Signature< ValueType > FunctionSig
constexpr IndependentValueType kWasmI64
void PrintF(const char *format,...)
Definition utils.cc:39
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define INTERNAL_TYPE_CASE(name, code,...)
#define CHECK_EXACT(kind,...)
Definition value-type.cc:34
#define NUMERIC_CASE(kind,...)
#define GENERIC_CASE(kind, code, typekind, name)
#define ABSTRACT_TYPE_CASE(name, code,...)
#define CHECK_MASK(kind,...)
Definition value-type.cc:17
#define FOREACH_NUMERIC_VALUE_TYPE(V)
Definition value-type.h:31
#define FOREACH_ABSTRACT_TYPE(V)
Definition value-type.h:175
#define FOREACH_NONE_TYPE(V)
Definition value-type.h:168
#define FOREACH_INTERNAL_TYPE(V)
Definition value-type.h:195