Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : *
4 : * Copyright 2015 Mozilla Foundation
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include "wasm/WasmBinaryToExperimentalText.h"
20 :
21 : #include "mozilla/CheckedInt.h"
22 :
23 : #include "jsnum.h"
24 : #include "jsprf.h"
25 :
26 : #include "vm/ArrayBufferObject.h"
27 : #include "vm/StringBuffer.h"
28 : #include "wasm/WasmAST.h"
29 : #include "wasm/WasmBinaryToAST.h"
30 : #include "wasm/WasmDebug.h"
31 : #include "wasm/WasmTextUtils.h"
32 : #include "wasm/WasmTypes.h"
33 :
34 : using namespace js;
35 : using namespace js::wasm;
36 :
37 : using mozilla::CheckedInt;
38 : using mozilla::IsInfinite;
39 : using mozilla::IsNaN;
40 : using mozilla::IsNegativeZero;
41 :
42 : enum PrintOperatorPrecedence
43 : {
44 : ExpressionPrecedence = 0,
45 : AssignmentPrecedence = 1,
46 : StoreOperatorPrecedence = 1,
47 : BitwiseOrPrecedence = 4,
48 : BitwiseXorPrecedence = 5,
49 : BitwiseAndPrecedence = 6,
50 : EqualityPrecedence = 7,
51 : ComparisonPrecedence = 8,
52 : BitwiseShiftPrecedence = 9,
53 : AdditionPrecedence = 10,
54 : MultiplicationPrecedence = 11,
55 : NegatePrecedence = 12,
56 : EqzPrecedence = 12,
57 : OperatorPrecedence = 15,
58 : LoadOperatorPrecedence = 15,
59 : CallPrecedence = 15,
60 : GroupPrecedence = 16,
61 : };
62 :
63 : struct WasmPrintContext
64 : {
65 : JSContext* cx;
66 : AstModule* module;
67 : WasmPrintBuffer& buffer;
68 : const ExperimentalTextFormatting& f;
69 : GeneratedSourceMap* maybeSourceMap;
70 : uint32_t indent;
71 :
72 : uint32_t currentFuncIndex;
73 : PrintOperatorPrecedence currentPrecedence;
74 :
75 0 : WasmPrintContext(JSContext* cx, AstModule* module, WasmPrintBuffer& buffer,
76 : const ExperimentalTextFormatting& f, GeneratedSourceMap* wasmSourceMap_)
77 0 : : cx(cx),
78 : module(module),
79 : buffer(buffer),
80 : f(f),
81 : maybeSourceMap(wasmSourceMap_),
82 : indent(0),
83 : currentFuncIndex(0),
84 0 : currentPrecedence(PrintOperatorPrecedence::ExpressionPrecedence)
85 0 : {}
86 :
87 0 : StringBuffer& sb() { return buffer.stringBuffer(); }
88 : };
89 :
90 : /*****************************************************************************/
91 : // utilities
92 :
93 : static bool
94 0 : IsDropValueExpr(AstExpr& expr)
95 : {
96 : // Based on AST information, determines if the expression does not return a value.
97 : // TODO infer presence of a return value for rest kinds of expressions from
98 : // the function return type.
99 0 : switch (expr.kind()) {
100 : case AstExprKind::Branch:
101 0 : return !expr.as<AstBranch>().maybeValue();
102 : case AstExprKind::BranchTable:
103 0 : return !expr.as<AstBranchTable>().maybeValue();
104 : case AstExprKind::If:
105 0 : return !expr.as<AstIf>().hasElse();
106 : case AstExprKind::Nop:
107 : case AstExprKind::Drop:
108 : case AstExprKind::Unreachable:
109 : case AstExprKind::Return:
110 : case AstExprKind::SetLocal:
111 : case AstExprKind::Store:
112 0 : return true;
113 : default:
114 0 : return false;
115 : }
116 : }
117 :
118 : static bool
119 0 : PrintIndent(WasmPrintContext& c)
120 : {
121 0 : for (uint32_t i = 0; i < c.indent; i++) {
122 0 : if (!c.buffer.append(" "))
123 0 : return false;
124 : }
125 0 : return true;
126 : }
127 :
128 : static bool
129 0 : PrintInt32(WasmPrintContext& c, int32_t num, bool printSign = false)
130 : {
131 : // Negative sign will be printed, printing '+' for non-negative values.
132 0 : if (printSign && num >= 0) {
133 0 : if (!c.buffer.append("+"))
134 0 : return false;
135 : }
136 0 : return NumberValueToStringBuffer(c.cx, Int32Value(num), c.buffer.stringBuffer());
137 : }
138 :
139 : static bool
140 0 : PrintInt64(WasmPrintContext& c, int64_t num)
141 : {
142 0 : if (num < 0 && !c.buffer.append("-"))
143 0 : return false;
144 0 : if (!num)
145 0 : return c.buffer.append("0");
146 :
147 0 : uint64_t abs = mozilla::Abs(num);
148 0 : uint64_t n = abs;
149 0 : uint64_t pow = 1;
150 0 : while (n) {
151 0 : pow *= 10;
152 0 : n /= 10;
153 : }
154 0 : pow /= 10;
155 :
156 0 : n = abs;
157 0 : while (pow) {
158 0 : if (!c.buffer.append((char16_t)(u'0' + n / pow)))
159 0 : return false;
160 0 : n -= (n / pow) * pow;
161 0 : pow /= 10;
162 : }
163 :
164 0 : return true;
165 : }
166 :
167 : static bool
168 0 : PrintDouble(WasmPrintContext& c, double d)
169 : {
170 0 : if (IsNegativeZero(d))
171 0 : return c.buffer.append("-0.0");
172 0 : if (IsNaN(d))
173 0 : return RenderNaN(c.sb(), d);
174 0 : if (IsInfinite(d)) {
175 0 : if (d > 0)
176 0 : return c.buffer.append("infinity");
177 0 : return c.buffer.append("-infinity");
178 : }
179 :
180 0 : uint32_t startLength = c.buffer.length();
181 0 : if (!NumberValueToStringBuffer(c.cx, DoubleValue(d), c.buffer.stringBuffer()))
182 0 : return false;
183 0 : MOZ_ASSERT(startLength < c.buffer.length());
184 :
185 : // Checking if we need to end number with '.0'.
186 0 : for (uint32_t i = c.buffer.length() - 1; i >= startLength; i--) {
187 0 : char16_t ch = c.buffer.getChar(i);
188 0 : if (ch == '.' || ch == 'e')
189 0 : return true;
190 : }
191 0 : return c.buffer.append(".0");
192 : }
193 :
194 : static bool
195 0 : PrintFloat32(WasmPrintContext& c, float f)
196 : {
197 0 : if (IsNaN(f))
198 0 : return RenderNaN(c.sb(), f) && c.buffer.append(".f");
199 0 : return PrintDouble(c, double(f)) &&
200 0 : c.buffer.append("f");
201 : }
202 :
203 : static bool
204 0 : PrintEscapedString(WasmPrintContext& c, const AstName& s)
205 : {
206 0 : size_t length = s.length();
207 0 : const char16_t* p = s.begin();
208 0 : for (size_t i = 0; i < length; i++) {
209 0 : char16_t byte = p[i];
210 0 : switch (byte) {
211 : case '\n':
212 0 : if (!c.buffer.append("\\n"))
213 0 : return false;
214 0 : break;
215 : case '\r':
216 0 : if (!c.buffer.append("\\0d"))
217 0 : return false;
218 0 : break;
219 : case '\t':
220 0 : if (!c.buffer.append("\\t"))
221 0 : return false;
222 0 : break;
223 : case '\f':
224 0 : if (!c.buffer.append("\\0c"))
225 0 : return false;
226 0 : break;
227 : case '\b':
228 0 : if (!c.buffer.append("\\08"))
229 0 : return false;
230 0 : break;
231 : case '\\':
232 0 : if (!c.buffer.append("\\\\"))
233 0 : return false;
234 0 : break;
235 : case '"' :
236 0 : if (!c.buffer.append("\\\""))
237 0 : return false;
238 0 : break;
239 : case '\'':
240 0 : if (!c.buffer.append("\\'"))
241 0 : return false;
242 0 : break;
243 : default:
244 0 : if (byte >= 32 && byte < 127) {
245 0 : if (!c.buffer.append((char)byte))
246 0 : return false;
247 : } else {
248 0 : char digit1 = byte / 16, digit2 = byte % 16;
249 0 : if (!c.buffer.append("\\"))
250 0 : return false;
251 0 : if (!c.buffer.append((char)(digit1 < 10 ? digit1 + '0' : digit1 - 10 + 'a')))
252 0 : return false;
253 0 : if (!c.buffer.append((char)(digit2 < 10 ? digit2 + '0' : digit2 - 10 + 'a')))
254 0 : return false;
255 : }
256 0 : break;
257 : }
258 : }
259 0 : return true;
260 : }
261 :
262 : static bool
263 0 : PrintExprType(WasmPrintContext& c, ExprType type)
264 : {
265 0 : switch (type) {
266 0 : case ExprType::Void: return true; // ignoring void
267 0 : case ExprType::I32: return c.buffer.append("i32");
268 0 : case ExprType::I64: return c.buffer.append("i64");
269 0 : case ExprType::F32: return c.buffer.append("f32");
270 0 : case ExprType::F64: return c.buffer.append("f64");
271 : default:;
272 : }
273 :
274 0 : MOZ_CRASH("bad type");
275 : }
276 :
277 : static bool
278 0 : PrintValType(WasmPrintContext& c, ValType type)
279 : {
280 0 : return PrintExprType(c, ToExprType(type));
281 : }
282 :
283 : static bool
284 0 : PrintName(WasmPrintContext& c, const AstName& name)
285 : {
286 0 : return c.buffer.append(name.begin(), name.end());
287 : }
288 :
289 : static bool
290 0 : PrintRef(WasmPrintContext& c, const AstRef& ref)
291 : {
292 0 : if (ref.name().empty())
293 0 : return PrintInt32(c, ref.index());
294 :
295 0 : return PrintName(c, ref.name());
296 : }
297 :
298 : static bool
299 : PrintExpr(WasmPrintContext& c, AstExpr& expr);
300 :
301 : static bool
302 0 : PrintBlockLevelExpr(WasmPrintContext& c, AstExpr& expr, bool isLast)
303 : {
304 0 : if (!PrintIndent(c))
305 0 : return false;
306 0 : if (!PrintExpr(c, expr))
307 0 : return false;
308 0 : if (!isLast || IsDropValueExpr(expr)) {
309 0 : if (!c.buffer.append(';'))
310 0 : return false;
311 : }
312 0 : return c.buffer.append('\n');
313 : }
314 :
315 : /*****************************************************************************/
316 : // binary format parsing and rendering
317 :
318 : static bool
319 0 : PrintNop(WasmPrintContext& c)
320 : {
321 0 : return c.buffer.append("nop");
322 : }
323 :
324 : static bool
325 0 : PrintDrop(WasmPrintContext& c, AstDrop& drop)
326 : {
327 0 : if (!PrintExpr(c, drop.value()))
328 0 : return false;
329 :
330 0 : return true;
331 : }
332 :
333 : static bool
334 0 : PrintUnreachable(WasmPrintContext& c, AstUnreachable& unreachable)
335 : {
336 0 : return c.buffer.append("unreachable");
337 : }
338 :
339 : static bool
340 0 : PrintCallArgs(WasmPrintContext& c, const AstExprVector& args)
341 : {
342 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
343 0 : c.currentPrecedence = ExpressionPrecedence;
344 :
345 0 : if (!c.buffer.append("("))
346 0 : return false;
347 0 : for (uint32_t i = 0; i < args.length(); i++) {
348 0 : if (!PrintExpr(c, *args[i]))
349 0 : return false;
350 0 : if (i + 1 == args.length())
351 0 : break;
352 0 : if (!c.buffer.append(", "))
353 0 : return false;
354 : }
355 0 : if (!c.buffer.append(")"))
356 0 : return false;
357 :
358 0 : c.currentPrecedence = lastPrecedence;
359 0 : return true;
360 : }
361 :
362 : static bool
363 0 : PrintCall(WasmPrintContext& c, AstCall& call)
364 : {
365 0 : if (call.op() == Op::Call) {
366 0 : if (!c.buffer.append("call "))
367 0 : return false;
368 : } else {
369 0 : return false;
370 : }
371 :
372 0 : if (!PrintRef(c, call.func()))
373 0 : return false;
374 :
375 0 : if (!c.buffer.append(" "))
376 0 : return false;
377 :
378 0 : if (!PrintCallArgs(c, call.args()))
379 0 : return false;
380 :
381 0 : return true;
382 : }
383 :
384 : static bool
385 0 : PrintCallIndirect(WasmPrintContext& c, AstCallIndirect& call)
386 : {
387 0 : if (!c.buffer.append("call_indirect "))
388 0 : return false;
389 0 : if (!PrintRef(c, call.sig()))
390 0 : return false;
391 :
392 0 : if (!c.buffer.append(' '))
393 0 : return false;
394 :
395 0 : if (!PrintCallArgs(c, call.args()))
396 0 : return false;
397 :
398 0 : if (!c.buffer.append(" ["))
399 0 : return false;
400 :
401 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
402 0 : c.currentPrecedence = ExpressionPrecedence;
403 :
404 0 : if (!PrintExpr(c, *call.index()))
405 0 : return false;
406 :
407 0 : c.currentPrecedence = lastPrecedence;
408 :
409 0 : if (!c.buffer.append(']'))
410 0 : return false;
411 0 : return true;
412 : }
413 :
414 : static bool
415 0 : PrintConst(WasmPrintContext& c, AstConst& cst)
416 : {
417 0 : switch (ToExprType(cst.val().type())) {
418 : case ExprType::I32:
419 0 : if (!PrintInt32(c, (uint32_t)cst.val().i32()))
420 0 : return false;
421 0 : break;
422 : case ExprType::I64:
423 0 : if (!PrintInt64(c, (uint32_t)cst.val().i64()))
424 0 : return false;
425 0 : if (!c.buffer.append("i64"))
426 0 : return false;
427 0 : break;
428 : case ExprType::F32:
429 0 : if (!PrintFloat32(c, cst.val().f32()))
430 0 : return false;
431 0 : break;
432 : case ExprType::F64:
433 0 : if (!PrintDouble(c, cst.val().f64()))
434 0 : return false;
435 0 : break;
436 : default:
437 0 : return false;
438 : }
439 0 : return true;
440 : }
441 :
442 : static bool
443 0 : PrintGetLocal(WasmPrintContext& c, AstGetLocal& gl)
444 : {
445 0 : if (!PrintRef(c, gl.local()))
446 0 : return false;
447 0 : return true;
448 : }
449 :
450 : static bool
451 0 : PrintSetLocal(WasmPrintContext& c, AstSetLocal& sl)
452 : {
453 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
454 :
455 0 : if (!c.f.reduceParens || lastPrecedence > AssignmentPrecedence) {
456 0 : if (!c.buffer.append("("))
457 0 : return false;
458 : }
459 :
460 0 : if (!PrintRef(c, sl.local()))
461 0 : return false;
462 0 : if (!c.buffer.append(" = "))
463 0 : return false;
464 :
465 0 : c.currentPrecedence = AssignmentPrecedence;
466 :
467 0 : if (!PrintExpr(c, sl.value()))
468 0 : return false;
469 :
470 0 : if (!c.f.reduceParens || lastPrecedence > AssignmentPrecedence) {
471 0 : if (!c.buffer.append(")"))
472 0 : return false;
473 : }
474 :
475 0 : c.currentPrecedence = lastPrecedence;
476 0 : return true;
477 : }
478 :
479 : static bool
480 0 : PrintTeeLocal(WasmPrintContext& c, AstTeeLocal& sl)
481 : {
482 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
483 :
484 0 : if (!c.f.reduceParens || lastPrecedence > AssignmentPrecedence) {
485 0 : if (!c.buffer.append("("))
486 0 : return false;
487 : }
488 :
489 0 : if (!PrintRef(c, sl.local()))
490 0 : return false;
491 0 : if (!c.buffer.append(" = "))
492 0 : return false;
493 :
494 0 : c.currentPrecedence = AssignmentPrecedence;
495 :
496 0 : if (!PrintExpr(c, sl.value()))
497 0 : return false;
498 :
499 0 : if (!c.f.reduceParens || lastPrecedence > AssignmentPrecedence) {
500 0 : if (!c.buffer.append(")"))
501 0 : return false;
502 : }
503 :
504 0 : c.currentPrecedence = lastPrecedence;
505 0 : return true;
506 : }
507 :
508 : static bool
509 0 : PrintGetGlobal(WasmPrintContext& c, AstGetGlobal& gg)
510 : {
511 0 : return PrintRef(c, gg.global());
512 : }
513 :
514 : static bool
515 0 : PrintSetGlobal(WasmPrintContext& c, AstSetGlobal& sg)
516 : {
517 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
518 :
519 0 : if (!c.f.reduceParens || lastPrecedence > AssignmentPrecedence) {
520 0 : if (!c.buffer.append("("))
521 0 : return false;
522 : }
523 :
524 0 : if (!PrintRef(c, sg.global()))
525 0 : return false;
526 0 : if (!c.buffer.append(" = "))
527 0 : return false;
528 :
529 0 : c.currentPrecedence = AssignmentPrecedence;
530 :
531 0 : if (!PrintExpr(c, sg.value()))
532 0 : return false;
533 :
534 0 : if (!c.f.reduceParens || lastPrecedence > AssignmentPrecedence) {
535 0 : if (!c.buffer.append(")"))
536 0 : return false;
537 : }
538 :
539 0 : c.currentPrecedence = lastPrecedence;
540 0 : return true;
541 : }
542 :
543 : static bool
544 0 : PrintExprList(WasmPrintContext& c, const AstExprVector& exprs, uint32_t startFrom = 0)
545 : {
546 0 : for (uint32_t i = startFrom; i < exprs.length(); i++) {
547 0 : if (!PrintBlockLevelExpr(c, *exprs[i], i + 1 == exprs.length()))
548 0 : return false;
549 : }
550 0 : return true;
551 : }
552 :
553 : static bool
554 0 : PrintGroupedBlock(WasmPrintContext& c, AstBlock& block)
555 : {
556 0 : uint32_t skip = 0;
557 0 : if (block.exprs().length() > 0 &&
558 0 : block.exprs()[0]->kind() == AstExprKind::Block) {
559 0 : if (!PrintGroupedBlock(c, *static_cast<AstBlock*>(block.exprs()[0])))
560 0 : return false;
561 0 : skip = 1;
562 : }
563 0 : c.indent++;
564 0 : if (!PrintExprList(c, block.exprs(), skip))
565 0 : return false;
566 0 : c.indent--;
567 0 : if (!PrintIndent(c))
568 0 : return false;
569 :
570 : // If no br/br_if/br_table refer this block, use some non-existent label.
571 0 : if (block.name().empty())
572 0 : return c.buffer.append("$label:\n");
573 :
574 0 : if (!PrintName(c, block.name()))
575 0 : return false;
576 0 : if (!c.buffer.append(":\n"))
577 0 : return false;
578 0 : return true;
579 : }
580 :
581 : static bool
582 0 : PrintBlockName(WasmPrintContext& c, const AstName& name) {
583 0 : if (name.empty())
584 0 : return true;
585 :
586 0 : if (!PrintIndent(c))
587 0 : return false;
588 0 : if (!PrintName(c, name))
589 0 : return false;
590 0 : return c.buffer.append(":\n");
591 : }
592 :
593 : static bool
594 0 : PrintBlock(WasmPrintContext& c, AstBlock& block)
595 : {
596 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
597 0 : if (block.op() == Op::Block) {
598 0 : if (!c.buffer.append("{\n"))
599 0 : return false;
600 0 : } else if (block.op() == Op::Loop) {
601 0 : if (!c.buffer.append("loop"))
602 0 : return false;
603 0 : if (!block.name().empty()) {
604 0 : if (!c.buffer.append(" "))
605 0 : return false;
606 0 : if (!PrintName(c, block.name()))
607 0 : return false;
608 : }
609 0 : if (!c.buffer.append(" {\n"))
610 0 : return false;
611 : } else
612 0 : return false;
613 :
614 0 : c.currentPrecedence = ExpressionPrecedence;
615 :
616 0 : bool skip = 0;
617 0 : if (c.f.groupBlocks && block.op() == Op::Block &&
618 0 : block.exprs().length() > 0 && block.exprs()[0]->kind() == AstExprKind::Block)
619 : {
620 0 : AstBlock* innerBlock = static_cast<AstBlock*>(block.exprs()[0]);
621 0 : if (innerBlock->op() == Op::Block) {
622 0 : if (!PrintGroupedBlock(c, *innerBlock))
623 0 : return false;
624 0 : skip = 1;
625 0 : if (block.exprs().length() == 1 && block.name().empty()) {
626 : // Special case to resolve ambiguity in parsing of optional end block label.
627 0 : if (!PrintIndent(c))
628 0 : return false;
629 0 : if (!c.buffer.append("$exit$:\n"))
630 0 : return false;
631 : }
632 : }
633 : }
634 :
635 0 : c.indent++;
636 0 : if (!PrintExprList(c, block.exprs(), skip))
637 0 : return false;
638 0 : c.indent--;
639 0 : c.currentPrecedence = lastPrecedence;
640 :
641 0 : if (block.op() != Op::Loop) {
642 0 : if (!PrintBlockName(c, block.name()))
643 0 : return false;
644 : }
645 :
646 0 : if (!PrintIndent(c))
647 0 : return false;
648 :
649 0 : return c.buffer.append("}");
650 : }
651 :
652 : static bool
653 0 : PrintUnaryOperator(WasmPrintContext& c, AstUnaryOperator& unary)
654 : {
655 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
656 :
657 : const char* opStr;
658 0 : const char* prefixStr = nullptr;
659 0 : PrintOperatorPrecedence precedence = OperatorPrecedence;
660 0 : switch (unary.op()) {
661 0 : case Op::I32Clz: opStr = "i32.clz"; break;
662 0 : case Op::I32Ctz: opStr = "i32.ctz"; break;
663 0 : case Op::I32Popcnt: opStr = "i32.popcnt"; break;
664 0 : case Op::I64Clz: opStr = "i64.clz"; break;
665 0 : case Op::I64Ctz: opStr = "i64.ctz"; break;
666 0 : case Op::I64Popcnt: opStr = "i64.popcnt"; break;
667 0 : case Op::F32Abs: opStr = "f32.abs"; break;
668 0 : case Op::F32Neg: opStr = "f32.neg"; prefixStr = "-"; precedence = NegatePrecedence; break;
669 0 : case Op::F32Ceil: opStr = "f32.ceil"; break;
670 0 : case Op::F32Floor: opStr = "f32.floor"; break;
671 0 : case Op::F32Sqrt: opStr = "f32.sqrt"; break;
672 0 : case Op::F32Trunc: opStr = "f32.trunc"; break;
673 0 : case Op::F32Nearest: opStr = "f32.nearest"; break;
674 0 : case Op::F64Abs: opStr = "f64.abs"; break;
675 0 : case Op::F64Neg: opStr = "f64.neg"; prefixStr = "-"; precedence = NegatePrecedence; break;
676 0 : case Op::F64Ceil: opStr = "f64.ceil"; break;
677 0 : case Op::F64Floor: opStr = "f64.floor"; break;
678 0 : case Op::F64Sqrt: opStr = "f64.sqrt"; break;
679 0 : default: return false;
680 : }
681 :
682 0 : if (c.f.allowAsciiOperators && prefixStr) {
683 0 : if (!c.f.reduceParens || lastPrecedence > precedence) {
684 0 : if (!c.buffer.append("("))
685 0 : return false;
686 : }
687 :
688 0 : c.currentPrecedence = precedence;
689 0 : if (!c.buffer.append(prefixStr, strlen(prefixStr)))
690 0 : return false;
691 0 : if (!PrintExpr(c, *unary.operand()))
692 0 : return false;
693 :
694 0 : if (!c.f.reduceParens || lastPrecedence > precedence) {
695 0 : if (!c.buffer.append(")"))
696 0 : return false;
697 : }
698 : } else {
699 0 : if (!c.buffer.append(opStr, strlen(opStr)))
700 0 : return false;
701 0 : if (!c.buffer.append("("))
702 0 : return false;
703 :
704 0 : c.currentPrecedence = ExpressionPrecedence;
705 0 : if (!PrintExpr(c, *unary.operand()))
706 0 : return false;
707 :
708 0 : if (!c.buffer.append(")"))
709 0 : return false;
710 : }
711 0 : c.currentPrecedence = lastPrecedence;
712 :
713 0 : return true;
714 : }
715 :
716 : static bool
717 0 : PrintBinaryOperator(WasmPrintContext& c, AstBinaryOperator& binary)
718 : {
719 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
720 :
721 : const char* opStr;
722 0 : const char* infixStr = nullptr;
723 : PrintOperatorPrecedence precedence;
724 0 : switch (binary.op()) {
725 0 : case Op::I32Add: opStr = "i32.add"; infixStr = "+"; precedence = AdditionPrecedence; break;
726 0 : case Op::I32Sub: opStr = "i32.sub"; infixStr = "-"; precedence = AdditionPrecedence; break;
727 0 : case Op::I32Mul: opStr = "i32.mul"; infixStr = "*"; precedence = MultiplicationPrecedence; break;
728 0 : case Op::I32DivS: opStr = "i32.div_s"; infixStr = "/s"; precedence = MultiplicationPrecedence; break;
729 0 : case Op::I32DivU: opStr = "i32.div_u"; infixStr = "/u"; precedence = MultiplicationPrecedence; break;
730 0 : case Op::I32RemS: opStr = "i32.rem_s"; infixStr = "%s"; precedence = MultiplicationPrecedence; break;
731 0 : case Op::I32RemU: opStr = "i32.rem_u"; infixStr = "%u"; precedence = MultiplicationPrecedence; break;
732 0 : case Op::I32And: opStr = "i32.and"; infixStr = "&"; precedence = BitwiseAndPrecedence; break;
733 0 : case Op::I32Or: opStr = "i32.or"; infixStr = "|"; precedence = BitwiseOrPrecedence; break;
734 0 : case Op::I32Xor: opStr = "i32.xor"; infixStr = "^"; precedence = BitwiseXorPrecedence; break;
735 0 : case Op::I32Shl: opStr = "i32.shl"; infixStr = "<<"; precedence = BitwiseShiftPrecedence; break;
736 0 : case Op::I32ShrS: opStr = "i32.shr_s"; infixStr = ">>s"; precedence = BitwiseShiftPrecedence; break;
737 0 : case Op::I32ShrU: opStr = "i32.shr_u"; infixStr = ">>u"; precedence = BitwiseShiftPrecedence; break;
738 0 : case Op::I64Add: opStr = "i64.add"; infixStr = "+"; precedence = AdditionPrecedence; break;
739 0 : case Op::I64Sub: opStr = "i64.sub"; infixStr = "-"; precedence = AdditionPrecedence; break;
740 0 : case Op::I64Mul: opStr = "i64.mul"; infixStr = "*"; precedence = MultiplicationPrecedence; break;
741 0 : case Op::I64DivS: opStr = "i64.div_s"; infixStr = "/s"; precedence = MultiplicationPrecedence; break;
742 0 : case Op::I64DivU: opStr = "i64.div_u"; infixStr = "/u"; precedence = MultiplicationPrecedence; break;
743 0 : case Op::I64RemS: opStr = "i64.rem_s"; infixStr = "%s"; precedence = MultiplicationPrecedence; break;
744 0 : case Op::I64RemU: opStr = "i64.rem_u"; infixStr = "%u"; precedence = MultiplicationPrecedence; break;
745 0 : case Op::I64And: opStr = "i64.and"; infixStr = "&"; precedence = BitwiseAndPrecedence; break;
746 0 : case Op::I64Or: opStr = "i64.or"; infixStr = "|"; precedence = BitwiseOrPrecedence; break;
747 0 : case Op::I64Xor: opStr = "i64.xor"; infixStr = "^"; precedence = BitwiseXorPrecedence; break;
748 0 : case Op::I64Shl: opStr = "i64.shl"; infixStr = "<<"; precedence = BitwiseShiftPrecedence; break;
749 0 : case Op::I64ShrS: opStr = "i64.shr_s"; infixStr = ">>s"; precedence = BitwiseShiftPrecedence; break;
750 0 : case Op::I64ShrU: opStr = "i64.shr_u"; infixStr = ">>u"; precedence = BitwiseShiftPrecedence; break;
751 0 : case Op::F32Add: opStr = "f32.add"; infixStr = "+"; precedence = AdditionPrecedence; break;
752 0 : case Op::F32Sub: opStr = "f32.sub"; infixStr = "-"; precedence = AdditionPrecedence; break;
753 0 : case Op::F32Mul: opStr = "f32.mul"; infixStr = "*"; precedence = MultiplicationPrecedence; break;
754 0 : case Op::F32Div: opStr = "f32.div"; infixStr = "/"; precedence = MultiplicationPrecedence; break;
755 0 : case Op::F32Min: opStr = "f32.min"; precedence = OperatorPrecedence; break;
756 0 : case Op::F32Max: opStr = "f32.max"; precedence = OperatorPrecedence; break;
757 0 : case Op::F32CopySign: opStr = "f32.copysign"; precedence = OperatorPrecedence; break;
758 0 : case Op::F64Add: opStr = "f64.add"; infixStr = "+"; precedence = AdditionPrecedence; break;
759 0 : case Op::F64Sub: opStr = "f64.sub"; infixStr = "-"; precedence = AdditionPrecedence; break;
760 0 : case Op::F64Mul: opStr = "f64.mul"; infixStr = "*"; precedence = MultiplicationPrecedence; break;
761 0 : case Op::F64Div: opStr = "f64.div"; infixStr = "/"; precedence = MultiplicationPrecedence; break;
762 0 : case Op::F64Min: opStr = "f64.min"; precedence = OperatorPrecedence; break;
763 0 : case Op::F64Max: opStr = "f64.max"; precedence = OperatorPrecedence; break;
764 0 : case Op::F64CopySign: opStr = "f64.copysign"; precedence = OperatorPrecedence; break;
765 0 : default: return false;
766 : }
767 :
768 0 : if (c.f.allowAsciiOperators && infixStr) {
769 0 : if (!c.f.reduceParens || lastPrecedence > precedence) {
770 0 : if (!c.buffer.append("("))
771 0 : return false;
772 : }
773 :
774 0 : c.currentPrecedence = precedence;
775 0 : if (!PrintExpr(c, *binary.lhs()))
776 0 : return false;
777 0 : if (!c.buffer.append(" "))
778 0 : return false;
779 0 : if (!c.buffer.append(infixStr, strlen(infixStr)))
780 0 : return false;
781 0 : if (!c.buffer.append(" "))
782 0 : return false;
783 : // case of A / (B / C)
784 0 : c.currentPrecedence = (PrintOperatorPrecedence)(precedence + 1);
785 :
786 0 : if (!PrintExpr(c, *binary.rhs()))
787 0 : return false;
788 0 : if (!c.f.reduceParens || lastPrecedence > precedence) {
789 0 : if (!c.buffer.append(")"))
790 0 : return false;
791 : }
792 : } else {
793 0 : if (!c.buffer.append(opStr, strlen(opStr)))
794 0 : return false;
795 0 : if (!c.buffer.append("("))
796 0 : return false;
797 :
798 0 : c.currentPrecedence = ExpressionPrecedence;
799 0 : if (!PrintExpr(c, *binary.lhs()))
800 0 : return false;
801 0 : if (!c.buffer.append(", "))
802 0 : return false;
803 0 : if (!PrintExpr(c, *binary.rhs()))
804 0 : return false;
805 :
806 0 : if (!c.buffer.append(")"))
807 0 : return false;
808 : }
809 0 : c.currentPrecedence = lastPrecedence;
810 :
811 0 : return true;
812 : }
813 :
814 : static bool
815 0 : PrintTernaryOperator(WasmPrintContext& c, AstTernaryOperator& ternary)
816 : {
817 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
818 :
819 : const char* opStr;
820 0 : switch (ternary.op()) {
821 0 : case Op::Select: opStr = "select"; break;
822 0 : default: return false;
823 : }
824 :
825 0 : if (!c.buffer.append(opStr, strlen(opStr)))
826 0 : return false;
827 0 : if (!c.buffer.append("("))
828 0 : return false;
829 :
830 0 : c.currentPrecedence = ExpressionPrecedence;
831 0 : if (!PrintExpr(c, *ternary.op0()))
832 0 : return false;
833 0 : if (!c.buffer.append(", "))
834 0 : return false;
835 0 : if (!PrintExpr(c, *ternary.op1()))
836 0 : return false;
837 0 : if (!c.buffer.append(", "))
838 0 : return false;
839 0 : if (!PrintExpr(c, *ternary.op2()))
840 0 : return false;
841 :
842 0 : if (!c.buffer.append(")"))
843 0 : return false;
844 0 : c.currentPrecedence = lastPrecedence;
845 :
846 0 : return true;
847 : }
848 :
849 : static bool
850 0 : PrintComparisonOperator(WasmPrintContext& c, AstComparisonOperator& comp)
851 : {
852 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
853 :
854 : const char* opStr;
855 0 : const char* infixStr = nullptr;
856 : PrintOperatorPrecedence precedence;
857 0 : switch (comp.op()) {
858 0 : case Op::I32Eq: opStr = "i32.eq"; infixStr = "=="; precedence = EqualityPrecedence; break;
859 0 : case Op::I32Ne: opStr = "i32.ne"; infixStr = "!="; precedence = EqualityPrecedence; break;
860 0 : case Op::I32LtS: opStr = "i32.lt_s"; infixStr = "<s"; precedence = ComparisonPrecedence; break;
861 0 : case Op::I32LtU: opStr = "i32.lt_u"; infixStr = "<u"; precedence = ComparisonPrecedence; break;
862 0 : case Op::I32LeS: opStr = "i32.le_s"; infixStr = "<=s"; precedence = ComparisonPrecedence; break;
863 0 : case Op::I32LeU: opStr = "i32.le_u"; infixStr = "<=u"; precedence = ComparisonPrecedence; break;
864 0 : case Op::I32GtS: opStr = "i32.gt_s"; infixStr = ">s"; precedence = ComparisonPrecedence; break;
865 0 : case Op::I32GtU: opStr = "i32.gt_u"; infixStr = ">u"; precedence = ComparisonPrecedence; break;
866 0 : case Op::I32GeS: opStr = "i32.ge_s"; infixStr = ">=s"; precedence = ComparisonPrecedence; break;
867 0 : case Op::I32GeU: opStr = "i32.ge_u"; infixStr = ">=u"; precedence = ComparisonPrecedence; break;
868 0 : case Op::I64Eq: opStr = "i64.eq"; infixStr = "=="; precedence = EqualityPrecedence; break;
869 0 : case Op::I64Ne: opStr = "i64.ne"; infixStr = "!="; precedence = EqualityPrecedence; break;
870 0 : case Op::I64LtS: opStr = "i64.lt_s"; infixStr = "<s"; precedence = ComparisonPrecedence; break;
871 0 : case Op::I64LtU: opStr = "i64.lt_u"; infixStr = "<u"; precedence = ComparisonPrecedence; break;
872 0 : case Op::I64LeS: opStr = "i64.le_s"; infixStr = "<=s"; precedence = ComparisonPrecedence; break;
873 0 : case Op::I64LeU: opStr = "i64.le_u"; infixStr = "<=u"; precedence = ComparisonPrecedence; break;
874 0 : case Op::I64GtS: opStr = "i64.gt_s"; infixStr = ">s"; precedence = ComparisonPrecedence; break;
875 0 : case Op::I64GtU: opStr = "i64.gt_u"; infixStr = ">u"; precedence = ComparisonPrecedence; break;
876 0 : case Op::I64GeS: opStr = "i64.ge_s"; infixStr = ">=s"; precedence = ComparisonPrecedence; break;
877 0 : case Op::I64GeU: opStr = "i64.ge_u"; infixStr = ">=u"; precedence = ComparisonPrecedence; break;
878 0 : case Op::F32Eq: opStr = "f32.eq"; infixStr = "=="; precedence = EqualityPrecedence; break;
879 0 : case Op::F32Ne: opStr = "f32.ne"; infixStr = "!="; precedence = EqualityPrecedence; break;
880 0 : case Op::F32Lt: opStr = "f32.lt"; infixStr = "<"; precedence = ComparisonPrecedence; break;
881 0 : case Op::F32Le: opStr = "f32.le"; infixStr = "<="; precedence = ComparisonPrecedence; break;
882 0 : case Op::F32Gt: opStr = "f32.gt"; infixStr = ">"; precedence = ComparisonPrecedence; break;
883 0 : case Op::F32Ge: opStr = "f32.ge"; infixStr = ">="; precedence = ComparisonPrecedence; break;
884 0 : case Op::F64Eq: opStr = "f64.eq"; infixStr = "=="; precedence = ComparisonPrecedence; break;
885 0 : case Op::F64Ne: opStr = "f64.ne"; infixStr = "!="; precedence = EqualityPrecedence; break;
886 0 : case Op::F64Lt: opStr = "f64.lt"; infixStr = "<"; precedence = EqualityPrecedence; break;
887 0 : case Op::F64Le: opStr = "f64.le"; infixStr = "<="; precedence = ComparisonPrecedence; break;
888 0 : case Op::F64Gt: opStr = "f64.gt"; infixStr = ">"; precedence = ComparisonPrecedence; break;
889 0 : case Op::F64Ge: opStr = "f64.ge"; infixStr = ">="; precedence = ComparisonPrecedence; break;
890 0 : default: return false;
891 : }
892 :
893 0 : if (c.f.allowAsciiOperators && infixStr) {
894 0 : if (!c.f.reduceParens || lastPrecedence > precedence) {
895 0 : if (!c.buffer.append("("))
896 0 : return false;
897 : }
898 0 : c.currentPrecedence = precedence;
899 0 : if (!PrintExpr(c, *comp.lhs()))
900 0 : return false;
901 0 : if (!c.buffer.append(" "))
902 0 : return false;
903 0 : if (!c.buffer.append(infixStr, strlen(infixStr)))
904 0 : return false;
905 0 : if (!c.buffer.append(" "))
906 0 : return false;
907 : // case of A == (B == C)
908 0 : c.currentPrecedence = (PrintOperatorPrecedence)(precedence + 1);
909 0 : if (!PrintExpr(c, *comp.rhs()))
910 0 : return false;
911 0 : if (!c.f.reduceParens || lastPrecedence > precedence) {
912 0 : if (!c.buffer.append(")"))
913 0 : return false;
914 : }
915 : } else {
916 0 : if (!c.buffer.append(opStr, strlen(opStr)))
917 0 : return false;
918 0 : c.currentPrecedence = ExpressionPrecedence;
919 0 : if (!c.buffer.append("("))
920 0 : return false;
921 0 : if (!PrintExpr(c, *comp.lhs()))
922 0 : return false;
923 0 : if (!c.buffer.append(", "))
924 0 : return false;
925 0 : if (!PrintExpr(c, *comp.rhs()))
926 0 : return false;
927 0 : if (!c.buffer.append(")"))
928 0 : return false;
929 : }
930 0 : c.currentPrecedence = lastPrecedence;
931 :
932 0 : return true;
933 : }
934 :
935 : static bool
936 0 : PrintConversionOperator(WasmPrintContext& c, AstConversionOperator& conv)
937 : {
938 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
939 :
940 : const char* opStr;
941 0 : const char* prefixStr = nullptr;
942 0 : PrintOperatorPrecedence precedence = ExpressionPrecedence;
943 0 : switch (conv.op()) {
944 0 : case Op::I32Eqz: opStr = "i32.eqz"; prefixStr = "!"; precedence = EqzPrecedence; break;
945 0 : case Op::I32WrapI64: opStr = "i32.wrap/i64"; break;
946 0 : case Op::I32TruncSF32: opStr = "i32.trunc_s/f32"; break;
947 0 : case Op::I32TruncUF32: opStr = "i32.trunc_u/f32"; break;
948 0 : case Op::I32ReinterpretF32: opStr = "i32.reinterpret/f32"; break;
949 0 : case Op::I32TruncSF64: opStr = "i32.trunc_s/f64"; break;
950 0 : case Op::I32TruncUF64: opStr = "i32.trunc_u/f64"; break;
951 0 : case Op::I64Eqz: opStr = "i64.eqz"; prefixStr = "!"; precedence = EqzPrecedence; break;
952 0 : case Op::I64ExtendSI32: opStr = "i64.extend_s/i32"; break;
953 0 : case Op::I64ExtendUI32: opStr = "i64.extend_u/i32"; break;
954 0 : case Op::I64TruncSF32: opStr = "i64.trunc_s/f32"; break;
955 0 : case Op::I64TruncUF32: opStr = "i64.trunc_u/f32"; break;
956 0 : case Op::I64TruncSF64: opStr = "i64.trunc_s/f64"; break;
957 0 : case Op::I64TruncUF64: opStr = "i64.trunc_u/f64"; break;
958 0 : case Op::I64ReinterpretF64: opStr = "i64.reinterpret/f64"; break;
959 0 : case Op::F32ConvertSI32: opStr = "f32.convert_s/i32"; break;
960 0 : case Op::F32ConvertUI32: opStr = "f32.convert_u/i32"; break;
961 0 : case Op::F32ReinterpretI32: opStr = "f32.reinterpret/i32"; break;
962 0 : case Op::F32ConvertSI64: opStr = "f32.convert_s/i64"; break;
963 0 : case Op::F32ConvertUI64: opStr = "f32.convert_u/i64"; break;
964 0 : case Op::F32DemoteF64: opStr = "f32.demote/f64"; break;
965 0 : case Op::F64ConvertSI32: opStr = "f64.convert_s/i32"; break;
966 0 : case Op::F64ConvertUI32: opStr = "f64.convert_u/i32"; break;
967 0 : case Op::F64ConvertSI64: opStr = "f64.convert_s/i64"; break;
968 0 : case Op::F64ConvertUI64: opStr = "f64.convert_u/i64"; break;
969 0 : case Op::F64ReinterpretI64: opStr = "f64.reinterpret/i64"; break;
970 0 : case Op::F64PromoteF32: opStr = "f64.promote/f32"; break;
971 0 : default: return false;
972 : }
973 :
974 0 : if (c.f.allowAsciiOperators && prefixStr) {
975 0 : if (!c.f.reduceParens || lastPrecedence > precedence) {
976 0 : if (!c.buffer.append("("))
977 0 : return false;
978 : }
979 :
980 0 : c.currentPrecedence = precedence;
981 0 : if (!c.buffer.append(prefixStr, strlen(prefixStr)))
982 0 : return false;
983 0 : if (!PrintExpr(c, *conv.operand()))
984 0 : return false;
985 :
986 0 : if (!c.f.reduceParens || lastPrecedence > precedence) {
987 0 : if (!c.buffer.append(")"))
988 0 : return false;
989 : }
990 : } else {
991 0 : if (!c.buffer.append(opStr, strlen(opStr)))
992 0 : return false;
993 0 : if (!c.buffer.append("("))
994 0 : return false;
995 :
996 0 : c.currentPrecedence = ExpressionPrecedence;
997 0 : if (!PrintExpr(c, *conv.operand()))
998 0 : return false;
999 :
1000 0 : if (!c.buffer.append(")"))
1001 0 : return false;
1002 : }
1003 0 : c.currentPrecedence = lastPrecedence;
1004 :
1005 0 : return true;
1006 : }
1007 :
1008 : static bool
1009 0 : PrintIf(WasmPrintContext& c, AstIf& if_)
1010 : {
1011 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
1012 :
1013 0 : c.currentPrecedence = ExpressionPrecedence;
1014 0 : if (!c.buffer.append("if ("))
1015 0 : return false;
1016 0 : if (!PrintExpr(c, if_.cond()))
1017 0 : return false;
1018 :
1019 0 : if (!c.buffer.append(") {\n"))
1020 0 : return false;
1021 :
1022 0 : c.indent++;
1023 0 : if (!PrintExprList(c, if_.thenExprs()))
1024 0 : return false;
1025 0 : c.indent--;
1026 :
1027 0 : if (!PrintBlockName(c, if_.name()))
1028 0 : return false;
1029 :
1030 0 : if (if_.hasElse()) {
1031 0 : if (!PrintIndent(c))
1032 0 : return false;
1033 0 : if (!c.buffer.append("} else {\n"))
1034 0 : return false;
1035 :
1036 0 : c.indent++;
1037 0 : if (!PrintExprList(c, if_.elseExprs()))
1038 0 : return false;
1039 0 : c.indent--;
1040 0 : if (!PrintBlockName(c, if_.name()))
1041 0 : return false;
1042 : }
1043 :
1044 0 : if (!PrintIndent(c))
1045 0 : return false;
1046 :
1047 0 : c.currentPrecedence = lastPrecedence;
1048 :
1049 0 : return c.buffer.append("}");
1050 : }
1051 :
1052 : static bool
1053 0 : PrintLoadStoreAddress(WasmPrintContext& c, const AstLoadStoreAddress& lsa, uint32_t defaultAlignLog2)
1054 : {
1055 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
1056 :
1057 0 : c.currentPrecedence = ExpressionPrecedence;
1058 :
1059 0 : if (!c.buffer.append("["))
1060 0 : return false;
1061 0 : if (!PrintExpr(c, lsa.base()))
1062 0 : return false;
1063 :
1064 0 : if (lsa.offset() != 0) {
1065 0 : if (!c.buffer.append(", "))
1066 0 : return false;
1067 0 : if (!PrintInt32(c, lsa.offset(), true))
1068 0 : return false;
1069 : }
1070 0 : if (!c.buffer.append("]"))
1071 0 : return false;
1072 :
1073 0 : uint32_t alignLog2 = lsa.flags();
1074 0 : if (defaultAlignLog2 != alignLog2) {
1075 0 : if (!c.buffer.append(", align="))
1076 0 : return false;
1077 0 : if (!PrintInt32(c, 1 << alignLog2))
1078 0 : return false;
1079 : }
1080 :
1081 0 : c.currentPrecedence = lastPrecedence;
1082 0 : return true;
1083 : }
1084 :
1085 : static bool
1086 0 : PrintLoad(WasmPrintContext& c, AstLoad& load)
1087 : {
1088 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
1089 :
1090 0 : c.currentPrecedence = LoadOperatorPrecedence;
1091 0 : if (!c.f.reduceParens || lastPrecedence > LoadOperatorPrecedence) {
1092 0 : if (!c.buffer.append("("))
1093 0 : return false;
1094 : }
1095 :
1096 : uint32_t defaultAlignLog2;
1097 0 : switch (load.op()) {
1098 : case Op::I32Load8S:
1099 0 : if (!c.buffer.append("i32:8s"))
1100 0 : return false;
1101 0 : defaultAlignLog2 = 0;
1102 0 : break;
1103 : case Op::I64Load8S:
1104 0 : if (!c.buffer.append("i64:8s"))
1105 0 : return false;
1106 0 : defaultAlignLog2 = 0;
1107 0 : break;
1108 : case Op::I32Load8U:
1109 0 : if (!c.buffer.append("i32:8u"))
1110 0 : return false;
1111 0 : defaultAlignLog2 = 0;
1112 0 : break;
1113 : case Op::I64Load8U:
1114 0 : if (!c.buffer.append("i64:8u"))
1115 0 : return false;
1116 0 : defaultAlignLog2 = 0;
1117 0 : break;
1118 : case Op::I32Load16S:
1119 0 : if (!c.buffer.append("i32:16s"))
1120 0 : return false;
1121 0 : defaultAlignLog2 = 1;
1122 0 : break;
1123 : case Op::I64Load16S:
1124 0 : if (!c.buffer.append("i64:16s"))
1125 0 : return false;
1126 0 : defaultAlignLog2 = 1;
1127 0 : break;
1128 : case Op::I32Load16U:
1129 0 : if (!c.buffer.append("i32:16u"))
1130 0 : return false;
1131 0 : defaultAlignLog2 = 1;
1132 0 : break;
1133 : case Op::I64Load16U:
1134 0 : if (!c.buffer.append("i64:16u"))
1135 0 : return false;
1136 0 : defaultAlignLog2 = 1;
1137 0 : break;
1138 : case Op::I64Load32S:
1139 0 : if (!c.buffer.append("i64:32s"))
1140 0 : return false;
1141 0 : defaultAlignLog2 = 2;
1142 0 : break;
1143 : case Op::I64Load32U:
1144 0 : if (!c.buffer.append("i64:32u"))
1145 0 : return false;
1146 0 : defaultAlignLog2 = 2;
1147 0 : break;
1148 : case Op::I32Load:
1149 0 : if (!c.buffer.append("i32"))
1150 0 : return false;
1151 0 : defaultAlignLog2 = 2;
1152 0 : break;
1153 : case Op::I64Load:
1154 0 : if (!c.buffer.append("i64"))
1155 0 : return false;
1156 0 : defaultAlignLog2 = 3;
1157 0 : break;
1158 : case Op::F32Load:
1159 0 : if (!c.buffer.append("f32"))
1160 0 : return false;
1161 0 : defaultAlignLog2 = 2;
1162 0 : break;
1163 : case Op::F64Load:
1164 0 : if (!c.buffer.append("f64"))
1165 0 : return false;
1166 0 : defaultAlignLog2 = 3;
1167 0 : break;
1168 : default:
1169 0 : return false;
1170 : }
1171 :
1172 0 : if (!PrintLoadStoreAddress(c, load.address(), defaultAlignLog2))
1173 0 : return false;
1174 :
1175 0 : if (!c.f.reduceParens || lastPrecedence > LoadOperatorPrecedence) {
1176 0 : if (!c.buffer.append(")"))
1177 0 : return false;
1178 : }
1179 0 : c.currentPrecedence = lastPrecedence;
1180 :
1181 0 : return true;
1182 : }
1183 :
1184 : static bool
1185 0 : PrintStore(WasmPrintContext& c, AstStore& store)
1186 : {
1187 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
1188 :
1189 0 : c.currentPrecedence = StoreOperatorPrecedence;
1190 0 : if (!c.f.reduceParens || lastPrecedence > StoreOperatorPrecedence) {
1191 0 : if (!c.buffer.append("("))
1192 0 : return false;
1193 : }
1194 :
1195 : uint32_t defaultAlignLog2;
1196 0 : switch (store.op()) {
1197 : case Op::I32Store8:
1198 0 : if (!c.buffer.append("i32:8"))
1199 0 : return false;
1200 0 : defaultAlignLog2 = 0;
1201 0 : break;
1202 : case Op::I64Store8:
1203 0 : if (!c.buffer.append("i64:8"))
1204 0 : return false;
1205 0 : defaultAlignLog2 = 0;
1206 0 : break;
1207 : case Op::I32Store16:
1208 0 : if (!c.buffer.append("i32:16"))
1209 0 : return false;
1210 0 : defaultAlignLog2 = 1;
1211 0 : break;
1212 : case Op::I64Store16:
1213 0 : if (!c.buffer.append("i64:16"))
1214 0 : return false;
1215 0 : defaultAlignLog2 = 1;
1216 0 : break;
1217 : case Op::I64Store32:
1218 0 : if (!c.buffer.append("i64:32"))
1219 0 : return false;
1220 0 : defaultAlignLog2 = 2;
1221 0 : break;
1222 : case Op::I32Store:
1223 0 : if (!c.buffer.append("i32"))
1224 0 : return false;
1225 0 : defaultAlignLog2 = 2;
1226 0 : break;
1227 : case Op::I64Store:
1228 0 : if (!c.buffer.append("i64"))
1229 0 : return false;
1230 0 : defaultAlignLog2 = 3;
1231 0 : break;
1232 : case Op::F32Store:
1233 0 : if (!c.buffer.append("f32"))
1234 0 : return false;
1235 0 : defaultAlignLog2 = 2;
1236 0 : break;
1237 : case Op::F64Store:
1238 0 : if (!c.buffer.append("f64"))
1239 0 : return false;
1240 0 : defaultAlignLog2 = 3;
1241 0 : break;
1242 : default:
1243 0 : return false;
1244 : }
1245 :
1246 0 : if (!PrintLoadStoreAddress(c, store.address(), defaultAlignLog2))
1247 0 : return false;
1248 :
1249 0 : if (!c.buffer.append(" = "))
1250 0 : return false;
1251 :
1252 0 : if (!PrintExpr(c, store.value()))
1253 0 : return false;
1254 :
1255 0 : if (!c.f.reduceParens || lastPrecedence > StoreOperatorPrecedence) {
1256 0 : if (!c.buffer.append(")"))
1257 0 : return false;
1258 : }
1259 :
1260 0 : c.currentPrecedence = lastPrecedence;
1261 0 : return true;
1262 : }
1263 :
1264 : static bool
1265 0 : PrintBranch(WasmPrintContext& c, AstBranch& branch)
1266 : {
1267 0 : Op op = branch.op();
1268 0 : MOZ_ASSERT(op == Op::BrIf || op == Op::Br);
1269 :
1270 0 : if (op == Op::BrIf ? !c.buffer.append("br_if ") : !c.buffer.append("br "))
1271 0 : return false;
1272 :
1273 0 : if (op == Op::BrIf || branch.maybeValue()) {
1274 0 : if (!c.buffer.append('('))
1275 0 : return false;
1276 : }
1277 :
1278 0 : if (op == Op::BrIf) {
1279 0 : if (!PrintExpr(c, branch.cond()))
1280 0 : return false;
1281 : }
1282 :
1283 0 : if (branch.maybeValue()) {
1284 0 : if (!c.buffer.append(", "))
1285 0 : return false;
1286 :
1287 0 : if (!PrintExpr(c, *(branch.maybeValue())))
1288 0 : return false;
1289 : }
1290 :
1291 0 : if (op == Op::BrIf || branch.maybeValue()) {
1292 0 : if (!c.buffer.append(") "))
1293 0 : return false;
1294 : }
1295 :
1296 0 : if (!PrintRef(c, branch.target()))
1297 0 : return false;
1298 :
1299 0 : return true;
1300 : }
1301 :
1302 : static bool
1303 0 : PrintBrTable(WasmPrintContext& c, AstBranchTable& table)
1304 : {
1305 0 : if (!c.buffer.append("br_table "))
1306 0 : return false;
1307 :
1308 0 : if (!c.buffer.append('('))
1309 0 : return false;
1310 :
1311 : // Index
1312 0 : if (!PrintExpr(c, table.index()))
1313 0 : return false;
1314 :
1315 0 : if (table.maybeValue()) {
1316 0 : if (!c.buffer.append(", "))
1317 0 : return false;
1318 :
1319 0 : if (!PrintExpr(c, *(table.maybeValue())))
1320 0 : return false;
1321 : }
1322 :
1323 0 : if (!c.buffer.append(") "))
1324 0 : return false;
1325 :
1326 0 : uint32_t tableLength = table.table().length();
1327 0 : if (tableLength > 0) {
1328 0 : if (!c.buffer.append("["))
1329 0 : return false;
1330 0 : for (uint32_t i = 0; i < tableLength; i++) {
1331 0 : if (!PrintRef(c, table.table()[i]))
1332 0 : return false;
1333 0 : if (i + 1 == tableLength)
1334 0 : break;
1335 0 : if (!c.buffer.append(", "))
1336 0 : return false;
1337 : }
1338 0 : if (!c.buffer.append("], "))
1339 0 : return false;
1340 : }
1341 :
1342 0 : if (!PrintRef(c, table.def()))
1343 0 : return false;
1344 :
1345 0 : return true;
1346 : }
1347 :
1348 : static bool
1349 0 : PrintReturn(WasmPrintContext& c, AstReturn& ret)
1350 : {
1351 0 : if (!c.buffer.append("return"))
1352 0 : return false;
1353 :
1354 0 : if (ret.maybeExpr()) {
1355 0 : if (!c.buffer.append(" "))
1356 0 : return false;
1357 0 : if (!PrintExpr(c, *(ret.maybeExpr())))
1358 0 : return false;
1359 : }
1360 :
1361 0 : return true;
1362 : }
1363 :
1364 : static bool
1365 0 : PrintFirst(WasmPrintContext& c, AstFirst& first)
1366 : {
1367 0 : if (!c.buffer.append("first("))
1368 0 : return false;
1369 :
1370 0 : for (uint32_t i = 0; i < first.exprs().length(); i++) {
1371 0 : if (!PrintExpr(c, *first.exprs()[i]))
1372 0 : return false;
1373 0 : if (i + 1 == first.exprs().length())
1374 0 : break;
1375 0 : if (!c.buffer.append(", "))
1376 0 : return false;
1377 : }
1378 :
1379 0 : if (!c.buffer.append(")"))
1380 0 : return false;
1381 :
1382 0 : return true;
1383 : }
1384 :
1385 : static bool
1386 0 : PrintCurrentMemory(WasmPrintContext& c, AstCurrentMemory& cm)
1387 : {
1388 0 : return c.buffer.append("current_memory");
1389 : }
1390 :
1391 : static bool
1392 0 : PrintGrowMemory(WasmPrintContext& c, AstGrowMemory& gm)
1393 : {
1394 0 : if (!c.buffer.append("grow_memory("))
1395 0 : return false;
1396 :
1397 0 : PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
1398 0 : c.currentPrecedence = ExpressionPrecedence;
1399 :
1400 0 : if (!PrintExpr(c, *gm.operand()))
1401 0 : return false;
1402 :
1403 0 : if (!c.buffer.append(")"))
1404 0 : return false;
1405 :
1406 0 : c.currentPrecedence = lastPrecedence;
1407 0 : return true;
1408 : }
1409 :
1410 : static bool
1411 0 : PrintExpr(WasmPrintContext& c, AstExpr& expr)
1412 : {
1413 0 : if (c.maybeSourceMap) {
1414 0 : uint32_t lineno = c.buffer.lineno();
1415 0 : uint32_t column = c.buffer.column();
1416 0 : if (!c.maybeSourceMap->exprlocs().emplaceBack(lineno, column, expr.offset()))
1417 0 : return false;
1418 : }
1419 :
1420 0 : switch (expr.kind()) {
1421 : case AstExprKind::Nop:
1422 0 : return PrintNop(c);
1423 : case AstExprKind::Drop:
1424 0 : return PrintDrop(c, expr.as<AstDrop>());
1425 : case AstExprKind::Unreachable:
1426 0 : return PrintUnreachable(c, expr.as<AstUnreachable>());
1427 : case AstExprKind::Call:
1428 0 : return PrintCall(c, expr.as<AstCall>());
1429 : case AstExprKind::CallIndirect:
1430 0 : return PrintCallIndirect(c, expr.as<AstCallIndirect>());
1431 : case AstExprKind::Const:
1432 0 : return PrintConst(c, expr.as<AstConst>());
1433 : case AstExprKind::GetLocal:
1434 0 : return PrintGetLocal(c, expr.as<AstGetLocal>());
1435 : case AstExprKind::SetLocal:
1436 0 : return PrintSetLocal(c, expr.as<AstSetLocal>());
1437 : case AstExprKind::TeeLocal:
1438 0 : return PrintTeeLocal(c, expr.as<AstTeeLocal>());
1439 : case AstExprKind::GetGlobal:
1440 0 : return PrintGetGlobal(c, expr.as<AstGetGlobal>());
1441 : case AstExprKind::SetGlobal:
1442 0 : return PrintSetGlobal(c, expr.as<AstSetGlobal>());
1443 : case AstExprKind::Block:
1444 0 : return PrintBlock(c, expr.as<AstBlock>());
1445 : case AstExprKind::If:
1446 0 : return PrintIf(c, expr.as<AstIf>());
1447 : case AstExprKind::UnaryOperator:
1448 0 : return PrintUnaryOperator(c, expr.as<AstUnaryOperator>());
1449 : case AstExprKind::BinaryOperator:
1450 0 : return PrintBinaryOperator(c, expr.as<AstBinaryOperator>());
1451 : case AstExprKind::TernaryOperator:
1452 0 : return PrintTernaryOperator(c, expr.as<AstTernaryOperator>());
1453 : case AstExprKind::ComparisonOperator:
1454 0 : return PrintComparisonOperator(c, expr.as<AstComparisonOperator>());
1455 : case AstExprKind::ConversionOperator:
1456 0 : return PrintConversionOperator(c, expr.as<AstConversionOperator>());
1457 : case AstExprKind::Load:
1458 0 : return PrintLoad(c, expr.as<AstLoad>());
1459 : case AstExprKind::Store:
1460 0 : return PrintStore(c, expr.as<AstStore>());
1461 : case AstExprKind::Branch:
1462 0 : return PrintBranch(c, expr.as<AstBranch>());
1463 : case AstExprKind::BranchTable:
1464 0 : return PrintBrTable(c, expr.as<AstBranchTable>());
1465 : case AstExprKind::Return:
1466 0 : return PrintReturn(c, expr.as<AstReturn>());
1467 : case AstExprKind::First:
1468 0 : return PrintFirst(c, expr.as<AstFirst>());
1469 : case AstExprKind::CurrentMemory:
1470 0 : return PrintCurrentMemory(c, expr.as<AstCurrentMemory>());
1471 : case AstExprKind::GrowMemory:
1472 0 : return PrintGrowMemory(c, expr.as<AstGrowMemory>());
1473 : case AstExprKind::Pop:
1474 0 : return true;
1475 : }
1476 :
1477 0 : MOZ_CRASH("Bad AstExprKind");
1478 : }
1479 :
1480 : static bool
1481 0 : PrintSignature(WasmPrintContext& c, const AstSig& sig, const AstNameVector* maybeLocals = nullptr)
1482 : {
1483 0 : uint32_t paramsNum = sig.args().length();
1484 :
1485 0 : if (!c.buffer.append("("))
1486 0 : return false;
1487 0 : if (maybeLocals) {
1488 0 : for (uint32_t i = 0; i < paramsNum; i++) {
1489 0 : const AstName& name = (*maybeLocals)[i];
1490 0 : if (!name.empty()) {
1491 0 : if (!PrintName(c, name))
1492 0 : return false;
1493 0 : if (!c.buffer.append(": "))
1494 0 : return false;
1495 : }
1496 0 : ValType arg = sig.args()[i];
1497 0 : if (!PrintValType(c, arg))
1498 0 : return false;
1499 0 : if (i + 1 == paramsNum)
1500 0 : break;
1501 0 : if (!c.buffer.append(", "))
1502 0 : return false;
1503 : }
1504 0 : } else if (paramsNum > 0) {
1505 0 : for (uint32_t i = 0; i < paramsNum; i++) {
1506 0 : ValType arg = sig.args()[i];
1507 0 : if (!PrintValType(c, arg))
1508 0 : return false;
1509 0 : if (i + 1 == paramsNum)
1510 0 : break;
1511 0 : if (!c.buffer.append(", "))
1512 0 : return false;
1513 : }
1514 : }
1515 0 : if (!c.buffer.append(") : ("))
1516 0 : return false;
1517 0 : if (sig.ret() != ExprType::Void) {
1518 0 : if (!PrintExprType(c, sig.ret()))
1519 0 : return false;
1520 : }
1521 0 : if (!c.buffer.append(")"))
1522 0 : return false;
1523 0 : return true;
1524 : }
1525 :
1526 : static bool
1527 0 : PrintTypeSection(WasmPrintContext& c, const AstModule::SigVector& sigs)
1528 : {
1529 0 : uint32_t numSigs = sigs.length();
1530 0 : if (!numSigs)
1531 0 : return true;
1532 :
1533 0 : for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
1534 0 : const AstSig* sig = sigs[sigIndex];
1535 0 : if (!PrintIndent(c))
1536 0 : return false;
1537 0 : if (!c.buffer.append("type "))
1538 0 : return false;
1539 0 : if (!sig->name().empty()) {
1540 0 : if (!PrintName(c, sig->name()))
1541 0 : return false;
1542 0 : if (!c.buffer.append(" of "))
1543 0 : return false;
1544 : }
1545 0 : if (!c.buffer.append("function "))
1546 0 : return false;
1547 0 : if (!PrintSignature(c, *sig))
1548 0 : return false;
1549 0 : if (!c.buffer.append(";\n"))
1550 0 : return false;
1551 : }
1552 :
1553 0 : if (!c.buffer.append("\n"))
1554 0 : return false;
1555 :
1556 0 : return true;
1557 : }
1558 :
1559 : static bool
1560 0 : PrintTableSection(WasmPrintContext& c, const AstModule& module)
1561 : {
1562 0 : if (module.elemSegments().empty())
1563 0 : return true;
1564 :
1565 0 : const AstElemSegment& segment = *module.elemSegments()[0];
1566 :
1567 0 : if (!c.buffer.append("table ["))
1568 0 : return false;
1569 :
1570 0 : for (uint32_t i = 0; i < segment.elems().length(); i++) {
1571 0 : const AstRef& elem = segment.elems()[i];
1572 0 : uint32_t index = elem.index();
1573 0 : AstName name = index < module.funcImportNames().length()
1574 0 : ? module.funcImportNames()[index]
1575 0 : : module.funcs()[index - module.funcImportNames().length()]->name();
1576 0 : if (name.empty()) {
1577 0 : if (!PrintInt32(c, index))
1578 0 : return false;
1579 : } else {
1580 0 : if (!PrintName(c, name))
1581 0 : return false;
1582 : }
1583 0 : if (i + 1 == segment.elems().length())
1584 0 : break;
1585 0 : if (!c.buffer.append(", "))
1586 0 : return false;
1587 : }
1588 :
1589 0 : if (!c.buffer.append("];\n\n"))
1590 0 : return false;
1591 :
1592 0 : return true;
1593 : }
1594 :
1595 : static bool
1596 0 : PrintImport(WasmPrintContext& c, AstImport& import, const AstModule::SigVector& sigs)
1597 : {
1598 0 : const AstSig* sig = sigs[import.funcSig().index()];
1599 0 : if (!PrintIndent(c))
1600 0 : return false;
1601 0 : if (!c.buffer.append("import "))
1602 0 : return false;
1603 0 : if (!c.buffer.append("\""))
1604 0 : return false;
1605 :
1606 0 : const AstName& fieldName = import.field();
1607 0 : if (!PrintEscapedString(c, fieldName))
1608 0 : return false;
1609 :
1610 0 : if (!c.buffer.append("\" as "))
1611 0 : return false;
1612 :
1613 0 : if (!PrintName(c, import.name()))
1614 0 : return false;
1615 :
1616 0 : if (!c.buffer.append(" from \""))
1617 0 : return false;
1618 :
1619 0 : const AstName& moduleName = import.module();
1620 0 : if (!PrintEscapedString(c, moduleName))
1621 0 : return false;
1622 :
1623 0 : if (!c.buffer.append("\" typeof function "))
1624 0 : return false;
1625 :
1626 0 : if (!PrintSignature(c, *sig))
1627 0 : return false;
1628 0 : if (!c.buffer.append(";\n"))
1629 0 : return false;
1630 :
1631 0 : return true;
1632 : }
1633 :
1634 :
1635 : static bool
1636 0 : PrintImportSection(WasmPrintContext& c, const AstModule::ImportVector& imports, const AstModule::SigVector& sigs)
1637 : {
1638 0 : uint32_t numImports = imports.length();
1639 :
1640 0 : for (uint32_t i = 0; i < numImports; i++) {
1641 0 : if (!PrintImport(c, *imports[i], sigs))
1642 0 : return false;
1643 : }
1644 :
1645 0 : if (numImports) {
1646 0 : if (!c.buffer.append("\n"))
1647 0 : return false;
1648 : }
1649 :
1650 0 : return true;
1651 : }
1652 :
1653 : static bool
1654 0 : PrintExport(WasmPrintContext& c, AstExport& export_,
1655 : const AstModule::NameVector& funcImportNames,
1656 : const AstModule::FuncVector& funcs)
1657 : {
1658 0 : if (!PrintIndent(c))
1659 0 : return false;
1660 0 : if (!c.buffer.append("export "))
1661 0 : return false;
1662 0 : if (export_.kind() == DefinitionKind::Memory) {
1663 0 : if (!c.buffer.append("memory"))
1664 0 : return false;
1665 : } else {
1666 0 : uint32_t index = export_.ref().index();
1667 0 : AstName name = index < funcImportNames.length()
1668 0 : ? funcImportNames[index]
1669 0 : : funcs[index - funcImportNames.length()]->name();
1670 0 : if (name.empty()) {
1671 0 : if (!PrintInt32(c, index))
1672 0 : return false;
1673 : } else {
1674 0 : if (!PrintName(c, name))
1675 0 : return false;
1676 : }
1677 : }
1678 0 : if (!c.buffer.append(" as \""))
1679 0 : return false;
1680 0 : if (!PrintEscapedString(c, export_.name()))
1681 0 : return false;
1682 0 : if (!c.buffer.append("\";\n"))
1683 0 : return false;
1684 :
1685 0 : return true;
1686 : }
1687 :
1688 : static bool
1689 0 : PrintExportSection(WasmPrintContext& c, const AstModule::ExportVector& exports,
1690 : const AstModule::NameVector& funcImportNames,
1691 : const AstModule::FuncVector& funcs)
1692 : {
1693 0 : uint32_t numExports = exports.length();
1694 0 : for (uint32_t i = 0; i < numExports; i++) {
1695 0 : if (!PrintExport(c, *exports[i], funcImportNames, funcs))
1696 0 : return false;
1697 : }
1698 0 : if (numExports) {
1699 0 : if (!c.buffer.append("\n"))
1700 0 : return false;
1701 : }
1702 0 : return true;
1703 : }
1704 :
1705 : static bool
1706 0 : PrintFunctionBody(WasmPrintContext& c, AstFunc& func, const AstModule::SigVector& sigs)
1707 : {
1708 0 : const AstSig* sig = sigs[func.sig().index()];
1709 0 : c.indent++;
1710 :
1711 0 : uint32_t argsNum = sig->args().length();
1712 0 : uint32_t localsNum = func.vars().length();
1713 0 : if (localsNum > 0) {
1714 0 : if (!PrintIndent(c))
1715 0 : return false;
1716 0 : if (!c.buffer.append("var "))
1717 0 : return false;
1718 0 : for (uint32_t i = 0; i < localsNum; i++) {
1719 0 : const AstName& name = func.locals()[argsNum + i];
1720 0 : if (!name.empty()) {
1721 0 : if (!PrintName(c, name))
1722 0 : return false;
1723 0 : if (!c.buffer.append(": "))
1724 0 : return false;
1725 : }
1726 0 : ValType local = func.vars()[i];
1727 0 : if (!PrintValType(c, local))
1728 0 : return false;
1729 0 : if (i + 1 == localsNum)
1730 0 : break;
1731 0 : if (!c.buffer.append(", "))
1732 0 : return false;
1733 : }
1734 0 : if (!c.buffer.append(";\n"))
1735 0 : return false;
1736 : }
1737 :
1738 :
1739 0 : uint32_t exprsNum = func.body().length();
1740 0 : for (uint32_t i = 0; i < exprsNum; i++) {
1741 0 : if (!PrintBlockLevelExpr(c, *func.body()[i], i + 1 == exprsNum))
1742 0 : return false;
1743 : }
1744 :
1745 0 : c.indent--;
1746 :
1747 0 : if (c.maybeSourceMap) {
1748 0 : if (!c.maybeSourceMap->exprlocs().emplaceBack(c.buffer.lineno(), c.buffer.column(), func.endOffset()))
1749 0 : return false;
1750 : }
1751 0 : return true;
1752 : }
1753 :
1754 : static bool
1755 0 : PrintCodeSection(WasmPrintContext& c, const AstModule::FuncVector& funcs, const AstModule::SigVector& sigs)
1756 : {
1757 0 : uint32_t numFuncBodies = funcs.length();
1758 0 : for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
1759 0 : AstFunc* func = funcs[funcIndex];
1760 0 : uint32_t sigIndex = func->sig().index();
1761 0 : AstSig* sig = sigs[sigIndex];
1762 :
1763 0 : if (!PrintIndent(c))
1764 0 : return false;
1765 0 : if (!c.buffer.append("function "))
1766 0 : return false;
1767 0 : if (!func->name().empty()) {
1768 0 : if (!PrintName(c, func->name()))
1769 0 : return false;
1770 : }
1771 :
1772 0 : if (!PrintSignature(c, *sig, &(func->locals())))
1773 0 : return false;
1774 0 : if (!c.buffer.append(" {\n"))
1775 0 : return false;
1776 :
1777 0 : c.currentFuncIndex = funcIndex;
1778 :
1779 0 : if (!PrintFunctionBody(c, *func, sigs))
1780 0 : return false;
1781 :
1782 0 : if (!PrintIndent(c))
1783 0 : return false;
1784 0 : if (!c.buffer.append("}\n\n"))
1785 0 : return false;
1786 : }
1787 :
1788 0 : return true;
1789 : }
1790 :
1791 : static bool
1792 0 : PrintDataSection(WasmPrintContext& c, const AstModule& module)
1793 : {
1794 0 : if (!module.hasMemory())
1795 0 : return true;
1796 :
1797 0 : MOZ_ASSERT(module.memories().length() == 1, "NYI: several memories");
1798 :
1799 0 : if (!PrintIndent(c))
1800 0 : return false;
1801 0 : if (!c.buffer.append("memory "))
1802 0 : return false;
1803 :
1804 0 : const Limits& memory = module.memories()[0].limits;
1805 0 : MOZ_ASSERT(memory.initial % PageSize == 0);
1806 0 : if (!PrintInt32(c, memory.initial / PageSize))
1807 0 : return false;
1808 :
1809 0 : if (memory.maximum) {
1810 0 : MOZ_ASSERT(*memory.maximum % PageSize == 0);
1811 0 : if (!c.buffer.append(", "))
1812 0 : return false;
1813 0 : if (!PrintInt32(c, *memory.maximum / PageSize))
1814 0 : return false;
1815 : }
1816 :
1817 0 : c.indent++;
1818 :
1819 0 : uint32_t numSegments = module.dataSegments().length();
1820 0 : if (!numSegments) {
1821 0 : if (!c.buffer.append(" {}\n\n"))
1822 0 : return false;
1823 0 : return true;
1824 : }
1825 0 : if (!c.buffer.append(" {\n"))
1826 0 : return false;
1827 :
1828 0 : for (uint32_t i = 0; i < numSegments; i++) {
1829 0 : const AstDataSegment* segment = module.dataSegments()[i];
1830 0 : if (!PrintIndent(c))
1831 0 : return false;
1832 0 : if (!c.buffer.append("segment "))
1833 0 : return false;
1834 0 : if (!PrintInt32(c, segment->offset()->as<AstConst>().val().i32()))
1835 0 : return false;
1836 0 : if (!c.buffer.append("\n"))
1837 0 : return false;
1838 :
1839 0 : c.indent++;
1840 0 : for (const AstName& fragment : segment->fragments()) {
1841 0 : if (!PrintIndent(c))
1842 0 : return false;
1843 0 : if (!c.buffer.append("\""))
1844 0 : return false;
1845 0 : if (!PrintEscapedString(c, fragment))
1846 0 : return false;
1847 0 : if (!c.buffer.append("\"\n"))
1848 0 : return false;
1849 : }
1850 0 : c.indent--;
1851 :
1852 0 : if (!PrintIndent(c))
1853 0 : return false;
1854 0 : if (!c.buffer.append(";\n"))
1855 0 : return false;
1856 : }
1857 :
1858 0 : c.indent--;
1859 0 : if (!c.buffer.append("}\n\n"))
1860 0 : return false;
1861 :
1862 0 : return true;
1863 : }
1864 :
1865 : static bool
1866 0 : PrintModule(WasmPrintContext& c, AstModule& module)
1867 : {
1868 0 : if (!PrintTypeSection(c, module.sigs()))
1869 0 : return false;
1870 :
1871 0 : if (!PrintImportSection(c, module.imports(), module.sigs()))
1872 0 : return false;
1873 :
1874 0 : if (!PrintTableSection(c, module))
1875 0 : return false;
1876 :
1877 0 : if (!PrintExportSection(c, module.exports(), module.funcImportNames(), module.funcs()))
1878 0 : return false;
1879 :
1880 0 : if (!PrintCodeSection(c, module.funcs(), module.sigs()))
1881 0 : return false;
1882 :
1883 0 : if (!PrintDataSection(c, module))
1884 0 : return false;
1885 :
1886 0 : return true;
1887 : }
1888 :
1889 : /*****************************************************************************/
1890 : // Top-level functions
1891 :
1892 : bool
1893 0 : wasm::BinaryToExperimentalText(JSContext* cx, const uint8_t* bytes, size_t length,
1894 : StringBuffer& buffer, const ExperimentalTextFormatting& formatting,
1895 : GeneratedSourceMap* sourceMap)
1896 : {
1897 :
1898 0 : LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
1899 :
1900 : AstModule* module;
1901 0 : if (!BinaryToAst(cx, bytes, length, lifo, &module))
1902 0 : return false;
1903 :
1904 0 : WasmPrintBuffer buf(buffer);
1905 0 : WasmPrintContext c(cx, module, buf, formatting, sourceMap);
1906 :
1907 0 : if (!PrintModule(c, *module)) {
1908 0 : if (!cx->isExceptionPending())
1909 0 : ReportOutOfMemory(cx);
1910 0 : return false;
1911 : }
1912 :
1913 0 : return true;
1914 : }
1915 :
|