1 /*
2 * Copyright 2015 WebAssembly Community Group participants
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef wasm_parsing_h
18 #define wasm_parsing_h
19
20 #include <cmath>
21 #include <ostream>
22 #include <sstream>
23 #include <string>
24
25 #include "asmjs/shared-constants.h"
26 #include "mixed_arena.h"
27 #include "shared-constants.h"
28 #include "support/colors.h"
29 #include "support/utilities.h"
30 #include "wasm-printing.h"
31 #include "wasm.h"
32
33 namespace wasm {
34
35 struct ParseException {
36 std::string text;
37 size_t line, col;
38
ParseExceptionParseException39 ParseException() : text("unknown parse error"), line(-1), col(-1) {}
ParseExceptionParseException40 ParseException(std::string text) : text(text), line(-1), col(-1) {}
ParseExceptionParseException41 ParseException(std::string text, size_t line, size_t col)
42 : text(text), line(line), col(col) {}
43
dumpParseException44 void dump(std::ostream& o) const {
45 Colors::magenta(o);
46 o << "[";
47 Colors::red(o);
48 o << "parse exception: ";
49 Colors::green(o);
50 o << text;
51 if (line != size_t(-1)) {
52 Colors::normal(o);
53 o << " (at " << line << ":" << col << ")";
54 }
55 Colors::magenta(o);
56 o << "]";
57 Colors::normal(o);
58 }
59 };
60
61 struct MapParseException {
62 std::string text;
63
MapParseExceptionMapParseException64 MapParseException() : text("unknown parse error") {}
MapParseExceptionMapParseException65 MapParseException(std::string text) : text(text) {}
66
dumpMapParseException67 void dump(std::ostream& o) const {
68 Colors::magenta(o);
69 o << "[";
70 Colors::red(o);
71 o << "map parse exception: ";
72 Colors::green(o);
73 o << text;
74 Colors::magenta(o);
75 o << "]";
76 Colors::normal(o);
77 }
78 };
79
80 inline Expression*
parseConst(cashew::IString s,Type type,MixedArena & allocator)81 parseConst(cashew::IString s, Type type, MixedArena& allocator) {
82 const char* str = s.str;
83 auto ret = allocator.alloc<Const>();
84 ret->type = type;
85 if (type.isFloat()) {
86 if (s == _INFINITY) {
87 switch (type.getBasic()) {
88 case Type::f32:
89 ret->value = Literal(std::numeric_limits<float>::infinity());
90 break;
91 case Type::f64:
92 ret->value = Literal(std::numeric_limits<double>::infinity());
93 break;
94 default:
95 return nullptr;
96 }
97 // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
98 return ret;
99 }
100 if (s == NEG_INFINITY) {
101 switch (type.getBasic()) {
102 case Type::f32:
103 ret->value = Literal(-std::numeric_limits<float>::infinity());
104 break;
105 case Type::f64:
106 ret->value = Literal(-std::numeric_limits<double>::infinity());
107 break;
108 default:
109 return nullptr;
110 }
111 // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
112 return ret;
113 }
114 if (s == _NAN) {
115 switch (type.getBasic()) {
116 case Type::f32:
117 ret->value = Literal(float(std::nan("")));
118 break;
119 case Type::f64:
120 ret->value = Literal(double(std::nan("")));
121 break;
122 default:
123 return nullptr;
124 }
125 // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
126 return ret;
127 }
128 bool negative = str[0] == '-';
129 const char* positive = negative ? str + 1 : str;
130 if (!negative) {
131 if (positive[0] == '+') {
132 positive++;
133 }
134 }
135 if (positive[0] == 'n' && positive[1] == 'a' && positive[2] == 'n') {
136 const char* modifier = positive[3] == ':' ? positive + 4 : nullptr;
137 if (!(modifier ? positive[4] == '0' && positive[5] == 'x' : 1)) {
138 throw ParseException("bad nan input");
139 }
140 switch (type.getBasic()) {
141 case Type::f32: {
142 uint32_t pattern;
143 if (modifier) {
144 std::istringstream istr(modifier);
145 istr >> std::hex >> pattern;
146 if (istr.fail()) {
147 throw ParseException("invalid f32 format");
148 }
149 pattern |= 0x7f800000U;
150 } else {
151 pattern = 0x7fc00000U;
152 }
153 if (negative) {
154 pattern |= 0x80000000U;
155 }
156 if (!std::isnan(bit_cast<float>(pattern))) {
157 pattern |= 1U;
158 }
159 ret->value = Literal(pattern).castToF32();
160 break;
161 }
162 case Type::f64: {
163 uint64_t pattern;
164 if (modifier) {
165 std::istringstream istr(modifier);
166 istr >> std::hex >> pattern;
167 if (istr.fail()) {
168 throw ParseException("invalid f64 format");
169 }
170 pattern |= 0x7ff0000000000000ULL;
171 } else {
172 pattern = 0x7ff8000000000000UL;
173 }
174 if (negative) {
175 pattern |= 0x8000000000000000ULL;
176 }
177 if (!std::isnan(bit_cast<double>(pattern))) {
178 pattern |= 1ULL;
179 }
180 ret->value = Literal(pattern).castToF64();
181 break;
182 }
183 default:
184 return nullptr;
185 }
186 // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
187 return ret;
188 }
189 if (s == NEG_NAN) {
190 switch (type.getBasic()) {
191 case Type::f32:
192 ret->value = Literal(float(-std::nan("")));
193 break;
194 case Type::f64:
195 ret->value = Literal(double(-std::nan("")));
196 break;
197 default:
198 return nullptr;
199 }
200 // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
201 return ret;
202 }
203 }
204 switch (type.getBasic()) {
205 case Type::i32: {
206 if ((str[0] == '0' && str[1] == 'x') ||
207 (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
208 bool negative = str[0] == '-';
209 if (negative) {
210 str++;
211 }
212 std::istringstream istr(str);
213 uint32_t temp;
214 istr >> std::hex >> temp;
215 if (istr.fail()) {
216 throw ParseException("invalid i32 format");
217 }
218 ret->value = Literal(negative ? -temp : temp);
219 } else {
220 std::istringstream istr(str[0] == '-' ? str + 1 : str);
221 uint32_t temp;
222 istr >> temp;
223 if (istr.fail()) {
224 throw ParseException("invalid i32 format");
225 }
226 ret->value = Literal(str[0] == '-' ? -temp : temp);
227 }
228 break;
229 }
230 case Type::i64: {
231 if ((str[0] == '0' && str[1] == 'x') ||
232 (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
233 bool negative = str[0] == '-';
234 if (negative) {
235 str++;
236 }
237 std::istringstream istr(str);
238 uint64_t temp;
239 istr >> std::hex >> temp;
240 if (istr.fail()) {
241 throw ParseException("invalid i64 format");
242 }
243 ret->value = Literal(negative ? -temp : temp);
244 } else {
245 std::istringstream istr(str[0] == '-' ? str + 1 : str);
246 uint64_t temp;
247 istr >> temp;
248 if (istr.fail()) {
249 throw ParseException("invalid i64 format");
250 }
251 ret->value = Literal(str[0] == '-' ? -temp : temp);
252 }
253 break;
254 }
255 case Type::f32: {
256 char* end;
257 ret->value = Literal(strtof(str, &end));
258 break;
259 }
260 case Type::f64: {
261 char* end;
262 ret->value = Literal(strtod(str, &end));
263 break;
264 }
265 case Type::v128:
266 case Type::funcref:
267 case Type::externref:
268 case Type::exnref:
269 case Type::anyref:
270 case Type::eqref:
271 case Type::i31ref:
272 WASM_UNREACHABLE("unexpected const type");
273 case Type::none:
274 case Type::unreachable: {
275 return nullptr;
276 }
277 }
278 if (ret->value.type != type) {
279 throw ParseException("parsed type does not match expected type");
280 }
281 // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
282 return ret;
283 }
284
285 // Helper for parsers that may not have unique label names. This transforms
286 // the names into unique ones, as required by Binaryen IR.
287 struct UniqueNameMapper {
288 std::vector<Name> labelStack;
289 // name in source => stack of uniquified names
290 std::map<Name, std::vector<Name>> labelMappings;
291 std::map<Name, Name> reverseLabelMapping; // uniquified name => name in source
292
293 Index otherIndex = 0;
294
getPrefixedNameUniqueNameMapper295 Name getPrefixedName(Name prefix) {
296 if (reverseLabelMapping.find(prefix) == reverseLabelMapping.end()) {
297 return prefix;
298 }
299 // make sure to return a unique name not already on the stack
300 while (1) {
301 Name ret = Name(prefix.str + std::to_string(otherIndex++));
302 if (reverseLabelMapping.find(ret) == reverseLabelMapping.end()) {
303 return ret;
304 }
305 }
306 }
307
308 // receives a source name. generates a unique name, pushes it, and returns it
pushLabelNameUniqueNameMapper309 Name pushLabelName(Name sName) {
310 Name name = getPrefixedName(sName);
311 labelStack.push_back(name);
312 labelMappings[sName].push_back(name);
313 reverseLabelMapping[name] = sName;
314 return name;
315 }
316
popLabelNameUniqueNameMapper317 void popLabelName(Name name) {
318 assert(labelStack.back() == name);
319 labelStack.pop_back();
320 labelMappings[reverseLabelMapping[name]].pop_back();
321 }
322
sourceToUniqueUniqueNameMapper323 Name sourceToUnique(Name sName) {
324 if (labelMappings.find(sName) == labelMappings.end()) {
325 throw ParseException("bad label in sourceToUnique");
326 }
327 if (labelMappings[sName].empty()) {
328 throw ParseException("use of popped label in sourceToUnique");
329 }
330 return labelMappings[sName].back();
331 }
332
uniqueToSourceUniqueNameMapper333 Name uniqueToSource(Name name) {
334 if (reverseLabelMapping.find(name) == reverseLabelMapping.end()) {
335 throw ParseException("label mismatch in uniqueToSource");
336 }
337 return reverseLabelMapping[name];
338 }
339
clearUniqueNameMapper340 void clear() {
341 labelStack.clear();
342 labelMappings.clear();
343 reverseLabelMapping.clear();
344 }
345
346 // Given an expression, ensures all names are unique
uniquifyUniqueNameMapper347 static void uniquify(Expression* curr) {
348 struct Walker : public ControlFlowWalker<Walker, Visitor<Walker>> {
349 UniqueNameMapper mapper;
350
351 static void doPreVisitControlFlow(Walker* self, Expression** currp) {
352 auto* curr = *currp;
353 if (auto* block = curr->dynCast<Block>()) {
354 if (block->name.is()) {
355 block->name = self->mapper.pushLabelName(block->name);
356 }
357 } else if (auto* loop = curr->dynCast<Loop>()) {
358 if (loop->name.is()) {
359 loop->name = self->mapper.pushLabelName(loop->name);
360 }
361 }
362 }
363 static void doPostVisitControlFlow(Walker* self, Expression** currp) {
364 auto* curr = *currp;
365 if (auto* block = curr->dynCast<Block>()) {
366 if (block->name.is()) {
367 self->mapper.popLabelName(block->name);
368 }
369 } else if (auto* loop = curr->dynCast<Loop>()) {
370 if (loop->name.is()) {
371 self->mapper.popLabelName(loop->name);
372 }
373 }
374 }
375
376 void visitBreak(Break* curr) {
377 curr->name = mapper.sourceToUnique(curr->name);
378 }
379 void visitBrOnExn(BrOnExn* curr) {
380 curr->name = mapper.sourceToUnique(curr->name);
381 }
382 void visitSwitch(Switch* curr) {
383 for (auto& target : curr->targets) {
384 target = mapper.sourceToUnique(target);
385 }
386 curr->default_ = mapper.sourceToUnique(curr->default_);
387 }
388 };
389
390 Walker walker;
391 walker.walk(curr);
392 }
393 };
394
395 } // namespace wasm
396
397 #endif // wasm_parsing_h
398