blob: fb9bf7bd709573659e65269d205923afaba1a76c [file] [log] [blame]
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/wasm/value-type.h"
#include "src/codegen/signature.h"
#include "src/utils/utils.h"
#include "src/wasm/canonical-types.h"
#include "src/wasm/signature-hashing.h"
namespace v8::internal::wasm {
namespace value_type_impl {
// Check that {kGenericKindMask} is defined appropriately.
#define CHECK_MASK(kind, ...) \
static_assert( \
static_cast<uint32_t>(GenericKind::k##kind) == \
(static_cast<uint32_t>(GenericKind::k##kind) & kGenericKindMask));
FOREACH_GENERIC_TYPE(CHECK_MASK)
#undef CHECK_MASK
#define CHECK_MASK(kind, ...) \
static_assert( \
static_cast<uint32_t>(NumericKind::k##kind) == \
(static_cast<uint32_t>(NumericKind::k##kind) & kNumericKindMask));
FOREACH_NUMERIC_VALUE_TYPE(CHECK_MASK)
#undef CHECK_MASK
// Check correctness of enum conversions.
static_assert(0 == ToZeroBasedIndex(NumericKind::kI32));
} // namespace value_type_impl
static_assert(kWasmBottom.is_bottom());
static_assert(kWasmTop.is_top());
ValueTypeCode ValueTypeBase::value_type_code_numeric() const {
switch (numeric_kind()) {
#define NUMERIC_CASE(kind, ...) \
case NumericKind::k##kind: \
return k##kind##Code;
FOREACH_NUMERIC_VALUE_TYPE(NUMERIC_CASE)
#undef NUMERIC_CASE
}
UNREACHABLE();
}
ValueTypeCode ValueTypeBase::value_type_code_generic() const {
switch (generic_kind()) {
#define ABSTRACT_TYPE_CASE(name, code, ...) \
case GenericKind::k##name: \
return k##code##Code;
FOREACH_ABSTRACT_TYPE(ABSTRACT_TYPE_CASE)
#undef ABSTRACT_TYPE_CASE
// Among "internal" types, only "void" has a wire bytes encoding.
#define INTERNAL_TYPE_CASE(name, code, ...) \
case GenericKind::k##name: \
if constexpr (GenericKind::k##name == GenericKind::kVoid) { \
return k##code##Code; \
} else { \
UNREACHABLE(); \
}
FOREACH_INTERNAL_TYPE(INTERNAL_TYPE_CASE)
#undef INTERNAL_TYPE_CASE
}
UNREACHABLE();
}
std::string ValueTypeBase::generic_heaptype_name() const {
DCHECK(is_generic());
std::ostringstream buf;
if (is_shared()) buf << "shared ";
switch (generic_kind()) {
#define GENERIC_CASE(kind, code, typekind, name) \
case GenericKind::k##kind: \
buf << name; \
return buf.str();
FOREACH_GENERIC_TYPE(GENERIC_CASE)
#undef GENERIC_CASE
}
UNREACHABLE();
}
std::string ValueTypeBase::name() const {
if (is_numeric()) {
switch (numeric_kind()) {
#define NUMERIC_CASE(kind, log2, code, mtype, shortName, name) \
case NumericKind::k##kind: \
return name;
FOREACH_NUMERIC_VALUE_TYPE(NUMERIC_CASE)
#undef NUMERIC_CASE
}
UNREACHABLE();
}
std::ostringstream buf;
if (has_index()) {
buf << "(ref ";
if (is_nullable()) buf << "null ";
buf << raw_index().index << ")";
} else {
DCHECK(is_generic());
if (is_nullable()) {
GenericKind kind = generic_kind();
if (kind == GenericKind::kNone) {
// The code below would produce "noneref", and we need to keep it
// that way for "(ref none)", so we need this special case.
return "nullref";
} else if (kind == GenericKind::kNoExn) {
return "nullexnref";
} else if (kind == GenericKind::kNoExtern) {
return "nullexternref";
} else if (kind == GenericKind::kNoFunc) {
return "nullfuncref";
} else if (kind == GenericKind::kNoCont) {
return "nullcontref";
}
}
bool shorthand = is_nullable() || is_sentinel() || is_string_view();
bool append_ref = is_nullable() && !is_sentinel();
if (!shorthand) buf << "(ref ";
buf << generic_heaptype_name();
if (append_ref) buf << "ref";
if (!shorthand) buf << ")";
}
return buf.str();
}
std::optional<wasm::ValueKind> WasmReturnTypeFromSignature(
const CanonicalSig* wasm_signature) {
if (wasm_signature->return_count() == 0) return {};
DCHECK_EQ(wasm_signature->return_count(), 1);
CanonicalValueType return_type = wasm_signature->GetReturn(0);
return {return_type.kind()};
}
bool EquivalentNumericSig(const CanonicalSig* a, const FunctionSig* b) {
if (a->parameter_count() != b->parameter_count()) return false;
if (a->return_count() != b->return_count()) return false;
base::Vector<const CanonicalValueType> a_types = a->all();
base::Vector<const ValueType> b_types = b->all();
for (size_t i = 0; i < a_types.size(); i++) {
if (!a_types[i].is_numeric()) return false;
if (a_types[i].kind() != b_types[i].kind()) return false;
}
return true;
}
#if DEBUG
V8_EXPORT_PRIVATE extern void PrintFunctionSig(const wasm::FunctionSig* sig) {
std::ostringstream os;
os << sig->parameter_count() << " parameters:\n";
for (size_t i = 0; i < sig->parameter_count(); i++) {
os << " " << i << ": " << sig->GetParam(i) << "\n";
}
os << sig->return_count() << " returns:\n";
for (size_t i = 0; i < sig->return_count(); i++) {
os << " " << i << ": " << sig->GetReturn() << "\n";
}
PrintF("%s", os.str().c_str());
}
#endif
namespace {
const wasm::FunctionSig* ReplaceTypeInSig(Zone* zone,
const wasm::FunctionSig* sig,
wasm::ValueType from,
wasm::ValueType to,
size_t num_replacements) {
size_t param_occurences =
std::count(sig->parameters().begin(), sig->parameters().end(), from);
size_t return_occurences =
std::count(sig->returns().begin(), sig->returns().end(), from);
if (param_occurences == 0 && return_occurences == 0) return sig;
wasm::FunctionSig::Builder builder(
zone, sig->return_count() + return_occurences * (num_replacements - 1),
sig->parameter_count() + param_occurences * (num_replacements - 1));
for (wasm::ValueType ret : sig->returns()) {
if (ret == from) {
for (size_t i = 0; i < num_replacements; i++) builder.AddReturn(to);
} else {
builder.AddReturn(ret);
}
}
for (wasm::ValueType param : sig->parameters()) {
if (param == from) {
for (size_t i = 0; i < num_replacements; i++) builder.AddParam(to);
} else {
builder.AddParam(param);
}
}
return builder.Get();
}
} // namespace
const wasm::FunctionSig* GetI32Sig(Zone* zone, const wasm::FunctionSig* sig) {
return ReplaceTypeInSig(zone, sig, wasm::kWasmI64, wasm::kWasmI32, 2);
}
CanonicalSig* CanonicalSig::Builder::Get() const {
CanonicalSig* sig =
reinterpret_cast<
const SignatureBuilder<CanonicalSig, CanonicalValueType>*>(this)
->Get();
sig->signature_hash_ = wasm::SignatureHasher::Hash(sig);
return sig;
}
} // namespace v8::internal::wasm