1 // Copyright 2015 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/signature.h"
6
7 #include "src/base/platform/elapsed-timer.h"
8 #include "src/compiler/wasm-compiler.h"
9 #include "src/flags.h"
10 #include "src/handles.h"
11 #include "src/objects-inl.h"
12 #include "src/ostreams.h"
13 #include "src/wasm/decoder.h"
14 #include "src/wasm/function-body-decoder-impl.h"
15 #include "src/wasm/function-body-decoder.h"
16 #include "src/wasm/wasm-limits.h"
17 #include "src/wasm/wasm-linkage.h"
18 #include "src/wasm/wasm-module.h"
19 #include "src/wasm/wasm-opcodes.h"
20
21 namespace v8 {
22 namespace internal {
23 namespace wasm {
24
25 namespace {
26
27 // An SsaEnv environment carries the current local variable renaming
28 // as well as the current effect and control dependency in the TF graph.
29 // It maintains a control state that tracks whether the environment
30 // is reachable, has reached a control end, or has been merged.
31 struct SsaEnv {
32 enum State { kControlEnd, kUnreachable, kReached, kMerged };
33
34 State state;
35 TFNode* control;
36 TFNode* effect;
37 compiler::WasmInstanceCacheNodes instance_cache;
38 TFNode** locals;
39
gov8::internal::wasm::__anonb954c62d0111::SsaEnv40 bool go() { return state >= kReached; }
Killv8::internal::wasm::__anonb954c62d0111::SsaEnv41 void Kill(State new_state = kControlEnd) {
42 state = new_state;
43 locals = nullptr;
44 control = nullptr;
45 effect = nullptr;
46 instance_cache = {};
47 }
SetNotMergedv8::internal::wasm::__anonb954c62d0111::SsaEnv48 void SetNotMerged() {
49 if (state == kMerged) state = kReached;
50 }
51 };
52
53 #define BUILD(func, ...) \
54 ([&] { \
55 DCHECK(ssa_env_->go()); \
56 DCHECK(decoder->ok()); \
57 return CheckForException(decoder, builder_->func(__VA_ARGS__)); \
58 })()
59
60 constexpr uint32_t kNullCatch = static_cast<uint32_t>(-1);
61
62 class WasmGraphBuildingInterface {
63 public:
64 static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
65 using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>;
66
67 struct Value : public ValueWithNamedConstructors<Value> {
68 TFNode* node;
69 };
70
71 struct TryInfo : public ZoneObject {
72 SsaEnv* catch_env;
73 TFNode* exception = nullptr;
74
TryInfov8::internal::wasm::__anonb954c62d0111::WasmGraphBuildingInterface::TryInfo75 explicit TryInfo(SsaEnv* c) : catch_env(c) {}
76 };
77
78 struct Control : public ControlWithNamedConstructors<Control, Value> {
79 SsaEnv* end_env; // end environment for the construct.
80 SsaEnv* false_env; // false environment (only for if).
81 TryInfo* try_info; // information used for compiling try statements.
82 int32_t previous_catch; // previous Control (on the stack) with a catch.
83 };
84
WasmGraphBuildingInterface(TFBuilder * builder)85 explicit WasmGraphBuildingInterface(TFBuilder* builder) : builder_(builder) {}
86
StartFunction(FullDecoder * decoder)87 void StartFunction(FullDecoder* decoder) {
88 SsaEnv* ssa_env =
89 reinterpret_cast<SsaEnv*>(decoder->zone()->New(sizeof(SsaEnv)));
90 uint32_t num_locals = decoder->NumLocals();
91 uint32_t env_count = num_locals;
92 size_t size = sizeof(TFNode*) * env_count;
93 ssa_env->state = SsaEnv::kReached;
94 ssa_env->locals =
95 size > 0 ? reinterpret_cast<TFNode**>(decoder->zone()->New(size))
96 : nullptr;
97
98 // The first '+ 1' is needed by TF Start node, the second '+ 1' is for the
99 // instance parameter.
100 TFNode* start = builder_->Start(
101 static_cast<int>(decoder->sig_->parameter_count() + 1 + 1));
102 // Initialize the instance parameter (index 0).
103 builder_->set_instance_node(builder_->Param(kWasmInstanceParameterIndex));
104 // Initialize local variables. Parameters are shifted by 1 because of the
105 // the instance parameter.
106 uint32_t index = 0;
107 for (; index < decoder->sig_->parameter_count(); ++index) {
108 ssa_env->locals[index] = builder_->Param(index + 1);
109 }
110 while (index < num_locals) {
111 ValueType type = decoder->GetLocalType(index);
112 TFNode* node = DefaultValue(type);
113 while (index < num_locals && decoder->GetLocalType(index) == type) {
114 // Do a whole run of like-typed locals at a time.
115 ssa_env->locals[index++] = node;
116 }
117 }
118 ssa_env->effect = start;
119 ssa_env->control = start;
120 // Initialize effect and control before loading the context.
121 builder_->set_effect_ptr(&ssa_env->effect);
122 builder_->set_control_ptr(&ssa_env->control);
123 LoadContextIntoSsa(ssa_env);
124 SetEnv(ssa_env);
125 }
126
127 // Reload the instance cache entries into the Ssa Environment.
LoadContextIntoSsa(SsaEnv * ssa_env)128 void LoadContextIntoSsa(SsaEnv* ssa_env) {
129 if (!ssa_env || !ssa_env->go()) return;
130 builder_->InitInstanceCache(&ssa_env->instance_cache);
131 }
132
StartFunctionBody(FullDecoder * decoder,Control * block)133 void StartFunctionBody(FullDecoder* decoder, Control* block) {
134 SsaEnv* break_env = ssa_env_;
135 SetEnv(Steal(decoder->zone(), break_env));
136 block->end_env = break_env;
137 }
138
FinishFunction(FullDecoder *)139 void FinishFunction(FullDecoder*) { builder_->PatchInStackCheckIfNeeded(); }
140
OnFirstError(FullDecoder *)141 void OnFirstError(FullDecoder*) {}
142
NextInstruction(FullDecoder *,WasmOpcode)143 void NextInstruction(FullDecoder*, WasmOpcode) {}
144
Block(FullDecoder * decoder,Control * block)145 void Block(FullDecoder* decoder, Control* block) {
146 // The break environment is the outer environment.
147 block->end_env = ssa_env_;
148 SetEnv(Steal(decoder->zone(), ssa_env_));
149 }
150
Loop(FullDecoder * decoder,Control * block)151 void Loop(FullDecoder* decoder, Control* block) {
152 SsaEnv* finish_try_env = Steal(decoder->zone(), ssa_env_);
153 block->end_env = finish_try_env;
154 // The continue environment is the inner environment.
155 SetEnv(PrepareForLoop(decoder, finish_try_env));
156 ssa_env_->SetNotMerged();
157 if (!decoder->ok()) return;
158 // Wrap input merge into phis.
159 for (unsigned i = 0; i < block->start_merge.arity; ++i) {
160 Value& val = block->start_merge[i];
161 val.node = builder_->Phi(val.type, 1, &val.node, block->end_env->control);
162 }
163 }
164
Try(FullDecoder * decoder,Control * block)165 void Try(FullDecoder* decoder, Control* block) {
166 SsaEnv* outer_env = ssa_env_;
167 SsaEnv* catch_env = Split(decoder, outer_env);
168 // Mark catch environment as unreachable, since only accessable
169 // through catch unwinding (i.e. landing pads).
170 catch_env->state = SsaEnv::kUnreachable;
171 SsaEnv* try_env = Steal(decoder->zone(), outer_env);
172 SetEnv(try_env);
173 TryInfo* try_info = new (decoder->zone()) TryInfo(catch_env);
174 block->end_env = outer_env;
175 block->try_info = try_info;
176 block->previous_catch = current_catch_;
177 current_catch_ = static_cast<int32_t>(decoder->control_depth() - 1);
178 }
179
If(FullDecoder * decoder,const Value & cond,Control * if_block)180 void If(FullDecoder* decoder, const Value& cond, Control* if_block) {
181 TFNode* if_true = nullptr;
182 TFNode* if_false = nullptr;
183 if (ssa_env_->go()) BUILD(BranchNoHint, cond.node, &if_true, &if_false);
184 SsaEnv* end_env = ssa_env_;
185 SsaEnv* false_env = Split(decoder, ssa_env_);
186 false_env->control = if_false;
187 SsaEnv* true_env = Steal(decoder->zone(), ssa_env_);
188 true_env->control = if_true;
189 if_block->end_env = end_env;
190 if_block->false_env = false_env;
191 SetEnv(true_env);
192 }
193
FallThruTo(FullDecoder * decoder,Control * c)194 void FallThruTo(FullDecoder* decoder, Control* c) {
195 DCHECK(!c->is_loop());
196 MergeValuesInto(decoder, c, &c->end_merge);
197 }
198
PopControl(FullDecoder * decoder,Control * block)199 void PopControl(FullDecoder* decoder, Control* block) {
200 if (!block->is_loop()) SetEnv(block->end_env);
201 }
202
EndControl(FullDecoder * decoder,Control * block)203 void EndControl(FullDecoder* decoder, Control* block) { ssa_env_->Kill(); }
204
UnOp(FullDecoder * decoder,WasmOpcode opcode,FunctionSig * sig,const Value & value,Value * result)205 void UnOp(FullDecoder* decoder, WasmOpcode opcode, FunctionSig* sig,
206 const Value& value, Value* result) {
207 result->node = BUILD(Unop, opcode, value.node, decoder->position());
208 }
209
BinOp(FullDecoder * decoder,WasmOpcode opcode,FunctionSig * sig,const Value & lhs,const Value & rhs,Value * result)210 void BinOp(FullDecoder* decoder, WasmOpcode opcode, FunctionSig* sig,
211 const Value& lhs, const Value& rhs, Value* result) {
212 auto node = BUILD(Binop, opcode, lhs.node, rhs.node, decoder->position());
213 if (result) result->node = node;
214 }
215
I32Const(FullDecoder * decoder,Value * result,int32_t value)216 void I32Const(FullDecoder* decoder, Value* result, int32_t value) {
217 result->node = builder_->Int32Constant(value);
218 }
219
I64Const(FullDecoder * decoder,Value * result,int64_t value)220 void I64Const(FullDecoder* decoder, Value* result, int64_t value) {
221 result->node = builder_->Int64Constant(value);
222 }
223
F32Const(FullDecoder * decoder,Value * result,float value)224 void F32Const(FullDecoder* decoder, Value* result, float value) {
225 result->node = builder_->Float32Constant(value);
226 }
227
F64Const(FullDecoder * decoder,Value * result,double value)228 void F64Const(FullDecoder* decoder, Value* result, double value) {
229 result->node = builder_->Float64Constant(value);
230 }
231
RefNull(FullDecoder * decoder,Value * result)232 void RefNull(FullDecoder* decoder, Value* result) {
233 result->node = builder_->RefNull();
234 }
235
Drop(FullDecoder * decoder,const Value & value)236 void Drop(FullDecoder* decoder, const Value& value) {}
237
DoReturn(FullDecoder * decoder,Vector<Value> values,bool implicit)238 void DoReturn(FullDecoder* decoder, Vector<Value> values, bool implicit) {
239 if (implicit) {
240 DCHECK_EQ(1, decoder->control_depth());
241 SetEnv(decoder->control_at(0)->end_env);
242 }
243 size_t num_values = values.size();
244 TFNode** buffer = GetNodes(values);
245 for (size_t i = 0; i < num_values; ++i) {
246 buffer[i] = values[i].node;
247 }
248 BUILD(Return, static_cast<unsigned>(values.size()), buffer);
249 }
250
GetLocal(FullDecoder * decoder,Value * result,const LocalIndexImmediate<validate> & imm)251 void GetLocal(FullDecoder* decoder, Value* result,
252 const LocalIndexImmediate<validate>& imm) {
253 if (!ssa_env_->locals) return; // unreachable
254 result->node = ssa_env_->locals[imm.index];
255 }
256
SetLocal(FullDecoder * decoder,const Value & value,const LocalIndexImmediate<validate> & imm)257 void SetLocal(FullDecoder* decoder, const Value& value,
258 const LocalIndexImmediate<validate>& imm) {
259 if (!ssa_env_->locals) return; // unreachable
260 ssa_env_->locals[imm.index] = value.node;
261 }
262
TeeLocal(FullDecoder * decoder,const Value & value,Value * result,const LocalIndexImmediate<validate> & imm)263 void TeeLocal(FullDecoder* decoder, const Value& value, Value* result,
264 const LocalIndexImmediate<validate>& imm) {
265 result->node = value.node;
266 if (!ssa_env_->locals) return; // unreachable
267 ssa_env_->locals[imm.index] = value.node;
268 }
269
GetGlobal(FullDecoder * decoder,Value * result,const GlobalIndexImmediate<validate> & imm)270 void GetGlobal(FullDecoder* decoder, Value* result,
271 const GlobalIndexImmediate<validate>& imm) {
272 result->node = BUILD(GetGlobal, imm.index);
273 }
274
SetGlobal(FullDecoder * decoder,const Value & value,const GlobalIndexImmediate<validate> & imm)275 void SetGlobal(FullDecoder* decoder, const Value& value,
276 const GlobalIndexImmediate<validate>& imm) {
277 BUILD(SetGlobal, imm.index, value.node);
278 }
279
Unreachable(FullDecoder * decoder)280 void Unreachable(FullDecoder* decoder) {
281 BUILD(Unreachable, decoder->position());
282 }
283
Select(FullDecoder * decoder,const Value & cond,const Value & fval,const Value & tval,Value * result)284 void Select(FullDecoder* decoder, const Value& cond, const Value& fval,
285 const Value& tval, Value* result) {
286 TFNode* controls[2];
287 BUILD(BranchNoHint, cond.node, &controls[0], &controls[1]);
288 TFNode* merge = BUILD(Merge, 2, controls);
289 TFNode* vals[2] = {tval.node, fval.node};
290 TFNode* phi = BUILD(Phi, tval.type, 2, vals, merge);
291 result->node = phi;
292 ssa_env_->control = merge;
293 }
294
Br(FullDecoder * decoder,Control * target)295 void Br(FullDecoder* decoder, Control* target) {
296 MergeValuesInto(decoder, target, target->br_merge());
297 }
298
BrIf(FullDecoder * decoder,const Value & cond,Control * target)299 void BrIf(FullDecoder* decoder, const Value& cond, Control* target) {
300 SsaEnv* fenv = ssa_env_;
301 SsaEnv* tenv = Split(decoder, fenv);
302 fenv->SetNotMerged();
303 BUILD(BranchNoHint, cond.node, &tenv->control, &fenv->control);
304 ssa_env_ = tenv;
305 Br(decoder, target);
306 ssa_env_ = fenv;
307 }
308
BrTable(FullDecoder * decoder,const BranchTableImmediate<validate> & imm,const Value & key)309 void BrTable(FullDecoder* decoder, const BranchTableImmediate<validate>& imm,
310 const Value& key) {
311 if (imm.table_count == 0) {
312 // Only a default target. Do the equivalent of br.
313 uint32_t target = BranchTableIterator<validate>(decoder, imm).next();
314 Br(decoder, decoder->control_at(target));
315 return;
316 }
317
318 SsaEnv* break_env = ssa_env_;
319 // Build branches to the various blocks based on the table.
320 TFNode* sw = BUILD(Switch, imm.table_count + 1, key.node);
321
322 SsaEnv* copy = Steal(decoder->zone(), break_env);
323 ssa_env_ = copy;
324 BranchTableIterator<validate> iterator(decoder, imm);
325 while (iterator.has_next()) {
326 uint32_t i = iterator.cur_index();
327 uint32_t target = iterator.next();
328 ssa_env_ = Split(decoder, copy);
329 ssa_env_->control =
330 (i == imm.table_count) ? BUILD(IfDefault, sw) : BUILD(IfValue, i, sw);
331 Br(decoder, decoder->control_at(target));
332 }
333 DCHECK(decoder->ok());
334 ssa_env_ = break_env;
335 }
336
Else(FullDecoder * decoder,Control * if_block)337 void Else(FullDecoder* decoder, Control* if_block) {
338 SetEnv(if_block->false_env);
339 }
340
LoadMem(FullDecoder * decoder,LoadType type,const MemoryAccessImmediate<validate> & imm,const Value & index,Value * result)341 void LoadMem(FullDecoder* decoder, LoadType type,
342 const MemoryAccessImmediate<validate>& imm, const Value& index,
343 Value* result) {
344 result->node =
345 BUILD(LoadMem, type.value_type(), type.mem_type(), index.node,
346 imm.offset, imm.alignment, decoder->position());
347 }
348
StoreMem(FullDecoder * decoder,StoreType type,const MemoryAccessImmediate<validate> & imm,const Value & index,const Value & value)349 void StoreMem(FullDecoder* decoder, StoreType type,
350 const MemoryAccessImmediate<validate>& imm, const Value& index,
351 const Value& value) {
352 BUILD(StoreMem, type.mem_rep(), index.node, imm.offset, imm.alignment,
353 value.node, decoder->position(), type.value_type());
354 }
355
CurrentMemoryPages(FullDecoder * decoder,Value * result)356 void CurrentMemoryPages(FullDecoder* decoder, Value* result) {
357 result->node = BUILD(CurrentMemoryPages);
358 }
359
GrowMemory(FullDecoder * decoder,const Value & value,Value * result)360 void GrowMemory(FullDecoder* decoder, const Value& value, Value* result) {
361 result->node = BUILD(GrowMemory, value.node);
362 // Always reload the instance cache after growing memory.
363 LoadContextIntoSsa(ssa_env_);
364 }
365
CallDirect(FullDecoder * decoder,const CallFunctionImmediate<validate> & imm,const Value args[],Value returns[])366 void CallDirect(FullDecoder* decoder,
367 const CallFunctionImmediate<validate>& imm,
368 const Value args[], Value returns[]) {
369 DoCall(decoder, nullptr, imm.sig, imm.index, args, returns);
370 }
371
CallIndirect(FullDecoder * decoder,const Value & index,const CallIndirectImmediate<validate> & imm,const Value args[],Value returns[])372 void CallIndirect(FullDecoder* decoder, const Value& index,
373 const CallIndirectImmediate<validate>& imm,
374 const Value args[], Value returns[]) {
375 DoCall(decoder, index.node, imm.sig, imm.sig_index, args, returns);
376 }
377
SimdOp(FullDecoder * decoder,WasmOpcode opcode,Vector<Value> args,Value * result)378 void SimdOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
379 Value* result) {
380 TFNode** inputs = GetNodes(args);
381 TFNode* node = BUILD(SimdOp, opcode, inputs);
382 if (result) result->node = node;
383 }
384
SimdLaneOp(FullDecoder * decoder,WasmOpcode opcode,const SimdLaneImmediate<validate> imm,Vector<Value> inputs,Value * result)385 void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode,
386 const SimdLaneImmediate<validate> imm, Vector<Value> inputs,
387 Value* result) {
388 TFNode** nodes = GetNodes(inputs);
389 result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes);
390 }
391
SimdShiftOp(FullDecoder * decoder,WasmOpcode opcode,const SimdShiftImmediate<validate> imm,const Value & input,Value * result)392 void SimdShiftOp(FullDecoder* decoder, WasmOpcode opcode,
393 const SimdShiftImmediate<validate> imm, const Value& input,
394 Value* result) {
395 TFNode* inputs[] = {input.node};
396 result->node = BUILD(SimdShiftOp, opcode, imm.shift, inputs);
397 }
398
Simd8x16ShuffleOp(FullDecoder * decoder,const Simd8x16ShuffleImmediate<validate> & imm,const Value & input0,const Value & input1,Value * result)399 void Simd8x16ShuffleOp(FullDecoder* decoder,
400 const Simd8x16ShuffleImmediate<validate>& imm,
401 const Value& input0, const Value& input1,
402 Value* result) {
403 TFNode* input_nodes[] = {input0.node, input1.node};
404 result->node = BUILD(Simd8x16ShuffleOp, imm.shuffle, input_nodes);
405 }
406
GetExceptionTag(FullDecoder * decoder,const ExceptionIndexImmediate<validate> & imm)407 TFNode* GetExceptionTag(FullDecoder* decoder,
408 const ExceptionIndexImmediate<validate>& imm) {
409 // TODO(kschimpf): Need to get runtime exception tag values. This
410 // code only handles non-imported/exported exceptions.
411 return BUILD(Int32Constant, imm.index);
412 }
413
Throw(FullDecoder * decoder,const ExceptionIndexImmediate<validate> & imm,Control * block,const Vector<Value> & value_args)414 void Throw(FullDecoder* decoder, const ExceptionIndexImmediate<validate>& imm,
415 Control* block, const Vector<Value>& value_args) {
416 int count = value_args.length();
417 ZoneVector<TFNode*> args(count, decoder->zone());
418 for (int i = 0; i < count; ++i) {
419 args[i] = value_args[i].node;
420 }
421 BUILD(Throw, imm.index, imm.exception, vec2vec(args));
422 Unreachable(decoder);
423 EndControl(decoder, block);
424 }
425
CatchException(FullDecoder * decoder,const ExceptionIndexImmediate<validate> & imm,Control * block,Vector<Value> values)426 void CatchException(FullDecoder* decoder,
427 const ExceptionIndexImmediate<validate>& imm,
428 Control* block, Vector<Value> values) {
429 DCHECK(block->is_try_catch());
430 current_catch_ = block->previous_catch;
431 SsaEnv* catch_env = block->try_info->catch_env;
432 SetEnv(catch_env);
433
434 TFNode* compare_i32 = nullptr;
435 if (block->try_info->exception == nullptr) {
436 // Catch not applicable, no possible throws in the try
437 // block. Create dummy code so that body of catch still
438 // compiles. Note: This only happens because the current
439 // implementation only builds a landing pad if some node in the
440 // try block can (possibly) throw.
441 //
442 // TODO(kschimpf): Always generate a landing pad for a try block.
443 compare_i32 = BUILD(Int32Constant, 0);
444 } else {
445 // Get the exception and see if wanted exception.
446 TFNode* caught_tag = BUILD(GetExceptionRuntimeId);
447 TFNode* exception_tag = BUILD(ConvertExceptionTagToRuntimeId, imm.index);
448 compare_i32 = BUILD(Binop, kExprI32Eq, caught_tag, exception_tag);
449 }
450
451 TFNode* if_catch = nullptr;
452 TFNode* if_no_catch = nullptr;
453 BUILD(BranchNoHint, compare_i32, &if_catch, &if_no_catch);
454
455 SsaEnv* if_no_catch_env = Split(decoder, ssa_env_);
456 if_no_catch_env->control = if_no_catch;
457 SsaEnv* if_catch_env = Steal(decoder->zone(), ssa_env_);
458 if_catch_env->control = if_catch;
459
460 // TODO(kschimpf): Generalize to allow more catches. Will force
461 // moving no_catch code to END opcode.
462 SetEnv(if_no_catch_env);
463 BUILD(Rethrow);
464 Unreachable(decoder);
465 EndControl(decoder, block);
466
467 SetEnv(if_catch_env);
468
469 if (block->try_info->exception == nullptr) {
470 // No caught value, make up filler nodes so that catch block still
471 // compiles.
472 for (Value& value : values) {
473 value.node = DefaultValue(value.type);
474 }
475 } else {
476 // TODO(kschimpf): Can't use BUILD() here, GetExceptionValues() returns
477 // TFNode** rather than TFNode*. Fix to add landing pads.
478 TFNode** caught_values = builder_->GetExceptionValues(imm.exception);
479 for (size_t i = 0, e = values.size(); i < e; ++i) {
480 values[i].node = caught_values[i];
481 }
482 }
483 }
484
AtomicOp(FullDecoder * decoder,WasmOpcode opcode,Vector<Value> args,const MemoryAccessImmediate<validate> & imm,Value * result)485 void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
486 const MemoryAccessImmediate<validate>& imm, Value* result) {
487 TFNode** inputs = GetNodes(args);
488 TFNode* node = BUILD(AtomicOp, opcode, inputs, imm.alignment, imm.offset,
489 decoder->position());
490 if (result) result->node = node;
491 }
492
493 private:
494 SsaEnv* ssa_env_;
495 TFBuilder* builder_;
496 uint32_t current_catch_ = kNullCatch;
497
current_try_info(FullDecoder * decoder)498 TryInfo* current_try_info(FullDecoder* decoder) {
499 return decoder->control_at(decoder->control_depth() - 1 - current_catch_)
500 ->try_info;
501 }
502
GetNodes(Value * values,size_t count)503 TFNode** GetNodes(Value* values, size_t count) {
504 TFNode** nodes = builder_->Buffer(count);
505 for (size_t i = 0; i < count; ++i) {
506 nodes[i] = values[i].node;
507 }
508 return nodes;
509 }
510
GetNodes(Vector<Value> values)511 TFNode** GetNodes(Vector<Value> values) {
512 return GetNodes(values.start(), values.size());
513 }
514
SetEnv(SsaEnv * env)515 void SetEnv(SsaEnv* env) {
516 #if DEBUG
517 if (FLAG_trace_wasm_decoder) {
518 char state = 'X';
519 if (env) {
520 switch (env->state) {
521 case SsaEnv::kReached:
522 state = 'R';
523 break;
524 case SsaEnv::kUnreachable:
525 state = 'U';
526 break;
527 case SsaEnv::kMerged:
528 state = 'M';
529 break;
530 case SsaEnv::kControlEnd:
531 state = 'E';
532 break;
533 }
534 }
535 PrintF("{set_env = %p, state = %c", static_cast<void*>(env), state);
536 if (env && env->control) {
537 PrintF(", control = ");
538 compiler::WasmGraphBuilder::PrintDebugName(env->control);
539 }
540 PrintF("}\n");
541 }
542 #endif
543 ssa_env_ = env;
544 // TODO(wasm): combine the control and effect pointers with instance cache.
545 builder_->set_control_ptr(&env->control);
546 builder_->set_effect_ptr(&env->effect);
547 builder_->set_instance_cache(&env->instance_cache);
548 }
549
CheckForException(FullDecoder * decoder,TFNode * node)550 TFNode* CheckForException(FullDecoder* decoder, TFNode* node) {
551 if (node == nullptr) return nullptr;
552
553 const bool inside_try_scope = current_catch_ != kNullCatch;
554
555 if (!inside_try_scope) return node;
556
557 TFNode* if_success = nullptr;
558 TFNode* if_exception = nullptr;
559 if (!builder_->ThrowsException(node, &if_success, &if_exception)) {
560 return node;
561 }
562
563 SsaEnv* success_env = Steal(decoder->zone(), ssa_env_);
564 success_env->control = if_success;
565
566 SsaEnv* exception_env = Split(decoder, success_env);
567 exception_env->control = if_exception;
568 TryInfo* try_info = current_try_info(decoder);
569 Goto(decoder, exception_env, try_info->catch_env);
570 TFNode* exception = try_info->exception;
571 if (exception == nullptr) {
572 DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state);
573 try_info->exception = if_exception;
574 } else {
575 DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state);
576 try_info->exception = builder_->CreateOrMergeIntoPhi(
577 MachineRepresentation::kWord32, try_info->catch_env->control,
578 try_info->exception, if_exception);
579 }
580
581 SetEnv(success_env);
582 return node;
583 }
584
DefaultValue(ValueType type)585 TFNode* DefaultValue(ValueType type) {
586 switch (type) {
587 case kWasmI32:
588 return builder_->Int32Constant(0);
589 case kWasmI64:
590 return builder_->Int64Constant(0);
591 case kWasmF32:
592 return builder_->Float32Constant(0);
593 case kWasmF64:
594 return builder_->Float64Constant(0);
595 case kWasmS128:
596 return builder_->S128Zero();
597 default:
598 UNREACHABLE();
599 }
600 }
601
MergeValuesInto(FullDecoder * decoder,Control * c,Merge<Value> * merge)602 void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge) {
603 DCHECK(merge == &c->start_merge || merge == &c->end_merge);
604 if (!ssa_env_->go()) return;
605
606 SsaEnv* target = c->end_env;
607 const bool first = target->state == SsaEnv::kUnreachable;
608 Goto(decoder, ssa_env_, target);
609
610 uint32_t avail =
611 decoder->stack_size() - decoder->control_at(0)->stack_depth;
612 uint32_t start = avail >= merge->arity ? 0 : merge->arity - avail;
613 for (uint32_t i = start; i < merge->arity; ++i) {
614 auto& val = decoder->GetMergeValueFromStack(c, merge, i);
615 auto& old = (*merge)[i];
616 DCHECK_NOT_NULL(val.node);
617 DCHECK(val.type == old.type || val.type == kWasmVar);
618 old.node = first ? val.node
619 : builder_->CreateOrMergeIntoPhi(
620 ValueTypes::MachineRepresentationFor(old.type),
621 target->control, old.node, val.node);
622 }
623 }
624
Goto(FullDecoder * decoder,SsaEnv * from,SsaEnv * to)625 void Goto(FullDecoder* decoder, SsaEnv* from, SsaEnv* to) {
626 DCHECK_NOT_NULL(to);
627 if (!from->go()) return;
628 switch (to->state) {
629 case SsaEnv::kUnreachable: { // Overwrite destination.
630 to->state = SsaEnv::kReached;
631 to->locals = from->locals;
632 to->control = from->control;
633 to->effect = from->effect;
634 to->instance_cache = from->instance_cache;
635 break;
636 }
637 case SsaEnv::kReached: { // Create a new merge.
638 to->state = SsaEnv::kMerged;
639 // Merge control.
640 TFNode* controls[] = {to->control, from->control};
641 TFNode* merge = builder_->Merge(2, controls);
642 to->control = merge;
643 // Merge effects.
644 if (from->effect != to->effect) {
645 TFNode* effects[] = {to->effect, from->effect, merge};
646 to->effect = builder_->EffectPhi(2, effects, merge);
647 }
648 // Merge SSA values.
649 for (int i = decoder->NumLocals() - 1; i >= 0; i--) {
650 TFNode* a = to->locals[i];
651 TFNode* b = from->locals[i];
652 if (a != b) {
653 TFNode* vals[] = {a, b};
654 to->locals[i] =
655 builder_->Phi(decoder->GetLocalType(i), 2, vals, merge);
656 }
657 }
658 // Start a new merge from the instance cache.
659 builder_->NewInstanceCacheMerge(&to->instance_cache,
660 &from->instance_cache, merge);
661 break;
662 }
663 case SsaEnv::kMerged: {
664 TFNode* merge = to->control;
665 // Extend the existing merge control node.
666 builder_->AppendToMerge(merge, from->control);
667 // Merge effects.
668 to->effect = builder_->CreateOrMergeIntoEffectPhi(merge, to->effect,
669 from->effect);
670 // Merge locals.
671 for (int i = decoder->NumLocals() - 1; i >= 0; i--) {
672 to->locals[i] = builder_->CreateOrMergeIntoPhi(
673 ValueTypes::MachineRepresentationFor(decoder->GetLocalType(i)),
674 merge, to->locals[i], from->locals[i]);
675 }
676 // Merge the instance caches.
677 builder_->MergeInstanceCacheInto(&to->instance_cache,
678 &from->instance_cache, merge);
679 break;
680 }
681 default:
682 UNREACHABLE();
683 }
684 return from->Kill();
685 }
686
PrepareForLoop(FullDecoder * decoder,SsaEnv * env)687 SsaEnv* PrepareForLoop(FullDecoder* decoder, SsaEnv* env) {
688 if (!env->go()) return Split(decoder, env);
689 env->state = SsaEnv::kMerged;
690
691 env->control = builder_->Loop(env->control);
692 env->effect = builder_->EffectPhi(1, &env->effect, env->control);
693 builder_->Terminate(env->effect, env->control);
694 // The '+ 1' here is to be able to set the instance cache as assigned.
695 BitVector* assigned = WasmDecoder<validate>::AnalyzeLoopAssignment(
696 decoder, decoder->pc(), decoder->total_locals() + 1, decoder->zone());
697 if (decoder->failed()) return env;
698 if (assigned != nullptr) {
699 // Only introduce phis for variables assigned in this loop.
700 int instance_cache_index = decoder->total_locals();
701 for (int i = decoder->NumLocals() - 1; i >= 0; i--) {
702 if (!assigned->Contains(i)) continue;
703 env->locals[i] = builder_->Phi(decoder->GetLocalType(i), 1,
704 &env->locals[i], env->control);
705 }
706 // Introduce phis for instance cache pointers if necessary.
707 if (assigned->Contains(instance_cache_index)) {
708 builder_->PrepareInstanceCacheForLoop(&env->instance_cache,
709 env->control);
710 }
711
712 SsaEnv* loop_body_env = Split(decoder, env);
713 builder_->StackCheck(decoder->position(), &(loop_body_env->effect),
714 &(loop_body_env->control));
715 return loop_body_env;
716 }
717
718 // Conservatively introduce phis for all local variables.
719 for (int i = decoder->NumLocals() - 1; i >= 0; i--) {
720 env->locals[i] = builder_->Phi(decoder->GetLocalType(i), 1,
721 &env->locals[i], env->control);
722 }
723
724 // Conservatively introduce phis for instance cache.
725 builder_->PrepareInstanceCacheForLoop(&env->instance_cache, env->control);
726
727 SsaEnv* loop_body_env = Split(decoder, env);
728 builder_->StackCheck(decoder->position(), &loop_body_env->effect,
729 &loop_body_env->control);
730 return loop_body_env;
731 }
732
733 // Create a complete copy of {from}.
Split(FullDecoder * decoder,SsaEnv * from)734 SsaEnv* Split(FullDecoder* decoder, SsaEnv* from) {
735 DCHECK_NOT_NULL(from);
736 SsaEnv* result =
737 reinterpret_cast<SsaEnv*>(decoder->zone()->New(sizeof(SsaEnv)));
738 size_t size = sizeof(TFNode*) * decoder->NumLocals();
739 result->control = from->control;
740 result->effect = from->effect;
741
742 if (from->go()) {
743 result->state = SsaEnv::kReached;
744 result->locals =
745 size > 0 ? reinterpret_cast<TFNode**>(decoder->zone()->New(size))
746 : nullptr;
747 memcpy(result->locals, from->locals, size);
748 result->instance_cache = from->instance_cache;
749 } else {
750 result->state = SsaEnv::kUnreachable;
751 result->locals = nullptr;
752 result->instance_cache = {};
753 }
754
755 return result;
756 }
757
758 // Create a copy of {from} that steals its state and leaves {from}
759 // unreachable.
Steal(Zone * zone,SsaEnv * from)760 SsaEnv* Steal(Zone* zone, SsaEnv* from) {
761 DCHECK_NOT_NULL(from);
762 if (!from->go()) return UnreachableEnv(zone);
763 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone->New(sizeof(SsaEnv)));
764 result->state = SsaEnv::kReached;
765 result->locals = from->locals;
766 result->control = from->control;
767 result->effect = from->effect;
768 result->instance_cache = from->instance_cache;
769 from->Kill(SsaEnv::kUnreachable);
770 return result;
771 }
772
773 // Create an unreachable environment.
UnreachableEnv(Zone * zone)774 SsaEnv* UnreachableEnv(Zone* zone) {
775 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone->New(sizeof(SsaEnv)));
776 result->state = SsaEnv::kUnreachable;
777 result->control = nullptr;
778 result->effect = nullptr;
779 result->locals = nullptr;
780 result->instance_cache = {};
781 return result;
782 }
783
DoCall(FullDecoder * decoder,TFNode * index_node,FunctionSig * sig,uint32_t index,const Value args[],Value returns[])784 void DoCall(FullDecoder* decoder, TFNode* index_node, FunctionSig* sig,
785 uint32_t index, const Value args[], Value returns[]) {
786 int param_count = static_cast<int>(sig->parameter_count());
787 TFNode** arg_nodes = builder_->Buffer(param_count + 1);
788 TFNode** return_nodes = nullptr;
789 arg_nodes[0] = index_node;
790 for (int i = 0; i < param_count; ++i) {
791 arg_nodes[i + 1] = args[i].node;
792 }
793 if (index_node) {
794 builder_->CallIndirect(index, arg_nodes, &return_nodes,
795 decoder->position());
796 } else {
797 builder_->CallDirect(index, arg_nodes, &return_nodes,
798 decoder->position());
799 }
800 int return_count = static_cast<int>(sig->return_count());
801 for (int i = 0; i < return_count; ++i) {
802 returns[i].node = return_nodes[i];
803 }
804 // The invoked function could have used grow_memory, so we need to
805 // reload mem_size and mem_start.
806 LoadContextIntoSsa(ssa_env_);
807 }
808 };
809
810 } // namespace
811
DecodeLocalDecls(const WasmFeatures & enabled,BodyLocalDecls * decls,const byte * start,const byte * end)812 bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
813 const byte* start, const byte* end) {
814 Decoder decoder(start, end);
815 if (WasmDecoder<Decoder::kValidate>::DecodeLocals(enabled, &decoder, nullptr,
816 &decls->type_list)) {
817 DCHECK(decoder.ok());
818 decls->encoded_size = decoder.pc_offset();
819 return true;
820 }
821 return false;
822 }
823
BytecodeIterator(const byte * start,const byte * end,BodyLocalDecls * decls)824 BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
825 BodyLocalDecls* decls)
826 : Decoder(start, end) {
827 if (decls != nullptr) {
828 if (DecodeLocalDecls(kAllWasmFeatures, decls, start, end)) {
829 pc_ += decls->encoded_size;
830 if (pc_ > end_) pc_ = end_;
831 }
832 }
833 }
834
VerifyWasmCode(AccountingAllocator * allocator,const WasmFeatures & enabled,const WasmModule * module,WasmFeatures * detected,FunctionBody & body)835 DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
836 const WasmFeatures& enabled,
837 const WasmModule* module, WasmFeatures* detected,
838 FunctionBody& body) {
839 Zone zone(allocator, ZONE_NAME);
840 WasmFullDecoder<Decoder::kValidate, EmptyInterface> decoder(
841 &zone, module, enabled, detected, body);
842 decoder.Decode();
843 return decoder.toResult(nullptr);
844 }
845
BuildTFGraph(AccountingAllocator * allocator,const WasmFeatures & enabled,const wasm::WasmModule * module,TFBuilder * builder,WasmFeatures * detected,FunctionBody & body,compiler::NodeOriginTable * node_origins)846 DecodeResult BuildTFGraph(AccountingAllocator* allocator,
847 const WasmFeatures& enabled,
848 const wasm::WasmModule* module, TFBuilder* builder,
849 WasmFeatures* detected, FunctionBody& body,
850 compiler::NodeOriginTable* node_origins) {
851 Zone zone(allocator, ZONE_NAME);
852 WasmFullDecoder<Decoder::kValidate, WasmGraphBuildingInterface> decoder(
853 &zone, module, enabled, detected, body, builder);
854 if (node_origins) {
855 builder->AddBytecodePositionDecorator(node_origins, &decoder);
856 }
857 decoder.Decode();
858 if (node_origins) {
859 builder->RemoveBytecodePositionDecorator();
860 }
861 return decoder.toResult(nullptr);
862 }
863
OpcodeLength(const byte * pc,const byte * end)864 unsigned OpcodeLength(const byte* pc, const byte* end) {
865 Decoder decoder(pc, end);
866 return WasmDecoder<Decoder::kNoValidate>::OpcodeLength(&decoder, pc);
867 }
868
StackEffect(const WasmModule * module,FunctionSig * sig,const byte * pc,const byte * end)869 std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
870 FunctionSig* sig, const byte* pc,
871 const byte* end) {
872 WasmFeatures unused_detected_features;
873 WasmDecoder<Decoder::kNoValidate> decoder(
874 module, kAllWasmFeatures, &unused_detected_features, sig, pc, end);
875 return decoder.StackEffect(pc);
876 }
877
PrintRawWasmCode(const byte * start,const byte * end)878 void PrintRawWasmCode(const byte* start, const byte* end) {
879 AccountingAllocator allocator;
880 PrintRawWasmCode(&allocator, FunctionBody{nullptr, 0, start, end}, nullptr,
881 kPrintLocals);
882 }
883
884 namespace {
RawOpcodeName(WasmOpcode opcode)885 const char* RawOpcodeName(WasmOpcode opcode) {
886 switch (opcode) {
887 #define DECLARE_NAME_CASE(name, opcode, sig) \
888 case kExpr##name: \
889 return "kExpr" #name;
890 FOREACH_OPCODE(DECLARE_NAME_CASE)
891 #undef DECLARE_NAME_CASE
892 default:
893 break;
894 }
895 return "Unknown";
896 }
897 } // namespace
898
PrintRawWasmCode(AccountingAllocator * allocator,const FunctionBody & body,const WasmModule * module,PrintLocals print_locals)899 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
900 const WasmModule* module, PrintLocals print_locals) {
901 StdoutStream os;
902 return PrintRawWasmCode(allocator, body, module, print_locals, os);
903 }
904
PrintRawWasmCode(AccountingAllocator * allocator,const FunctionBody & body,const WasmModule * module,PrintLocals print_locals,std::ostream & os,std::vector<int> * line_numbers)905 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
906 const WasmModule* module, PrintLocals print_locals,
907 std::ostream& os, std::vector<int>* line_numbers) {
908 Zone zone(allocator, ZONE_NAME);
909 WasmFeatures unused_detected_features;
910 WasmDecoder<Decoder::kNoValidate> decoder(module, kAllWasmFeatures,
911 &unused_detected_features, body.sig,
912 body.start, body.end);
913 int line_nr = 0;
914 constexpr int kNoByteCode = -1;
915
916 // Print the function signature.
917 if (body.sig) {
918 os << "// signature: " << *body.sig << std::endl;
919 if (line_numbers) line_numbers->push_back(kNoByteCode);
920 ++line_nr;
921 }
922
923 // Print the local declarations.
924 BodyLocalDecls decls(&zone);
925 BytecodeIterator i(body.start, body.end, &decls);
926 if (body.start != i.pc() && print_locals == kPrintLocals) {
927 os << "// locals: ";
928 if (!decls.type_list.empty()) {
929 ValueType type = decls.type_list[0];
930 uint32_t count = 0;
931 for (size_t pos = 0; pos < decls.type_list.size(); ++pos) {
932 if (decls.type_list[pos] == type) {
933 ++count;
934 } else {
935 os << " " << count << " " << ValueTypes::TypeName(type);
936 type = decls.type_list[pos];
937 count = 1;
938 }
939 }
940 }
941 os << std::endl;
942 if (line_numbers) line_numbers->push_back(kNoByteCode);
943 ++line_nr;
944
945 for (const byte* locals = body.start; locals < i.pc(); locals++) {
946 os << (locals == body.start ? "0x" : " 0x") << AsHex(*locals, 2) << ",";
947 }
948 os << std::endl;
949 if (line_numbers) line_numbers->push_back(kNoByteCode);
950 ++line_nr;
951 }
952
953 os << "// body: " << std::endl;
954 if (line_numbers) line_numbers->push_back(kNoByteCode);
955 ++line_nr;
956 unsigned control_depth = 0;
957 for (; i.has_next(); i.next()) {
958 unsigned length =
959 WasmDecoder<Decoder::kNoValidate>::OpcodeLength(&decoder, i.pc());
960
961 WasmOpcode opcode = i.current();
962 if (line_numbers) line_numbers->push_back(i.position());
963 if (opcode == kExprElse) control_depth--;
964
965 int num_whitespaces = control_depth < 32 ? 2 * control_depth : 64;
966
967 // 64 whitespaces
968 const char* padding =
969 " ";
970 os.write(padding, num_whitespaces);
971
972 os << RawOpcodeName(opcode) << ",";
973
974 if (opcode == kExprLoop || opcode == kExprIf || opcode == kExprBlock ||
975 opcode == kExprTry) {
976 DCHECK_EQ(2, length);
977
978 switch (i.pc()[1]) {
979 #define CASE_LOCAL_TYPE(local_name, type_name) \
980 case kLocal##local_name: \
981 os << " kWasm" #type_name ","; \
982 break;
983
984 CASE_LOCAL_TYPE(I32, I32)
985 CASE_LOCAL_TYPE(I64, I64)
986 CASE_LOCAL_TYPE(F32, F32)
987 CASE_LOCAL_TYPE(F64, F64)
988 CASE_LOCAL_TYPE(S128, S128)
989 CASE_LOCAL_TYPE(Void, Stmt)
990 default:
991 os << " 0x" << AsHex(i.pc()[1], 2) << ",";
992 break;
993 }
994 #undef CASE_LOCAL_TYPE
995 } else {
996 for (unsigned j = 1; j < length; ++j) {
997 os << " 0x" << AsHex(i.pc()[j], 2) << ",";
998 }
999 }
1000
1001 switch (opcode) {
1002 case kExprElse:
1003 os << " // @" << i.pc_offset();
1004 control_depth++;
1005 break;
1006 case kExprLoop:
1007 case kExprIf:
1008 case kExprBlock:
1009 case kExprTry: {
1010 BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
1011 i.pc());
1012 os << " // @" << i.pc_offset();
1013 if (decoder.Complete(imm)) {
1014 for (unsigned i = 0; i < imm.out_arity(); i++) {
1015 os << " " << ValueTypes::TypeName(imm.out_type(i));
1016 }
1017 }
1018 control_depth++;
1019 break;
1020 }
1021 case kExprEnd:
1022 os << " // @" << i.pc_offset();
1023 control_depth--;
1024 break;
1025 case kExprBr: {
1026 BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
1027 os << " // depth=" << imm.depth;
1028 break;
1029 }
1030 case kExprBrIf: {
1031 BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
1032 os << " // depth=" << imm.depth;
1033 break;
1034 }
1035 case kExprBrTable: {
1036 BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc());
1037 os << " // entries=" << imm.table_count;
1038 break;
1039 }
1040 case kExprCallIndirect: {
1041 CallIndirectImmediate<Decoder::kNoValidate> imm(&i, i.pc());
1042 os << " // sig #" << imm.sig_index;
1043 if (decoder.Complete(i.pc(), imm)) {
1044 os << ": " << *imm.sig;
1045 }
1046 break;
1047 }
1048 case kExprCallFunction: {
1049 CallFunctionImmediate<Decoder::kNoValidate> imm(&i, i.pc());
1050 os << " // function #" << imm.index;
1051 if (decoder.Complete(i.pc(), imm)) {
1052 os << ": " << *imm.sig;
1053 }
1054 break;
1055 }
1056 default:
1057 break;
1058 }
1059 os << std::endl;
1060 ++line_nr;
1061 }
1062 DCHECK(!line_numbers || line_numbers->size() == static_cast<size_t>(line_nr));
1063
1064 return decoder.ok();
1065 }
1066
AnalyzeLoopAssignmentForTesting(Zone * zone,size_t num_locals,const byte * start,const byte * end)1067 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
1068 const byte* start, const byte* end) {
1069 Decoder decoder(start, end);
1070 return WasmDecoder<Decoder::kValidate>::AnalyzeLoopAssignment(
1071 &decoder, start, static_cast<uint32_t>(num_locals), zone);
1072 }
1073
1074 #undef BUILD
1075
1076 } // namespace wasm
1077 } // namespace internal
1078 } // namespace v8
1079