Use constexpr instead of const in symbol definitions that are obviously constexpr.
[WebKit-https.git] / Source / JavaScriptCore / wasm / WasmSignature.h
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
42 namespace WTF {
43 class PrintStream;
44 }
45
46 namespace JSC {
47
48 namespace Wasm {
49
50 using SignatureArgCount = uint32_t;
51 using SignatureIndex = uint64_t;
52
53 class 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
74 public:
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
108 private:
109     friend class SignatureInformation;
110     SignatureArgCount m_argCount;
111     // Return Type and arguments are stored here.
112 };
113
114 struct 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 constexpr bool safeToCompareToEmptyOrDeleted = false;
129     bool isHashTableDeletedValue() const { return key.isHashTableDeletedValue(); }
130 };
131
132 } } // namespace JSC::Wasm
133
134
135 namespace WTF {
136
137 template<typename T> struct DefaultHash;
138 template<> struct DefaultHash<JSC::Wasm::SignatureHash> {
139     typedef JSC::Wasm::SignatureHash Hash;
140 };
141
142 template<typename T> struct HashTraits;
143 template<> struct HashTraits<JSC::Wasm::SignatureHash> : SimpleClassHashTraits<JSC::Wasm::SignatureHash> {
144     static constexpr bool emptyValueIsZero = true;
145 };
146
147 } // namespace WTF
148
149
150 namespace 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
154 class SignatureInformation {
155     WTF_MAKE_NONCOPYABLE(SignatureInformation);
156     WTF_MAKE_FAST_ALLOCATED;
157
158     SignatureInformation();
159
160 public:
161     static SignatureInformation& singleton();
162
163     static Ref<Signature> WARN_UNUSED_RETURN adopt(Ref<Signature>&&);
164     static const Signature& WARN_UNUSED_RETURN get(SignatureIndex);
165     static SignatureIndex WARN_UNUSED_RETURN get(const Signature&);
166     static void tryCleanup();
167
168 private:
169     HashSet<Wasm::SignatureHash> m_signatureSet;
170     Lock m_lock;
171
172     JS_EXPORT_PRIVATE static SignatureInformation* theOne;
173     JS_EXPORT_PRIVATE static std::once_flag signatureInformationFlag;
174 };
175
176 } } // namespace JSC::Wasm
177
178 #endif // ENABLE(WEBASSEMBLY)