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#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
56 Signature() = delete;
57 Signature(const Signature&) = delete;
58 Signature(SignatureArgCount retCount, SignatureArgCount argCount)
59 : m_retCount(retCount)
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> retCount, Checked<SignatureArgCount> argCount)
70 {
71 return (sizeof(Signature) + (retCount + argCount) * sizeof(Type)).unsafeGet();
72 }
73
74public:
75 SignatureArgCount returnCount() const { return m_retCount; }
76 SignatureArgCount argumentCount() const { return m_argCount; }
77
78 Type returnType(SignatureArgCount i) const { ASSERT(i < returnCount()); return const_cast<Signature*>(this)->getReturnType(i); }
79 bool returnsVoid() const { return !returnCount(); }
80 Type argument(SignatureArgCount i) const { return const_cast<Signature*>(this)->getArgument(i); }
81 SignatureIndex index() const { return bitwise_cast<SignatureIndex>(this); }
82
83 WTF::String toString() const;
84 void dump(WTF::PrintStream& out) const;
85 bool operator==(const Signature& rhs) const { return this == &rhs; }
86 unsigned hash() const;
87
88 // 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.
89 static const constexpr SignatureIndex invalidIndex = 0;
90
91private:
92 friend class SignatureInformation;
93 friend struct ParameterTypes;
94
95 static RefPtr<Signature> tryCreate(SignatureArgCount returnCount, SignatureArgCount argumentCount);
96 Type& getReturnType(SignatureArgCount i) { ASSERT(i < returnCount()); return *storage(i); }
97 Type& getArgument(SignatureArgCount i) { ASSERT(i < argumentCount()); return *storage(returnCount() + i); }
98
99 SignatureArgCount m_retCount;
100 SignatureArgCount m_argCount;
101 // Return Type and arguments are stored here.
102};
103
104struct SignatureHash {
105 RefPtr<Signature> key { nullptr };
106 SignatureHash() = default;
107 explicit SignatureHash(Ref<Signature>&& key)
108 : key(WTFMove(key))
109 { }
110 explicit SignatureHash(WTF::HashTableDeletedValueType)
111 : key(WTF::HashTableDeletedValue)
112 { }
113 bool operator==(const SignatureHash& rhs) const { return equal(*this, rhs); }
114 static bool equal(const SignatureHash& lhs, const SignatureHash& rhs) { return lhs.key == rhs.key; }
115 static unsigned hash(const SignatureHash& signature) { return signature.key ? signature.key->hash() : 0; }
116 static constexpr bool safeToCompareToEmptyOrDeleted = false;
117 bool isHashTableDeletedValue() const { return key.isHashTableDeletedValue(); }
118};
119
120} } // namespace JSC::Wasm
121
122
123namespace WTF {
124
125template<typename T> struct DefaultHash;
126template<> struct DefaultHash<JSC::Wasm::SignatureHash> {
127 typedef JSC::Wasm::SignatureHash Hash;
128};
129
130template<typename T> struct HashTraits;
131template<> struct HashTraits<JSC::Wasm::SignatureHash> : SimpleClassHashTraits<JSC::Wasm::SignatureHash> {
132 static constexpr bool emptyValueIsZero = true;
133};
134
135} // namespace WTF
136
137
138namespace JSC { namespace Wasm {
139
140// 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.
141class SignatureInformation {
142 WTF_MAKE_NONCOPYABLE(SignatureInformation);
143 WTF_MAKE_FAST_ALLOCATED;
144
145 SignatureInformation();
146
147public:
148 static SignatureInformation& singleton();
149
150 static RefPtr<Signature> signatureFor(const Vector<Type, 1>& returnTypes, const Vector<Type>& argumentTypes);
151 ALWAYS_INLINE const Signature* thunkFor(Type type) const { return thunkSignatures[linearizeType(type)]; }
152
153 static const Signature& get(SignatureIndex);
154 static SignatureIndex get(const Signature&);
155 static void tryCleanup();
156
157private:
158 HashSet<Wasm::SignatureHash> m_signatureSet;
159 const Signature* thunkSignatures[numTypes];
160 Lock m_lock;
161
162 JS_EXPORT_PRIVATE static SignatureInformation* theOne;
163 JS_EXPORT_PRIVATE static std::once_flag signatureInformationFlag;
164};
165
166} } // namespace JSC::Wasm
167
168#endif // ENABLE(WEBASSEMBLY)
169