Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(534)

Side by Side Diff: src/wasm/s-expr.cc

Issue 2520943002: [wasm] Implement official wasm text format (Closed)
Patch Set: Return a value even after UNREACHABLE Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/wasm/s-expr.h"
6
7 #include "src/ostreams.h"
8 #include "src/wasm/ast-decoder.h"
9 #include "src/wasm/wasm-module.h"
10 #include "src/wasm/wasm-opcodes.h"
11 #include "src/zone/zone.h"
12
13 using namespace v8::internal;
14 using namespace v8::internal::wasm;
15
16 namespace {
17 const char *GetOpName(WasmOpcode opcode) {
18 #define CASE_OP(name, str) \
19 case kExpr##name: \
20 return str;
21 #define CASE_I32_OP(name, str) CASE_OP(I32##name, "i32." str)
22 #define CASE_I64_OP(name, str) CASE_OP(I64##name, "i64." str)
23 #define CASE_F32_OP(name, str) CASE_OP(F32##name, "f32." str)
24 #define CASE_F64_OP(name, str) CASE_OP(F64##name, "f64." str)
25 #define CASE_INT_OP(name, str) CASE_I32_OP(name, str) CASE_I64_OP(name, str)
26 #define CASE_FLOAT_OP(name, str) CASE_F32_OP(name, str) CASE_F64_OP(name, str)
27 #define CASE_ALL_OP(name, str) CASE_FLOAT_OP(name, str) CASE_INT_OP(name, str)
28 #define CASE_SIGN_OP(TYPE, name, str) \
29 CASE_##TYPE##_OP(name##S, str "_s") CASE_##TYPE##_OP(name##U, str "_u")
30 #define CASE_ALL_SIGN_OP(name, str) \
31 CASE_FLOAT_OP(name, str) CASE_SIGN_OP(INT, name, str)
32 #define CASE_CONVERT_OP(name, RES, SRC, src_suffix, str) \
33 CASE_##RES##_OP(U##name##SRC, str "_u/" src_suffix) \
34 CASE_##RES##_OP(S##name##SRC, str "_s/" src_suffix)
35
36 switch (opcode) {
37 CASE_INT_OP(Eqz, "eqz")
titzer 2016/11/21 14:57:26 Nice! This is well macro'd code :-)
38 CASE_ALL_OP(Eq, "eq")
39 CASE_ALL_OP(Ne, "ne")
40 CASE_ALL_OP(Add, "add")
41 CASE_ALL_OP(Sub, "sub")
42 CASE_ALL_OP(Mul, "mul")
43 CASE_ALL_SIGN_OP(Lt, "lt")
44 CASE_ALL_SIGN_OP(Gt, "gt")
45 CASE_ALL_SIGN_OP(Le, "le")
46 CASE_ALL_SIGN_OP(Ge, "ge")
47 CASE_INT_OP(Clz, "clz")
48 CASE_INT_OP(Ctz, "ctz")
49 CASE_INT_OP(Popcnt, "popcnt")
50 CASE_ALL_SIGN_OP(Div, "div")
51 CASE_SIGN_OP(INT, Rem, "rem")
52 CASE_INT_OP(And, "and")
53 CASE_INT_OP(Ior, "or")
54 CASE_INT_OP(Xor, "xor")
55 CASE_INT_OP(Shl, "shl")
56 CASE_SIGN_OP(INT, Shr, "shr")
rossberg 2016/11/21 15:03:51 Nit: there should be CASE_INT_SIGN_OP for symmetry
Clemens Hammacher 2016/11/21 17:48:40 I use CASE_SIGN_OP for both I64 and INT. So I woul
57 CASE_INT_OP(Rol, "rol")
58 CASE_INT_OP(Ror, "ror")
59 CASE_FLOAT_OP(Abs, "abs")
60 CASE_FLOAT_OP(Neg, "neg")
61 CASE_FLOAT_OP(Ceil, "ceil")
62 CASE_FLOAT_OP(Floor, "floor")
63 CASE_FLOAT_OP(Trunc, "trunc")
64 CASE_FLOAT_OP(NearestInt, "nearest")
65 CASE_FLOAT_OP(Sqrt, "sqrt")
66 CASE_FLOAT_OP(Min, "min")
67 CASE_FLOAT_OP(Max, "max")
68 CASE_FLOAT_OP(CopySign, "copysign")
69 CASE_I32_OP(ConvertI64, "wrap/i64")
70 CASE_CONVERT_OP(Convert, INT, F32, "f32", "trunc")
71 CASE_CONVERT_OP(Convert, INT, F64, "f64", "trunc")
72 CASE_CONVERT_OP(Convert, I64, I32, "i32", "extend")
73 CASE_CONVERT_OP(Convert, F32, I32, "i32", "convert")
74 CASE_CONVERT_OP(Convert, F32, I64, "i64", "convert")
75 CASE_F32_OP(ConvertF64, "demote/f64")
76 CASE_CONVERT_OP(Convert, F64, I32, "i32", "convert")
77 CASE_CONVERT_OP(Convert, F64, I64, "i64", "convert")
78 CASE_F64_OP(ConvertF32, "promote/f32")
79 CASE_I32_OP(ReinterpretF32, "reinterpret/f32")
80 CASE_I64_OP(ReinterpretF64, "reinterpret/f64")
81 CASE_F32_OP(ReinterpretI32, "reinterpret/i32")
82 CASE_F64_OP(ReinterpretI64, "reinterpret/i64")
83 CASE_OP(Unreachable, "unreachable")
84 CASE_OP(Nop, "nop")
85 CASE_OP(Return, "return")
86 CASE_OP(MemorySize, "current_memory")
87 CASE_OP(GrowMemory, "grow_memory")
88 CASE_OP(Loop, "loop")
89 CASE_OP(If, "if")
90 CASE_OP(Block, "block")
91 CASE_OP(Try, "try")
92 CASE_OP(Throw, "throw")
93 CASE_OP(Catch, "catch")
94 CASE_OP(Drop, "drop")
95 CASE_ALL_OP(LoadMem, "load")
96 CASE_SIGN_OP(INT, LoadMem8, "load8")
97 CASE_SIGN_OP(INT, LoadMem16, "load16")
98 CASE_SIGN_OP(I64, LoadMem32, "load32")
99 CASE_ALL_OP(StoreMem, "store")
100 CASE_INT_OP(StoreMem8, "store8")
101 CASE_INT_OP(StoreMem16, "store16")
102 CASE_I64_OP(StoreMem32, "store32")
103 CASE_OP(SetLocal, "set_local")
104 CASE_OP(GetLocal, "get_local")
105 CASE_OP(TeeLocal, "tee_local")
106 default:
107 UNREACHABLE();
108 return WasmOpcodes::OpcodeName(opcode);
109 }
110 }
111
112 bool IsValidFunctionName(const Vector<const char> &name) {
113 if (name.is_empty()) return false;
114 const char *special_chars = "_.+-*/\\^~=<>!?@#$%&|:'`";
115 for (char c : name) {
116 bool valid_char = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
117 (c >= 'A' && c <= 'Z') || strchr(special_chars, c);
118 if (!valid_char) return false;
119 }
120 return true;
121 }
122
123 } // namespace
124
125 void wasm::PrintSExpr(
126 const WasmModule *module, uint32_t func_index, std::ostream &os,
127 std::vector<std::tuple<uint32_t, int, int>> *offset_table) {
128 DCHECK_NOT_NULL(module);
129 DCHECK_GT(module->functions.size(), func_index);
130 const WasmFunction *fun = &module->functions[func_index];
131
132 AccountingAllocator allocator;
133 Zone zone(&allocator, ZONE_NAME);
134 int line_nr = 0;
135 int control_depth = 0;
136
137 // Print the function signature.
138 os << "func";
139 Vector<const char> fun_name(
140 reinterpret_cast<const char *>(module->module_start + fun->name_offset),
141 fun->name_length);
142 if (IsValidFunctionName(fun_name)) {
143 os << " $";
144 os.write(fun_name.start(), fun_name.length());
145 }
146 size_t param_count = fun->sig->parameter_count();
147 if (param_count) {
148 os << " (param";
149 for (size_t i = 0; i < param_count; ++i)
150 os << ' ' << WasmOpcodes::TypeName(fun->sig->GetParam(i));
151 os << ')';
152 }
153 size_t return_count = fun->sig->return_count();
154 if (return_count) {
155 os << " (result";
156 for (size_t i = 0; i < return_count; ++i)
157 os << ' ' << WasmOpcodes::TypeName(fun->sig->GetReturn(i));
158 os << ')';
159 }
160 os << "\n";
161 ++line_nr;
162
163 // Print the local declarations.
164 AstLocalDecls decls(&zone);
165 const byte *code_start = module->module_start + fun->code_start_offset;
166 const byte *code_end = module->module_start + fun->code_end_offset;
167 BytecodeIterator i(code_start, code_end, &decls);
168 DCHECK_LT(code_start, i.pc());
169 if (!decls.local_types.empty()) {
170 os << "(local";
171 for (auto p : decls.local_types) {
172 for (unsigned i = 0; i < p.second; ++i)
173 os << ' ' << WasmOpcodes::TypeName(p.first);
174 }
175 os << ")\n";
176 os << std::endl;
177 ++line_nr;
178 }
179
180 for (; i.has_next(); i.next()) {
181 WasmOpcode opcode = i.current();
182 if (opcode == kExprElse || opcode == kExprEnd) --control_depth;
183
184 DCHECK_LE(0, control_depth);
185 int num_whitespaces = control_depth < 32 ? 2 * control_depth : 64;
rossberg 2016/11/21 15:03:50 Maybe turn the 32 into a constant.
Clemens Hammacher 2016/11/21 17:48:40 Done.
186 if (offset_table) {
187 offset_table->push_back(
188 std::make_tuple(i.pc_offset(), line_nr, num_whitespaces));
189 }
190
191 // 64 whitespaces
192 const char *padding =
193 " ";
194 os.write(padding, num_whitespaces);
195
196 switch (opcode) {
197 case kExprLoop:
198 case kExprIf:
199 case kExprBlock:
200 case kExprTry: {
201 BlockTypeOperand operand(&i, i.pc());
202 os << GetOpName(opcode);
203 for (unsigned i = 0; i < operand.arity; i++) {
204 os << " " << WasmOpcodes::TypeName(operand.read_entry(i));
205 }
206 control_depth++;
207 break;
208 }
209 case kExprBr:
210 case kExprBrIf: {
211 BreakDepthOperand operand(&i, i.pc());
212 os << "br" << (opcode == kExprBr ? "" : "_if") << " " << operand.depth;
rossberg 2016/11/21 15:03:51 Why not use GetOpName here?
Clemens Hammacher 2016/11/21 17:48:40 Yeah, it's just two alternatives, so I thought inl
213 break;
214 }
215 case kExprElse:
216 os << "else";
217 control_depth++;
218 break;
219 case kExprEnd:
220 os << "end";
221 break;
222 case kExprBrTable: {
223 BranchTableOperand operand(&i, i.pc());
224 os << "br_table";
225 for (unsigned op = 0, num_ops = operand.table_count; op < num_ops; ++op)
226 os << ' ' << operand.read_entry(&i, op);
227 break;
228 }
229 case kExprCallIndirect: {
230 CallIndirectOperand operand(&i, i.pc());
231 DCHECK_EQ(0U, operand.table_index);
232 os << "call_indirect " << operand.index;
233 break;
234 }
235 case kExprCallFunction: {
236 CallFunctionOperand operand(&i, i.pc());
237 os << "call " << operand.index;
238 break;
239 }
240 case kExprGetLocal:
241 case kExprSetLocal:
242 case kExprTeeLocal:
243 case kExprCatch: {
244 LocalIndexOperand operand(&i, i.pc());
245 os << GetOpName(opcode) << ' ' << operand.index;
246 break;
247 }
248 case kExprGetGlobal:
249 case kExprSetGlobal: {
250 GlobalIndexOperand operand(&i, i.pc());
251 os << (opcode == kExprGetLocal ? 'g' : 's') << "et_global "
rossberg 2016/11/21 15:03:51 GetOpName?
Clemens Hammacher 2016/11/21 17:48:40 Same.
252 << operand.index;
253 break;
254 }
255 #define CASE_CONST(type, str) \
256 case kExpr##type##Const: { \
257 Imm##type##Operand operand(&i, i.pc()); \
258 os << #str ".const " << operand.value; \
259 break; \
260 }
261 CASE_CONST(I8, i8)
262 CASE_CONST(I32, i32)
263 CASE_CONST(I64, i64)
264 CASE_CONST(F32, f32)
265 CASE_CONST(F64, f64)
266
267 #define CASE_OPCODE(opcode, _, __) case kExpr##opcode:
268 FOREACH_SIMPLE_OPCODE(CASE_OPCODE)
rossberg 2016/11/21 15:03:51 Nit: indent less?
Clemens Hammacher 2016/11/21 17:48:40 This is clang-format messing it up. I tried to pla
rossberg 2016/11/22 11:51:58 clang-format, making your code horrible since 2015
269 case kExprUnreachable:
270 case kExprNop:
271 case kExprReturn:
272 case kExprMemorySize:
273 case kExprGrowMemory:
274 case kExprDrop:
275 case kExprThrow:
276 os << GetOpName(opcode);
277 break;
278
279 FOREACH_LOAD_MEM_OPCODE(CASE_OPCODE)
rossberg 2016/11/21 15:03:51 Nit: indent less?
Clemens Hammacher 2016/11/21 17:48:40 Same.
280 FOREACH_STORE_MEM_OPCODE(CASE_OPCODE) {
281 MemoryAccessOperand operand(&i, i.pc(), kMaxUInt32);
282 os << GetOpName(opcode) << " offset=" << operand.offset
283 << " align=" << (1ULL << operand.alignment);
284 break;
285 }
286 default:
287 // Better print anything than failing.
rossberg 2016/11/21 15:03:51 Better fail than introducing silent bugs
Clemens Hammacher 2016/11/21 17:48:40 Hm, this requires us to also handle the opcodes wh
288 os << WasmOpcodes::OpcodeName(opcode);
289 break;
290 }
291 os << std::endl;
292 ++line_nr;
293 }
294 DCHECK_EQ(0, control_depth);
295 DCHECK(i.ok());
296 }
OLDNEW
« src/wasm/s-expr.h ('K') | « src/wasm/s-expr.h ('k') | src/wasm/wasm-module.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698