1/*
2 * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WasmSignature.h"
28
29#if ENABLE(WEBASSEMBLY)
30
31#include "WasmSignatureInlines.h"
32#include <wtf/CommaPrinter.h>
33#include <wtf/FastMalloc.h>
34#include <wtf/HashFunctions.h>
35#include <wtf/PrintStream.h>
36#include <wtf/StringPrintStream.h>
37#include <wtf/text/WTFString.h>
38
39namespace JSC { namespace Wasm {
40
41namespace {
42namespace WasmSignatureInternal {
43static constexpr bool verbose = false;
44}
45}
46
47SignatureInformation* SignatureInformation::theOne { nullptr };
48std::once_flag SignatureInformation::signatureInformationFlag;
49
50String Signature::toString() const
51{
52 return WTF::toString(*this);
53}
54
55void Signature::dump(PrintStream& out) const
56{
57 {
58 out.print("(");
59 CommaPrinter comma;
60 for (SignatureArgCount arg = 0; arg < argumentCount(); ++arg)
61 out.print(comma, makeString(argument(arg)));
62 out.print(")");
63 }
64
65 {
66 CommaPrinter comma;
67 out.print(" -> [");
68 for (SignatureArgCount ret = 0; ret < returnCount(); ++ret)
69 out.print(comma, makeString(returnType(ret)));
70 out.print("]");
71 }
72}
73
74static unsigned computeHash(size_t returnCount, const Type* returnTypes, size_t argumentCount, const Type* argumentTypes)
75{
76 unsigned accumulator = 0xa1bcedd8u;
77 for (uint32_t i = 0; i < argumentCount; ++i)
78 accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(argumentTypes[i])));
79 for (uint32_t i = 0; i < returnCount; ++i)
80 accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(returnTypes[i])));
81 return accumulator;
82}
83
84unsigned Signature::hash() const
85{
86 return computeHash(returnCount(), storage(0), argumentCount(), storage(returnCount()));
87}
88
89RefPtr<Signature> Signature::tryCreate(SignatureArgCount returnCount, SignatureArgCount argumentCount)
90{
91 // We use WTF_MAKE_FAST_ALLOCATED for this class.
92 auto result = tryFastMalloc(allocatedSize(returnCount, argumentCount));
93 void* memory = nullptr;
94 if (!result.getValue(memory))
95 return nullptr;
96 Signature* signature = new (NotNull, memory) Signature(returnCount, argumentCount);
97 return adoptRef(signature);
98}
99
100SignatureInformation::SignatureInformation()
101{
102#define MAKE_THUNK_SIGNATURE(type, enc, str, val) \
103 do { \
104 if (type != Void) { \
105 RefPtr<Signature> sig = Signature::tryCreate(1, 0); \
106 sig->ref(); \
107 sig->getReturnType(0) = type; \
108 thunkSignatures[linearizeType(type)] = sig.get(); \
109 m_signatureSet.add(SignatureHash { sig.releaseNonNull() }); \
110 } \
111 } while (false);
112
113 FOR_EACH_WASM_TYPE(MAKE_THUNK_SIGNATURE);
114
115 // Make Void again because we don't use the one that has void in it.
116 {
117 RefPtr<Signature> sig = Signature::tryCreate(0, 0);
118 sig->ref();
119 thunkSignatures[linearizeType(Void)] = sig.get();
120 m_signatureSet.add(SignatureHash { sig.releaseNonNull() });
121 }
122}
123
124
125
126struct ParameterTypes {
127 const Vector<Type, 1>& returnTypes;
128 const Vector<Type>& argumentTypes;
129
130 static unsigned hash(const ParameterTypes& params)
131 {
132 return computeHash(params.returnTypes.size(), params.returnTypes.data(), params.argumentTypes.size(), params.argumentTypes.data());
133 }
134
135 static bool equal(const SignatureHash& sig, const ParameterTypes& params)
136 {
137 if (sig.key->argumentCount() != params.argumentTypes.size())
138 return false;
139 if (sig.key->returnCount() != params.returnTypes.size())
140 return false;
141
142 for (unsigned i = 0; i < sig.key->argumentCount(); ++i) {
143 if (sig.key->argument(i) != params.argumentTypes[i])
144 return false;
145 }
146
147 for (unsigned i = 0; i < sig.key->returnCount(); ++i) {
148 if (sig.key->returnType(i) != params.returnTypes[i])
149 return false;
150 }
151 return true;
152 }
153
154 static void translate(SignatureHash& entry, const ParameterTypes& params, unsigned)
155 {
156 RefPtr<Signature> signature = Signature::tryCreate(params.returnTypes.size(), params.argumentTypes.size());
157 RELEASE_ASSERT(signature);
158
159 for (unsigned i = 0; i < params.returnTypes.size(); ++i)
160 signature->getReturnType(i) = params.returnTypes[i];
161
162 for (unsigned i = 0; i < params.argumentTypes.size(); ++i)
163 signature->getArgument(i) = params.argumentTypes[i];
164
165 entry.key = WTFMove(signature);
166 }
167};
168
169RefPtr<Signature> SignatureInformation::signatureFor(const Vector<Type, 1>& results, const Vector<Type>& args)
170{
171 SignatureInformation& info = singleton();
172 LockHolder lock(info.m_lock);
173
174 auto addResult = info.m_signatureSet.template add<ParameterTypes>(ParameterTypes { results, args });
175 return makeRef(*addResult.iterator->key);
176}
177
178void SignatureInformation::tryCleanup()
179{
180 SignatureInformation& info = singleton();
181 LockHolder lock(info.m_lock);
182
183 info.m_signatureSet.removeIf([&] (auto& hash) {
184 const auto& signature = hash.key;
185 return signature->refCount() == 1;
186 });
187}
188
189} } // namespace JSC::Wasm
190
191#endif // ENABLE(WEBASSEMBLY)
192