8ec8422f2e651830719e689042bb2667bcde2361
[WebKit-https.git] / Source / JavaScriptCore / wasm / WasmParser.h
1 /*
2  * Copyright (C) 2016 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 "B3Compilation.h"
31 #include "B3Procedure.h"
32 #include "WasmFormat.h"
33 #include "WasmOps.h"
34 #include "WasmSections.h"
35 #include <type_traits>
36 #include <wtf/Expected.h>
37 #include <wtf/LEBDecoder.h>
38 #include <wtf/StdLibExtras.h>
39 #include <wtf/text/WTFString.h>
40
41 namespace JSC { namespace Wasm {
42
43 namespace FailureHelper {
44 // FIXME We should move this to makeString. It's in its own namespace to enable C++ Argument Dependent Lookup à la std::swap: user code can deblare its own "boxFailure" and the fail() helper will find it.
45 static inline auto makeString(const char *failure) { return ASCIILiteral(failure); }
46 template <typename Int, typename = typename std::enable_if<std::is_integral<Int>::value>::type>
47 static inline auto makeString(Int failure) { return String::number(failure); }
48 }
49
50 template<typename SuccessType>
51 class Parser {
52 public:
53     typedef String ErrorType;
54     typedef UnexpectedType<ErrorType> UnexpectedResult;
55     typedef Expected<void, ErrorType> PartialResult;
56     typedef Expected<SuccessType, ErrorType> Result;
57
58 protected:
59     Parser(const uint8_t*, size_t);
60
61     bool WARN_UNUSED_RETURN consumeCharacter(char);
62     bool WARN_UNUSED_RETURN consumeString(const char*);
63     bool WARN_UNUSED_RETURN consumeUTF8String(String&, size_t);
64
65     bool WARN_UNUSED_RETURN parseVarUInt1(uint8_t&);
66     bool WARN_UNUSED_RETURN parseInt7(int8_t&);
67     bool WARN_UNUSED_RETURN parseUInt7(uint8_t&);
68     bool WARN_UNUSED_RETURN parseUInt8(uint8_t&);
69     bool WARN_UNUSED_RETURN parseUInt32(uint32_t&);
70     bool WARN_UNUSED_RETURN parseUInt64(uint64_t&);
71     bool WARN_UNUSED_RETURN parseVarUInt32(uint32_t&);
72     bool WARN_UNUSED_RETURN parseVarUInt64(uint64_t&);
73
74     bool WARN_UNUSED_RETURN parseVarInt32(int32_t&);
75     bool WARN_UNUSED_RETURN parseVarInt64(int64_t&);
76
77     bool WARN_UNUSED_RETURN parseResultType(Type&);
78     bool WARN_UNUSED_RETURN parseValueType(Type&);
79     bool WARN_UNUSED_RETURN parseExternalKind(ExternalKind&);
80
81     const uint8_t* source() const { return m_source; }
82     size_t length() const { return m_sourceLength; }
83
84     size_t m_offset = 0;
85
86     template <typename ...Args>
87     NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
88     {
89         using namespace FailureHelper; // See ADL comment in namespace above.
90         return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module doesn't parse at byte "), String::number(m_offset), ASCIILiteral(" / "), String::number(m_sourceLength), ASCIILiteral(": "), makeString(args)...));
91     }
92 #define WASM_PARSER_FAIL_IF(condition, ...) do { \
93     if (UNLIKELY(condition))                     \
94         return fail(__VA_ARGS__);                \
95     } while (0)
96
97 #define WASM_FAIL_IF_HELPER_FAILS(helper) do {   \
98         auto helperResult = helper;              \
99         if (UNLIKELY(!helperResult))             \
100             return helperResult.getUnexpected(); \
101     } while (0)
102
103 private:
104     const uint8_t* m_source;
105     size_t m_sourceLength;
106 };
107
108 template<typename SuccessType>
109 ALWAYS_INLINE Parser<SuccessType>::Parser(const uint8_t* sourceBuffer, size_t sourceLength)
110     : m_source(sourceBuffer)
111     , m_sourceLength(sourceLength)
112 {
113 }
114
115 template<typename SuccessType>
116 ALWAYS_INLINE bool Parser<SuccessType>::consumeCharacter(char c)
117 {
118     if (m_offset >= length())
119         return false;
120     if (c == source()[m_offset]) {
121         m_offset++;
122         return true;
123     }
124     return false;
125 }
126
127 template<typename SuccessType>
128 ALWAYS_INLINE bool Parser<SuccessType>::consumeString(const char* str)
129 {
130     unsigned start = m_offset;
131     if (m_offset >= length())
132         return false;
133     for (size_t i = 0; str[i]; i++) {
134         if (!consumeCharacter(str[i])) {
135             m_offset = start;
136             return false;
137         }
138     }
139     return true;
140 }
141
142 template<typename SuccessType>
143 ALWAYS_INLINE bool Parser<SuccessType>::consumeUTF8String(String& result, size_t stringLength)
144 {
145     if (stringLength == 0) {
146         result = emptyString();
147         return true;
148     }
149     if (length() < stringLength || m_offset > length() - stringLength)
150         return false;
151     result = String::fromUTF8(static_cast<const LChar*>(&source()[m_offset]), stringLength);
152     m_offset += stringLength;
153     if (result.isEmpty())
154         return false;
155     return true;
156 }
157
158 template<typename SuccessType>
159 ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt32(uint32_t& result)
160 {
161     return WTF::LEBDecoder::decodeUInt32(m_source, m_sourceLength, m_offset, result);
162 }
163
164 template<typename SuccessType>
165 ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt64(uint64_t& result)
166 {
167     return WTF::LEBDecoder::decodeUInt64(m_source, m_sourceLength, m_offset, result);
168 }
169
170 template<typename SuccessType>
171 ALWAYS_INLINE bool Parser<SuccessType>::parseVarInt32(int32_t& result)
172 {
173     return WTF::LEBDecoder::decodeInt32(m_source, m_sourceLength, m_offset, result);
174 }
175
176 template<typename SuccessType>
177 ALWAYS_INLINE bool Parser<SuccessType>::parseVarInt64(int64_t& result)
178 {
179     return WTF::LEBDecoder::decodeInt64(m_source, m_sourceLength, m_offset, result);
180 }
181
182 template<typename SuccessType>
183 ALWAYS_INLINE bool Parser<SuccessType>::parseUInt32(uint32_t& result)
184 {
185     if (length() < 4 || m_offset > length() - 4)
186         return false;
187     result = *reinterpret_cast<const uint32_t*>(source() + m_offset);
188     m_offset += 4;
189     return true;
190 }
191
192 template<typename SuccessType>
193 ALWAYS_INLINE bool Parser<SuccessType>::parseUInt64(uint64_t& result)
194 {
195     if (length() < 8 || m_offset > length() - 8)
196         return false;
197     result = *reinterpret_cast<const uint64_t*>(source() + m_offset);
198     m_offset += 8;
199     return true;
200 }
201
202 template<typename SuccessType>
203 ALWAYS_INLINE bool Parser<SuccessType>::parseUInt8(uint8_t& result)
204 {
205     if (m_offset >= length())
206         return false;
207     result = source()[m_offset++];
208     return true;
209 }
210
211 template<typename SuccessType>
212 ALWAYS_INLINE bool Parser<SuccessType>::parseInt7(int8_t& result)
213 {
214     if (m_offset >= length())
215         return false;
216     uint8_t v = source()[m_offset++];
217     result = (v & 0x40) ? WTF::bitwise_cast<int8_t>(uint8_t(v | 0x80)) : v;
218     return (v & 0x80) == 0;
219 }
220
221 template<typename SuccessType>
222 ALWAYS_INLINE bool Parser<SuccessType>::parseUInt7(uint8_t& result)
223 {
224     if (m_offset >= length())
225         return false;
226     result = source()[m_offset++];
227     return result < 0x80;
228 }
229
230 template<typename SuccessType>
231 ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt1(uint8_t& result)
232 {
233     uint32_t temp;
234     if (!parseVarUInt32(temp))
235         return false;
236     if (temp > 1)
237         return false;
238     result = static_cast<uint8_t>(temp);
239     return true;
240 }
241
242 template<typename SuccessType>
243 ALWAYS_INLINE bool Parser<SuccessType>::parseResultType(Type& result)
244 {
245     int8_t value;
246     if (!parseInt7(value))
247         return false;
248     if (!isValidType(value))
249         return false;
250     result = static_cast<Type>(value);
251     return true;
252 }
253
254 template<typename SuccessType>
255 ALWAYS_INLINE bool Parser<SuccessType>::parseValueType(Type& result)
256 {
257     return parseResultType(result) && isValueType(result);
258 }
259
260 template<typename SuccessType>
261 ALWAYS_INLINE bool Parser<SuccessType>::parseExternalKind(ExternalKind& result)
262 {
263     uint8_t value;
264     if (!parseUInt7(value))
265         return false;
266     if (!isValidExternalKind(value))
267         return false;
268     result = static_cast<ExternalKind>(value);
269     return true;
270 }
271
272 } } // namespace JSC::Wasm
273
274 #endif // ENABLE(WEBASSEMBLY)