1/*
2 * Copyright (C) 2016-2017 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#pragma once
27
28#if ENABLE(WEBASSEMBLY)
29
30#include "B3Type.h"
31#include "WasmOps.h"
32#include <cstdint>
33#include <cstring>
34#include <wtf/CheckedArithmetic.h>
35#include <wtf/HashMap.h>
36#include <wtf/HashSet.h>
37#include <wtf/HashTraits.h>
38#include <wtf/StdLibExtras.h>
39#include <wtf/ThreadSafeRefCounted.h>
40#include <wtf/Vector.h>
41
42namespace WTF {
43class PrintStream;
44}
45
46namespace JSC {
47
48namespace Wasm {
49
50using SignatureArgCount = uint32_t;
51using SignatureIndex = uint64_t;
52
53class Signature : public ThreadSafeRefCounted<Signature> {
54 WTF_MAKE_FAST_ALLOCATED;
55 static const constexpr SignatureArgCount s_retCount = 1;
56
57 Signature() = delete;
58 Signature(const Signature&) = delete;
59 Signature(SignatureArgCount argCount)
60 : m_argCount(argCount)
61 {
62 }
63
64 Type* storage(SignatureArgCount i)
65 {
66 return i + reinterpret_cast<Type*>(reinterpret_cast<char*>(this) + sizeof(Signature));
67 }
68 Type* storage(SignatureArgCount i) const { return const_cast<Signature*>(this)->storage(i); }
69 static size_t allocatedSize(Checked<SignatureArgCount> argCount)
70 {
71 return (sizeof(Signature) + (s_retCount + argCount) * sizeof(Type)).unsafeGet();
72 }
73
74public:
75 Type& returnType() { return *storage(0); }
76 Type returnType() const { return *storage(0); }
77 SignatureArgCount returnCount() const { return s_retCount; }
78 SignatureArgCount argumentCount() const { return m_argCount; }
79 Type& argument(SignatureArgCount i)
80 {
81 ASSERT(i < argumentCount());
82 return *storage(returnCount() + i);
83 }
84 Type argument(SignatureArgCount i) const { return const_cast<Signature*>(this)->argument(i); }
85 SignatureIndex index() const { return bitwise_cast<SignatureIndex>(this); }
86
87 WTF::String toString() const;
88 void dump(WTF::PrintStream& out) const;
89 bool operator==(const Signature& rhs) const
90 {
91 if (argumentCount() != rhs.argumentCount())
92 return false;
93 if (returnType() != rhs.returnType())
94 return false;
95 for (unsigned i = 0; i < argumentCount(); ++i) {
96 if (argument(i) != rhs.argument(i))
97 return false;
98 }
99 return true;
100 }
101 unsigned hash() const;
102
103 static RefPtr<Signature> tryCreate(SignatureArgCount);
104
105 // Signatures are uniqued and, for call_indirect, validated at runtime. Tables can create invalid SignatureIndex values which cause call_indirect to fail. We use 0 as the invalidIndex so that the codegen can easily test for it and trap, and we add a token invalid entry in SignatureInformation.
106 static const constexpr SignatureIndex invalidIndex = 0;
107
108private:
109 friend class SignatureInformation;
110 SignatureArgCount m_argCount;
111 // Return Type and arguments are stored here.
112};
113
114struct SignatureHash {
115 RefPtr<Signature> key { nullptr };
116 SignatureHash() = default;
117 explicit SignatureHash(Ref<Signature>&& key)
118 : key(WTFMove(key))
119 {
120 }
121 explicit SignatureHash(WTF::HashTableDeletedValueType)
122 : key(WTF::HashTableDeletedValue)
123 {
124 }
125 bool operator==(const SignatureHash& rhs) const { return equal(*this, rhs); }
126 static bool equal(const SignatureHash& lhs, const SignatureHash& rhs) { return lhs.key == rhs.key || (lhs.key && rhs.key && *lhs.key == *rhs.key); }
127 static unsigned hash(const SignatureHash& signature) { return signature.key ? signature.key->hash() : 0; }
128 static const bool safeToCompareToEmptyOrDeleted = false;
129 bool isHashTableDeletedValue() const { return key.isHashTableDeletedValue(); }
130};
131
132} } // namespace JSC::Wasm
133
134
135namespace WTF {
136
137template<typename T> struct DefaultHash;
138template<> struct DefaultHash<JSC::Wasm::SignatureHash> {
139 typedef JSC::Wasm::SignatureHash Hash;
140};
141
142template<typename T> struct HashTraits;
143template<> struct HashTraits<JSC::Wasm::SignatureHash> : SimpleClassHashTraits<JSC::Wasm::SignatureHash> {
144 static const bool emptyValueIsZero = true;
145};
146
147} // namespace WTF
148
149
150namespace JSC { namespace Wasm {
151
152// Signature information is held globally and shared by the entire process to allow all signatures to be unique. This is required when wasm calls another wasm instance, and must work when modules are shared between multiple VMs.
153// Note: signatures are never removed because that would require accounting for all WebAssembly.Module and which signatures they use. The maximum number of signatures is bounded, and isn't worth the counting overhead. We could clear everything when we reach zero outstanding WebAssembly.Module. https://bugs.webkit.org/show_bug.cgi?id=166037
154class SignatureInformation {
155 WTF_MAKE_NONCOPYABLE(SignatureInformation);
156
157 SignatureInformation();
158
159public:
160 static SignatureInformation& singleton();
161
162 static Ref<Signature> WARN_UNUSED_RETURN adopt(Ref<Signature>&&);
163 static const Signature& WARN_UNUSED_RETURN get(SignatureIndex);
164 static SignatureIndex WARN_UNUSED_RETURN get(const Signature&);
165 static void tryCleanup();
166
167private:
168 HashSet<Wasm::SignatureHash> m_signatureSet;
169 Lock m_lock;
170
171 JS_EXPORT_PRIVATE static SignatureInformation* theOne;
172 JS_EXPORT_PRIVATE static std::once_flag signatureInformationFlag;
173};
174
175} } // namespace JSC::Wasm
176
177#endif // ENABLE(WEBASSEMBLY)
178