blob: b44891cc31f7d51f9d5b2d5915b300c30431b4bb [file] [log] [blame]
/*
* Copyright (C) 2016-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WasmTypeDefinition.h"
#if ENABLE(WEBASSEMBLY)
#include "WasmTypeDefinitionInlines.h"
#include <wtf/CommaPrinter.h>
#include <wtf/FastMalloc.h>
#include <wtf/StringPrintStream.h>
namespace JSC { namespace Wasm {
String TypeDefinition::toString() const
{
return WTF::toString(*this);
}
void TypeDefinition::dump(PrintStream& out) const
{
if (is<FunctionSignature>())
return as<FunctionSignature>()->dump(out);
ASSERT(is<StructType>());
return as<StructType>()->dump(out);
}
String FunctionSignature::toString() const
{
return WTF::toString(*this);
}
void FunctionSignature::dump(PrintStream& out) const
{
{
out.print("(");
CommaPrinter comma;
for (FunctionArgCount arg = 0; arg < argumentCount(); ++arg)
out.print(comma, makeString(argumentType(arg).kind));
out.print(")");
}
{
CommaPrinter comma;
out.print(" -> [");
for (FunctionArgCount ret = 0; ret < returnCount(); ++ret)
out.print(comma, makeString(returnType(ret).kind));
out.print("]");
}
}
String StructType::toString() const
{
return WTF::toString(*this);
}
void StructType::dump(PrintStream& out) const
{
out.print("(");
CommaPrinter comma;
for (StructFieldCount fieldIndex = 0; fieldIndex < fieldCount(); ++fieldIndex) {
out.print(comma, makeString(field(fieldIndex).type.kind));
out.print(comma, field(fieldIndex).mutability ? "immutable" : "mutable");
}
out.print(")");
}
static unsigned computeSignatureHash(size_t returnCount, const Type* returnTypes, size_t argumentCount, const Type* argumentTypes)
{
unsigned accumulator = 0xa1bcedd8u;
for (uint32_t i = 0; i < argumentCount; ++i) {
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(argumentTypes[i].kind)));
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(argumentTypes[i].nullable)));
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<unsigned>::hash(argumentTypes[i].index));
}
for (uint32_t i = 0; i < returnCount; ++i) {
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(returnTypes[i].kind)));
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(returnTypes[i].nullable)));
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<unsigned>::hash(returnTypes[i].index));
}
return accumulator;
}
static unsigned computeStructTypeHash(size_t fieldCount, const StructField* fields)
{
unsigned accumulator = 0x15d2546;
for (uint32_t i = 0; i < fieldCount; ++i) {
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(fields[i].type.kind)));
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(fields[i].type.nullable)));
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(fields[i].type.index)));
accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(fields[i].mutability)));
}
return accumulator;
}
unsigned TypeDefinition::hash() const
{
if (is<FunctionSignature>()) {
const FunctionSignature* signature = as<FunctionSignature>();
return computeSignatureHash(signature->returnCount(), signature->storage(0), signature->argumentCount(), signature->storage(signature->returnCount()));
}
ASSERT(is<StructType>());
const StructType* structType = as<StructType>();
return computeStructTypeHash(structType->fieldCount(), structType->storage(0));
}
RefPtr<TypeDefinition> TypeDefinition::tryCreateFunctionSignature(FunctionArgCount returnCount, FunctionArgCount argumentCount)
{
// We use WTF_MAKE_FAST_ALLOCATED for this class.
auto result = tryFastMalloc(allocatedFunctionSize(returnCount, argumentCount));
void* memory = nullptr;
if (!result.getValue(memory))
return nullptr;
TypeDefinition* signature = new (NotNull, memory) TypeDefinition(returnCount, argumentCount);
return adoptRef(signature);
}
RefPtr<TypeDefinition> TypeDefinition::tryCreateStructType(StructFieldCount fieldCount)
{
// We use WTF_MAKE_FAST_ALLOCATED for this class.
auto result = tryFastMalloc(allocatedStructSize(fieldCount));
void* memory = nullptr;
if (!result.getValue(memory))
return nullptr;
TypeDefinition* signature = new (NotNull, memory) TypeDefinition(fieldCount);
return adoptRef(signature);
}
TypeInformation::TypeInformation()
{
#define MAKE_THUNK_SIGNATURE(type, enc, str, val, _) \
do { \
if (TypeKind::type != TypeKind::Void) { \
RefPtr<TypeDefinition> sig = TypeDefinition::tryCreateFunctionSignature(1, 0); \
sig->ref(); \
sig->as<FunctionSignature>()->getReturnType(0) = Types::type; \
thunkTypes[linearizeType(TypeKind::type)] = sig.get(); \
m_typeSet.add(TypeHash { sig.releaseNonNull() }); \
} \
} while (false);
FOR_EACH_WASM_TYPE(MAKE_THUNK_SIGNATURE);
// Make Void again because we don't use the one that has void in it.
{
RefPtr<TypeDefinition> sig = TypeDefinition::tryCreateFunctionSignature(0, 0);
sig->ref();
thunkTypes[linearizeType(TypeKind::Void)] = sig.get();
m_typeSet.add(TypeHash { sig.releaseNonNull() });
}
}
struct FunctionParameterTypes {
const Vector<Type, 1>& returnTypes;
const Vector<Type>& argumentTypes;
static unsigned hash(const FunctionParameterTypes& params)
{
return computeSignatureHash(params.returnTypes.size(), params.returnTypes.data(), params.argumentTypes.size(), params.argumentTypes.data());
}
static bool equal(const TypeHash& sig, const FunctionParameterTypes& params)
{
if (sig.key->is<StructType>())
return false;
const FunctionSignature* signature = sig.key->as<FunctionSignature>();
if (signature->argumentCount() != params.argumentTypes.size())
return false;
if (signature->returnCount() != params.returnTypes.size())
return false;
for (unsigned i = 0; i < signature->argumentCount(); ++i) {
if (signature->argumentType(i) != params.argumentTypes[i])
return false;
}
for (unsigned i = 0; i < signature->returnCount(); ++i) {
if (signature->returnType(i) != params.returnTypes[i])
return false;
}
return true;
}
static void translate(TypeHash& entry, const FunctionParameterTypes& params, unsigned)
{
RefPtr<TypeDefinition> signature = TypeDefinition::tryCreateFunctionSignature(params.returnTypes.size(), params.argumentTypes.size());
RELEASE_ASSERT(signature);
for (unsigned i = 0; i < params.returnTypes.size(); ++i)
signature->as<FunctionSignature>()->getReturnType(i) = params.returnTypes[i];
for (unsigned i = 0; i < params.argumentTypes.size(); ++i)
signature->as<FunctionSignature>()->getArgumentType(i) = params.argumentTypes[i];
entry.key = WTFMove(signature);
}
};
struct StructParameterTypes {
const Vector<StructField>& fields;
static unsigned hash(const StructParameterTypes& params)
{
return computeStructTypeHash(params.fields.size(), params.fields.data());
}
static bool equal(const TypeHash& sig, const StructParameterTypes& params)
{
if (sig.key->is<FunctionSignature>())
return false;
const StructType* structType = sig.key->as<StructType>();
if (structType->fieldCount() != params.fields.size())
return false;
for (unsigned i = 0; i < structType->fieldCount(); ++i) {
if (structType->field(i) != params.fields[i])
return false;
}
return true;
}
static void translate(TypeHash& entry, const StructParameterTypes& params, unsigned)
{
RefPtr<TypeDefinition> signature = TypeDefinition::tryCreateStructType(params.fields.size());
RELEASE_ASSERT(signature);
StructType* structType = signature->as<StructType>();
for (unsigned i = 0; i < params.fields.size(); ++i)
structType->getField(i) = params.fields[i];
entry.key = WTFMove(signature);
}
};
RefPtr<TypeDefinition> TypeInformation::typeDefinitionForFunction(const Vector<Type, 1>& results, const Vector<Type>& args)
{
if constexpr (ASSERT_ENABLED) {
ASSERT(!results.contains(Wasm::Types::Void));
ASSERT(!args.contains(Wasm::Types::Void));
}
TypeInformation& info = singleton();
Locker locker { info.m_lock };
auto addResult = info.m_typeSet.template add<FunctionParameterTypes>(FunctionParameterTypes { results, args });
return addResult.iterator->key;
}
RefPtr<TypeDefinition> TypeInformation::typeDefinitionForStruct(const Vector<StructField>& fields)
{
TypeInformation& info = singleton();
Locker locker { info.m_lock };
auto addResult = info.m_typeSet.template add<StructParameterTypes>(StructParameterTypes { fields });
return addResult.iterator->key;
}
void TypeInformation::tryCleanup()
{
TypeInformation& info = singleton();
Locker locker { info.m_lock };
info.m_typeSet.removeIf([&] (auto& hash) {
const auto& signature = hash.key;
return signature->refCount() == 1;
});
}
} } // namespace JSC::Wasm
#endif // ENABLE(WEBASSEMBLY)