blob: 3a8740350bbba36f4e7eea394c57e8e76e98d57d [file] [log] [blame]
/*
* Copyright 2022 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef wasm_wasm_type_printing_h
#define wasm_wasm_type_printing_h
#include <cstddef>
#include <iostream>
#include <unordered_map>
#include "support/name.h"
#include "support/utilities.h"
#include "wasm-type.h"
#include "wasm.h"
namespace wasm {
// CRTP base that all other type name generators should subclass. Provides the
// ability to use the generator as a function to print Types and HeapTypes to
// streams.
template<typename Subclass> struct TypeNameGeneratorBase {
TypeNames getNames(HeapType type) {
static_assert(&TypeNameGeneratorBase<Subclass>::getNames !=
&Subclass::getNames,
"Derived class must implement getNames");
WASM_UNREACHABLE("Derived class must implement getNames");
}
HeapType::Printed operator()(HeapType type) {
return type.print(
[&](HeapType ht) { return static_cast<Subclass*>(this)->getNames(ht); });
}
Type::Printed operator()(Type type) {
return type.print(
[&](HeapType ht) { return static_cast<Subclass*>(this)->getNames(ht); });
}
};
// Generates names like "func.0", "struct.1", "array.2", etc. Struct fields are
// not given names.
struct DefaultTypeNameGenerator
: TypeNameGeneratorBase<DefaultTypeNameGenerator> {
size_t funcCount = 0;
size_t structCount = 0;
size_t arrayCount = 0;
// Cached names for types that have already been seen.
std::unordered_map<HeapType, TypeNames> nameCache;
TypeNames getNames(HeapType type);
};
// Generates names based on the indices of types in some collection, falling
// back to the given FallbackGenerator when encountering a type not in the
// collection. Struct fields are not given names.
template<typename FallbackGenerator = DefaultTypeNameGenerator>
struct IndexedTypeNameGenerator
: TypeNameGeneratorBase<IndexedTypeNameGenerator<FallbackGenerator>> {
DefaultTypeNameGenerator defaultGenerator;
FallbackGenerator& fallback;
std::unordered_map<HeapType, TypeNames> names;
template<typename T>
IndexedTypeNameGenerator(T& types,
FallbackGenerator& fallback,
const std::string& prefix = "")
: fallback(fallback) {
for (size_t i = 0; i < types.size(); ++i) {
names.insert({types[i], {prefix + std::to_string(i), {}}});
}
}
template<typename T>
IndexedTypeNameGenerator(T& types, const std::string& prefix = "")
: IndexedTypeNameGenerator(types, defaultGenerator, prefix) {}
TypeNames getNames(HeapType type) {
if (auto it = names.find(type); it != names.end()) {
return it->second;
} else {
return fallback.getNames(type);
}
}
};
// Prints heap types stored in a module, falling back to the given
// FallbackGenerator if the module does not have a name for type type.
template<typename FallbackGenerator = DefaultTypeNameGenerator>
struct ModuleTypeNameGenerator
: TypeNameGeneratorBase<ModuleTypeNameGenerator<FallbackGenerator>> {
const Module& wasm;
DefaultTypeNameGenerator defaultGenerator;
FallbackGenerator& fallback;
ModuleTypeNameGenerator(const Module& wasm, FallbackGenerator& fallback)
: wasm(wasm), fallback(fallback) {}
// TODO: Use C++20 `requires` to clean this up.
template<class T = FallbackGenerator>
ModuleTypeNameGenerator(
const Module& wasm,
std::enable_if_t<std::is_same_v<T, DefaultTypeNameGenerator>>* = nullptr)
: ModuleTypeNameGenerator(wasm, defaultGenerator) {}
TypeNames getNames(HeapType type) {
if (auto it = wasm.typeNames.find(type); it != wasm.typeNames.end()) {
return it->second;
}
return fallback.getNames(type);
}
};
} // namespace wasm
#endif // wasm_wasm_type_printing_h