1 // Copyright 2018 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/graph-builder-interface.h"
6
7 #include "src/compiler/wasm-compiler.h"
8 #include "src/flags/flags.h"
9 #include "src/handles/handles.h"
10 #include "src/objects/objects-inl.h"
11 #include "src/utils/ostreams.h"
12 #include "src/wasm/decoder.h"
13 #include "src/wasm/function-body-decoder-impl.h"
14 #include "src/wasm/function-body-decoder.h"
15 #include "src/wasm/value-type.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-inl.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 : public ZoneObject {
32 enum State { kControlEnd, kUnreachable, kReached, kMerged };
33
34 State state;
35 TFNode* control;
36 TFNode* effect;
37 compiler::WasmInstanceCacheNodes instance_cache;
38 ZoneVector<TFNode*> locals;
39
SsaEnvv8::internal::wasm::__anonfc9fbc4f0111::SsaEnv40 SsaEnv(Zone* zone, State state, TFNode* control, TFNode* effect,
41 uint32_t locals_size)
42 : state(state), control(control), effect(effect), locals(zone) {
43 if (locals_size > 0) locals.resize(locals_size);
44 }
45
46 SsaEnv(const SsaEnv& other) V8_NOEXCEPT = default;
SsaEnvv8::internal::wasm::__anonfc9fbc4f0111::SsaEnv47 SsaEnv(SsaEnv&& other) V8_NOEXCEPT : state(other.state),
48 control(other.control),
49 effect(other.effect),
50 instance_cache(other.instance_cache),
51 locals(std::move(other.locals)) {
52 other.Kill(kUnreachable);
53 }
54
Killv8::internal::wasm::__anonfc9fbc4f0111::SsaEnv55 void Kill(State new_state = kControlEnd) {
56 state = new_state;
57 locals.clear();
58 control = nullptr;
59 effect = nullptr;
60 instance_cache = {};
61 }
SetNotMergedv8::internal::wasm::__anonfc9fbc4f0111::SsaEnv62 void SetNotMerged() {
63 if (state == kMerged) state = kReached;
64 }
65 };
66
67 #define BUILD(func, ...) \
68 ([&] { \
69 DCHECK(decoder->ok()); \
70 return CheckForException(decoder, builder_->func(__VA_ARGS__)); \
71 })()
72
73 constexpr uint32_t kNullCatch = static_cast<uint32_t>(-1);
74
75 class WasmGraphBuildingInterface {
76 public:
77 static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
78 using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>;
79 using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
80
81 struct Value : public ValueBase<validate> {
82 TFNode* node = nullptr;
83
84 template <typename... Args>
Valuev8::internal::wasm::__anonfc9fbc4f0111::WasmGraphBuildingInterface::Value85 explicit Value(Args&&... args) V8_NOEXCEPT
86 : ValueBase(std::forward<Args>(args)...) {}
87 };
88
89 struct TryInfo : public ZoneObject {
90 SsaEnv* catch_env;
91 TFNode* exception = nullptr;
92
might_throwv8::internal::wasm::__anonfc9fbc4f0111::WasmGraphBuildingInterface::TryInfo93 bool might_throw() const { return exception != nullptr; }
94
95 MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TryInfo);
96
TryInfov8::internal::wasm::__anonfc9fbc4f0111::WasmGraphBuildingInterface::TryInfo97 explicit TryInfo(SsaEnv* c) : catch_env(c) {}
98 };
99
100 struct Control : public ControlBase<Value, validate> {
101 SsaEnv* end_env = nullptr; // end environment for the construct.
102 SsaEnv* false_env = nullptr; // false environment (only for if).
103 TryInfo* try_info = nullptr; // information about try statements.
104 int32_t previous_catch = -1; // previous Control with a catch.
105
106 MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(Control);
107
108 template <typename... Args>
Controlv8::internal::wasm::__anonfc9fbc4f0111::WasmGraphBuildingInterface::Control109 explicit Control(Args&&... args) V8_NOEXCEPT
110 : ControlBase(std::forward<Args>(args)...) {}
111 };
112
WasmGraphBuildingInterface(compiler::WasmGraphBuilder * builder)113 explicit WasmGraphBuildingInterface(compiler::WasmGraphBuilder* builder)
114 : builder_(builder) {}
115
StartFunction(FullDecoder * decoder)116 void StartFunction(FullDecoder* decoder) {
117 // The first '+ 1' is needed by TF Start node, the second '+ 1' is for the
118 // instance parameter.
119 TFNode* start = builder_->Start(
120 static_cast<int>(decoder->sig_->parameter_count() + 1 + 1));
121 uint32_t num_locals = decoder->num_locals();
122 SsaEnv* ssa_env = decoder->zone()->New<SsaEnv>(
123 decoder->zone(), SsaEnv::kReached, start, start, num_locals);
124
125 // Initialize effect and control before initializing the locals default
126 // values (which might require instance loads) or loading the context.
127 builder_->SetEffectControl(start);
128 // Initialize the instance parameter (index 0).
129 builder_->set_instance_node(builder_->Param(kWasmInstanceParameterIndex));
130 // Initialize local variables. Parameters are shifted by 1 because of the
131 // the instance parameter.
132 uint32_t index = 0;
133 for (; index < decoder->sig_->parameter_count(); ++index) {
134 ssa_env->locals[index] = builder_->Param(index + 1);
135 }
136 while (index < num_locals) {
137 ValueType type = decoder->local_type(index);
138 TFNode* node = DefaultValue(type);
139 while (index < num_locals && decoder->local_type(index) == type) {
140 // Do a whole run of like-typed locals at a time.
141 ssa_env->locals[index++] = node;
142 }
143 }
144 SetEnv(ssa_env);
145 LoadContextIntoSsa(ssa_env);
146
147 if (FLAG_trace_wasm) BUILD(TraceFunctionEntry, decoder->position());
148 }
149
150 // Reload the instance cache entries into the Ssa Environment.
LoadContextIntoSsa(SsaEnv * ssa_env)151 void LoadContextIntoSsa(SsaEnv* ssa_env) {
152 if (ssa_env) builder_->InitInstanceCache(&ssa_env->instance_cache);
153 }
154
StartFunctionBody(FullDecoder * decoder,Control * block)155 void StartFunctionBody(FullDecoder* decoder, Control* block) {}
156
FinishFunction(FullDecoder *)157 void FinishFunction(FullDecoder*) { builder_->PatchInStackCheckIfNeeded(); }
158
OnFirstError(FullDecoder *)159 void OnFirstError(FullDecoder*) {}
160
NextInstruction(FullDecoder *,WasmOpcode)161 void NextInstruction(FullDecoder*, WasmOpcode) {}
162
Block(FullDecoder * decoder,Control * block)163 void Block(FullDecoder* decoder, Control* block) {
164 // The branch environment is the outer environment.
165 block->end_env = ssa_env_;
166 SetEnv(Steal(decoder->zone(), ssa_env_));
167 }
168
Loop(FullDecoder * decoder,Control * block)169 void Loop(FullDecoder* decoder, Control* block) {
170 SsaEnv* finish_try_env = Steal(decoder->zone(), ssa_env_);
171 block->end_env = finish_try_env;
172 SetEnv(finish_try_env);
173 // The continue environment is the inner environment.
174 PrepareForLoop(decoder);
175 ssa_env_->SetNotMerged();
176 if (!decoder->ok()) return;
177 // Wrap input merge into phis.
178 for (uint32_t i = 0; i < block->start_merge.arity; ++i) {
179 Value& val = block->start_merge[i];
180 TFNode* inputs[] = {val.node, block->end_env->control};
181 val.node = builder_->Phi(val.type, 1, inputs);
182 }
183 }
184
Try(FullDecoder * decoder,Control * block)185 void Try(FullDecoder* decoder, Control* block) {
186 SsaEnv* outer_env = ssa_env_;
187 SsaEnv* catch_env = Split(decoder->zone(), outer_env);
188 // Mark catch environment as unreachable, since only accessable
189 // through catch unwinding (i.e. landing pads).
190 catch_env->state = SsaEnv::kUnreachable;
191 SsaEnv* try_env = Steal(decoder->zone(), outer_env);
192 SetEnv(try_env);
193 TryInfo* try_info = decoder->zone()->New<TryInfo>(catch_env);
194 block->end_env = outer_env;
195 block->try_info = try_info;
196 block->previous_catch = current_catch_;
197 current_catch_ = static_cast<int32_t>(decoder->control_depth() - 1);
198 }
199
If(FullDecoder * decoder,const Value & cond,Control * if_block)200 void If(FullDecoder* decoder, const Value& cond, Control* if_block) {
201 TFNode* if_true = nullptr;
202 TFNode* if_false = nullptr;
203 BUILD(BranchNoHint, cond.node, &if_true, &if_false);
204 SsaEnv* end_env = ssa_env_;
205 SsaEnv* false_env = Split(decoder->zone(), ssa_env_);
206 false_env->control = if_false;
207 SsaEnv* true_env = Steal(decoder->zone(), ssa_env_);
208 true_env->control = if_true;
209 if_block->end_env = end_env;
210 if_block->false_env = false_env;
211 SetEnv(true_env);
212 }
213
FallThruTo(FullDecoder * decoder,Control * c)214 void FallThruTo(FullDecoder* decoder, Control* c) {
215 DCHECK(!c->is_loop());
216 MergeValuesInto(decoder, c, &c->end_merge);
217 }
218
PopControl(FullDecoder * decoder,Control * block)219 void PopControl(FullDecoder* decoder, Control* block) {
220 // A loop just continues with the end environment. There is no merge.
221 if (block->is_loop()) return;
222 // Any other block falls through to the parent block.
223 if (block->reachable()) FallThruTo(decoder, block);
224 if (block->is_onearmed_if()) {
225 // Merge the else branch into the end merge.
226 SetEnv(block->false_env);
227 DCHECK_EQ(block->start_merge.arity, block->end_merge.arity);
228 Value* values =
229 block->start_merge.arity > 0 ? &block->start_merge[0] : nullptr;
230 MergeValuesInto(decoder, block, &block->end_merge, values);
231 }
232 // Now continue with the merged environment.
233 SetEnv(block->end_env);
234 }
235
EndControl(FullDecoder * decoder,Control * block)236 void EndControl(FullDecoder* decoder, Control* block) { ssa_env_->Kill(); }
237
UnOp(FullDecoder * decoder,WasmOpcode opcode,const Value & value,Value * result)238 void UnOp(FullDecoder* decoder, WasmOpcode opcode, const Value& value,
239 Value* result) {
240 result->node = BUILD(Unop, opcode, value.node, decoder->position());
241 }
242
BinOp(FullDecoder * decoder,WasmOpcode opcode,const Value & lhs,const Value & rhs,Value * result)243 void BinOp(FullDecoder* decoder, WasmOpcode opcode, const Value& lhs,
244 const Value& rhs, Value* result) {
245 TFNode* node =
246 BUILD(Binop, opcode, lhs.node, rhs.node, decoder->position());
247 if (result) result->node = node;
248 }
249
I32Const(FullDecoder * decoder,Value * result,int32_t value)250 void I32Const(FullDecoder* decoder, Value* result, int32_t value) {
251 result->node = builder_->Int32Constant(value);
252 }
253
I64Const(FullDecoder * decoder,Value * result,int64_t value)254 void I64Const(FullDecoder* decoder, Value* result, int64_t value) {
255 result->node = builder_->Int64Constant(value);
256 }
257
F32Const(FullDecoder * decoder,Value * result,float value)258 void F32Const(FullDecoder* decoder, Value* result, float value) {
259 result->node = builder_->Float32Constant(value);
260 }
261
F64Const(FullDecoder * decoder,Value * result,double value)262 void F64Const(FullDecoder* decoder, Value* result, double value) {
263 result->node = builder_->Float64Constant(value);
264 }
265
S128Const(FullDecoder * decoder,const Simd128Immediate<validate> & imm,Value * result)266 void S128Const(FullDecoder* decoder, const Simd128Immediate<validate>& imm,
267 Value* result) {
268 result->node = builder_->Simd128Constant(imm.value);
269 }
270
RefNull(FullDecoder * decoder,ValueType type,Value * result)271 void RefNull(FullDecoder* decoder, ValueType type, Value* result) {
272 result->node = builder_->RefNull();
273 }
274
RefFunc(FullDecoder * decoder,uint32_t function_index,Value * result)275 void RefFunc(FullDecoder* decoder, uint32_t function_index, Value* result) {
276 result->node = BUILD(RefFunc, function_index);
277 }
278
RefAsNonNull(FullDecoder * decoder,const Value & arg,Value * result)279 void RefAsNonNull(FullDecoder* decoder, const Value& arg, Value* result) {
280 result->node = BUILD(RefAsNonNull, arg.node, decoder->position());
281 }
282
Drop(FullDecoder * decoder,const Value & value)283 void Drop(FullDecoder* decoder, const Value& value) {}
284
DoReturn(FullDecoder * decoder,Vector<Value> values)285 void DoReturn(FullDecoder* decoder, Vector<Value> values) {
286 base::SmallVector<TFNode*, 8> nodes(values.size());
287 GetNodes(nodes.begin(), values);
288 if (FLAG_trace_wasm) {
289 BUILD(TraceFunctionExit, VectorOf(nodes), decoder->position());
290 }
291 BUILD(Return, VectorOf(nodes));
292 }
293
LocalGet(FullDecoder * decoder,Value * result,const LocalIndexImmediate<validate> & imm)294 void LocalGet(FullDecoder* decoder, Value* result,
295 const LocalIndexImmediate<validate>& imm) {
296 result->node = ssa_env_->locals[imm.index];
297 }
298
LocalSet(FullDecoder * decoder,const Value & value,const LocalIndexImmediate<validate> & imm)299 void LocalSet(FullDecoder* decoder, const Value& value,
300 const LocalIndexImmediate<validate>& imm) {
301 ssa_env_->locals[imm.index] = value.node;
302 }
303
LocalTee(FullDecoder * decoder,const Value & value,Value * result,const LocalIndexImmediate<validate> & imm)304 void LocalTee(FullDecoder* decoder, const Value& value, Value* result,
305 const LocalIndexImmediate<validate>& imm) {
306 result->node = value.node;
307 ssa_env_->locals[imm.index] = value.node;
308 }
309
AllocateLocals(FullDecoder * decoder,Vector<Value> local_values)310 void AllocateLocals(FullDecoder* decoder, Vector<Value> local_values) {
311 ZoneVector<TFNode*>* locals = &ssa_env_->locals;
312 locals->insert(locals->begin(), local_values.size(), nullptr);
313 for (uint32_t i = 0; i < local_values.size(); i++) {
314 (*locals)[i] = local_values[i].node;
315 }
316 }
317
DeallocateLocals(FullDecoder * decoder,uint32_t count)318 void DeallocateLocals(FullDecoder* decoder, uint32_t count) {
319 ZoneVector<TFNode*>* locals = &ssa_env_->locals;
320 locals->erase(locals->begin(), locals->begin() + count);
321 }
322
GlobalGet(FullDecoder * decoder,Value * result,const GlobalIndexImmediate<validate> & imm)323 void GlobalGet(FullDecoder* decoder, Value* result,
324 const GlobalIndexImmediate<validate>& imm) {
325 result->node = BUILD(GlobalGet, imm.index);
326 }
327
GlobalSet(FullDecoder * decoder,const Value & value,const GlobalIndexImmediate<validate> & imm)328 void GlobalSet(FullDecoder* decoder, const Value& value,
329 const GlobalIndexImmediate<validate>& imm) {
330 BUILD(GlobalSet, imm.index, value.node);
331 }
332
TableGet(FullDecoder * decoder,const Value & index,Value * result,const TableIndexImmediate<validate> & imm)333 void TableGet(FullDecoder* decoder, const Value& index, Value* result,
334 const TableIndexImmediate<validate>& imm) {
335 result->node = BUILD(TableGet, imm.index, index.node, decoder->position());
336 }
337
TableSet(FullDecoder * decoder,const Value & index,const Value & value,const TableIndexImmediate<validate> & imm)338 void TableSet(FullDecoder* decoder, const Value& index, const Value& value,
339 const TableIndexImmediate<validate>& imm) {
340 BUILD(TableSet, imm.index, index.node, value.node, decoder->position());
341 }
342
Unreachable(FullDecoder * decoder)343 void Unreachable(FullDecoder* decoder) {
344 BUILD(Trap, wasm::TrapReason::kTrapUnreachable, decoder->position());
345 }
346
Select(FullDecoder * decoder,const Value & cond,const Value & fval,const Value & tval,Value * result)347 void Select(FullDecoder* decoder, const Value& cond, const Value& fval,
348 const Value& tval, Value* result) {
349 TFNode* controls[2];
350 BUILD(BranchNoHint, cond.node, &controls[0], &controls[1]);
351 TFNode* merge = BUILD(Merge, 2, controls);
352 TFNode* inputs[] = {tval.node, fval.node, merge};
353 TFNode* phi = BUILD(Phi, tval.type, 2, inputs);
354 result->node = phi;
355 builder_->SetControl(merge);
356 }
357
BrOrRet(FullDecoder * decoder,uint32_t depth)358 void BrOrRet(FullDecoder* decoder, uint32_t depth) {
359 if (depth == decoder->control_depth() - 1) {
360 uint32_t ret_count = static_cast<uint32_t>(decoder->sig_->return_count());
361 base::SmallVector<TFNode*, 8> values(ret_count);
362 if (ret_count > 0) {
363 GetNodes(values.begin(), decoder->stack_value(ret_count), ret_count);
364 }
365 BUILD(Return, VectorOf(values));
366 } else {
367 Br(decoder, decoder->control_at(depth));
368 }
369 }
370
Br(FullDecoder * decoder,Control * target)371 void Br(FullDecoder* decoder, Control* target) {
372 MergeValuesInto(decoder, target, target->br_merge());
373 }
374
BrIf(FullDecoder * decoder,const Value & cond,uint32_t depth)375 void BrIf(FullDecoder* decoder, const Value& cond, uint32_t depth) {
376 SsaEnv* fenv = ssa_env_;
377 SsaEnv* tenv = Split(decoder->zone(), fenv);
378 fenv->SetNotMerged();
379 BUILD(BranchNoHint, cond.node, &tenv->control, &fenv->control);
380 builder_->SetControl(fenv->control);
381 SetEnv(tenv);
382 BrOrRet(decoder, depth);
383 SetEnv(fenv);
384 }
385
BrTable(FullDecoder * decoder,const BranchTableImmediate<validate> & imm,const Value & key)386 void BrTable(FullDecoder* decoder, const BranchTableImmediate<validate>& imm,
387 const Value& key) {
388 if (imm.table_count == 0) {
389 // Only a default target. Do the equivalent of br.
390 uint32_t target = BranchTableIterator<validate>(decoder, imm).next();
391 BrOrRet(decoder, target);
392 return;
393 }
394
395 SsaEnv* branch_env = ssa_env_;
396 // Build branches to the various blocks based on the table.
397 TFNode* sw = BUILD(Switch, imm.table_count + 1, key.node);
398
399 SsaEnv* copy = Steal(decoder->zone(), branch_env);
400 SetEnv(copy);
401 BranchTableIterator<validate> iterator(decoder, imm);
402 while (iterator.has_next()) {
403 uint32_t i = iterator.cur_index();
404 uint32_t target = iterator.next();
405 SetEnv(Split(decoder->zone(), copy));
406 builder_->SetControl(i == imm.table_count ? BUILD(IfDefault, sw)
407 : BUILD(IfValue, i, sw));
408 BrOrRet(decoder, target);
409 }
410 DCHECK(decoder->ok());
411 SetEnv(branch_env);
412 }
413
Else(FullDecoder * decoder,Control * if_block)414 void Else(FullDecoder* decoder, Control* if_block) {
415 if (if_block->reachable()) {
416 // Merge the if branch into the end merge.
417 MergeValuesInto(decoder, if_block, &if_block->end_merge);
418 }
419 SetEnv(if_block->false_env);
420 }
421
LoadMem(FullDecoder * decoder,LoadType type,const MemoryAccessImmediate<validate> & imm,const Value & index,Value * result)422 void LoadMem(FullDecoder* decoder, LoadType type,
423 const MemoryAccessImmediate<validate>& imm, const Value& index,
424 Value* result) {
425 result->node =
426 BUILD(LoadMem, type.value_type(), type.mem_type(), index.node,
427 imm.offset, imm.alignment, decoder->position());
428 }
429
LoadTransform(FullDecoder * decoder,LoadType type,LoadTransformationKind transform,const MemoryAccessImmediate<validate> & imm,const Value & index,Value * result)430 void LoadTransform(FullDecoder* decoder, LoadType type,
431 LoadTransformationKind transform,
432 const MemoryAccessImmediate<validate>& imm,
433 const Value& index, Value* result) {
434 result->node =
435 BUILD(LoadTransform, type.value_type(), type.mem_type(), transform,
436 index.node, imm.offset, imm.alignment, decoder->position());
437 }
438
LoadLane(FullDecoder * decoder,LoadType type,const Value & value,const Value & index,const MemoryAccessImmediate<validate> & imm,const uint8_t laneidx,Value * result)439 void LoadLane(FullDecoder* decoder, LoadType type, const Value& value,
440 const Value& index, const MemoryAccessImmediate<validate>& imm,
441 const uint8_t laneidx, Value* result) {
442 result->node = BUILD(LoadLane, type.mem_type(), value.node, index.node,
443 imm.offset, laneidx, decoder->position());
444 }
445
StoreMem(FullDecoder * decoder,StoreType type,const MemoryAccessImmediate<validate> & imm,const Value & index,const Value & value)446 void StoreMem(FullDecoder* decoder, StoreType type,
447 const MemoryAccessImmediate<validate>& imm, const Value& index,
448 const Value& value) {
449 BUILD(StoreMem, type.mem_rep(), index.node, imm.offset, imm.alignment,
450 value.node, decoder->position(), type.value_type());
451 }
452
StoreLane(FullDecoder * decoder,StoreType type,const MemoryAccessImmediate<validate> & imm,const Value & index,const Value & value,const uint8_t laneidx)453 void StoreLane(FullDecoder* decoder, StoreType type,
454 const MemoryAccessImmediate<validate>& imm, const Value& index,
455 const Value& value, const uint8_t laneidx) {
456 BUILD(StoreLane, type.mem_rep(), index.node, imm.offset, imm.alignment,
457 value.node, laneidx, decoder->position(), type.value_type());
458 }
459
CurrentMemoryPages(FullDecoder * decoder,Value * result)460 void CurrentMemoryPages(FullDecoder* decoder, Value* result) {
461 result->node = BUILD(CurrentMemoryPages);
462 }
463
MemoryGrow(FullDecoder * decoder,const Value & value,Value * result)464 void MemoryGrow(FullDecoder* decoder, const Value& value, Value* result) {
465 result->node = BUILD(MemoryGrow, value.node);
466 // Always reload the instance cache after growing memory.
467 LoadContextIntoSsa(ssa_env_);
468 }
469
470 enum CallMode { kDirect, kIndirect, kRef };
471
CallDirect(FullDecoder * decoder,const CallFunctionImmediate<validate> & imm,const Value args[],Value returns[])472 void CallDirect(FullDecoder* decoder,
473 const CallFunctionImmediate<validate>& imm,
474 const Value args[], Value returns[]) {
475 DoCall(decoder, kDirect, 0, CheckForNull::kWithoutNullCheck, nullptr,
476 imm.sig, imm.index, args, returns);
477 }
478
ReturnCall(FullDecoder * decoder,const CallFunctionImmediate<validate> & imm,const Value args[])479 void ReturnCall(FullDecoder* decoder,
480 const CallFunctionImmediate<validate>& imm,
481 const Value args[]) {
482 DoReturnCall(decoder, kDirect, 0, CheckForNull::kWithoutNullCheck, nullptr,
483 imm.sig, imm.index, args);
484 }
485
CallIndirect(FullDecoder * decoder,const Value & index,const CallIndirectImmediate<validate> & imm,const Value args[],Value returns[])486 void CallIndirect(FullDecoder* decoder, const Value& index,
487 const CallIndirectImmediate<validate>& imm,
488 const Value args[], Value returns[]) {
489 DoCall(decoder, kIndirect, imm.table_index, CheckForNull::kWithoutNullCheck,
490 index.node, imm.sig, imm.sig_index, args, returns);
491 }
492
ReturnCallIndirect(FullDecoder * decoder,const Value & index,const CallIndirectImmediate<validate> & imm,const Value args[])493 void ReturnCallIndirect(FullDecoder* decoder, const Value& index,
494 const CallIndirectImmediate<validate>& imm,
495 const Value args[]) {
496 DoReturnCall(decoder, kIndirect, imm.table_index,
497 CheckForNull::kWithoutNullCheck, index.node, imm.sig,
498 imm.sig_index, args);
499 }
500
CallRef(FullDecoder * decoder,const Value & func_ref,const FunctionSig * sig,uint32_t sig_index,const Value args[],Value returns[])501 void CallRef(FullDecoder* decoder, const Value& func_ref,
502 const FunctionSig* sig, uint32_t sig_index, const Value args[],
503 Value returns[]) {
504 CheckForNull null_check = func_ref.type.is_nullable()
505 ? CheckForNull::kWithNullCheck
506 : CheckForNull::kWithoutNullCheck;
507 DoCall(decoder, kRef, 0, null_check, func_ref.node, sig, sig_index, args,
508 returns);
509 }
510
ReturnCallRef(FullDecoder * decoder,const Value & func_ref,const FunctionSig * sig,uint32_t sig_index,const Value args[])511 void ReturnCallRef(FullDecoder* decoder, const Value& func_ref,
512 const FunctionSig* sig, uint32_t sig_index,
513 const Value args[]) {
514 CheckForNull null_check = func_ref.type.is_nullable()
515 ? CheckForNull::kWithNullCheck
516 : CheckForNull::kWithoutNullCheck;
517 DoReturnCall(decoder, kRef, 0, null_check, func_ref.node, sig, sig_index,
518 args);
519 }
520
BrOnNull(FullDecoder * decoder,const Value & ref_object,uint32_t depth)521 void BrOnNull(FullDecoder* decoder, const Value& ref_object, uint32_t depth) {
522 SsaEnv* non_null_env = ssa_env_;
523 SsaEnv* null_env = Split(decoder->zone(), non_null_env);
524 non_null_env->SetNotMerged();
525 BUILD(BrOnNull, ref_object.node, &null_env->control,
526 &non_null_env->control);
527 builder_->SetControl(non_null_env->control);
528 SetEnv(null_env);
529 BrOrRet(decoder, depth);
530 SetEnv(non_null_env);
531 }
532
SimdOp(FullDecoder * decoder,WasmOpcode opcode,Vector<Value> args,Value * result)533 void SimdOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
534 Value* result) {
535 base::SmallVector<TFNode*, 8> inputs(args.size());
536 GetNodes(inputs.begin(), args);
537 TFNode* node = BUILD(SimdOp, opcode, inputs.begin());
538 if (result) result->node = node;
539 }
540
SimdLaneOp(FullDecoder * decoder,WasmOpcode opcode,const SimdLaneImmediate<validate> & imm,Vector<Value> inputs,Value * result)541 void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode,
542 const SimdLaneImmediate<validate>& imm, Vector<Value> inputs,
543 Value* result) {
544 base::SmallVector<TFNode*, 8> nodes(inputs.size());
545 GetNodes(nodes.begin(), inputs);
546 result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes.begin());
547 }
548
Simd8x16ShuffleOp(FullDecoder * decoder,const Simd128Immediate<validate> & imm,const Value & input0,const Value & input1,Value * result)549 void Simd8x16ShuffleOp(FullDecoder* decoder,
550 const Simd128Immediate<validate>& imm,
551 const Value& input0, const Value& input1,
552 Value* result) {
553 TFNode* input_nodes[] = {input0.node, input1.node};
554 result->node = BUILD(Simd8x16ShuffleOp, imm.value, input_nodes);
555 }
556
Throw(FullDecoder * decoder,const ExceptionIndexImmediate<validate> & imm,const Vector<Value> & value_args)557 void Throw(FullDecoder* decoder, const ExceptionIndexImmediate<validate>& imm,
558 const Vector<Value>& value_args) {
559 int count = value_args.length();
560 ZoneVector<TFNode*> args(count, decoder->zone());
561 for (int i = 0; i < count; ++i) {
562 args[i] = value_args[i].node;
563 }
564 BUILD(Throw, imm.index, imm.exception, VectorOf(args), decoder->position());
565 builder_->TerminateThrow(effect(), control());
566 }
567
Rethrow(FullDecoder * decoder,const Value & exception)568 void Rethrow(FullDecoder* decoder, const Value& exception) {
569 BUILD(Rethrow, exception.node);
570 builder_->TerminateThrow(effect(), control());
571 }
572
BrOnException(FullDecoder * decoder,const Value & exception,const ExceptionIndexImmediate<validate> & imm,uint32_t depth,Vector<Value> values)573 void BrOnException(FullDecoder* decoder, const Value& exception,
574 const ExceptionIndexImmediate<validate>& imm,
575 uint32_t depth, Vector<Value> values) {
576 TFNode* if_match = nullptr;
577 TFNode* if_no_match = nullptr;
578
579 // Get the exception tag and see if it matches the expected one.
580 TFNode* caught_tag =
581 BUILD(GetExceptionTag, exception.node, decoder->position());
582 TFNode* exception_tag = BUILD(LoadExceptionTagFromTable, imm.index);
583 TFNode* compare = BUILD(ExceptionTagEqual, caught_tag, exception_tag);
584 BUILD(BranchNoHint, compare, &if_match, &if_no_match);
585 SsaEnv* if_no_match_env = Split(decoder->zone(), ssa_env_);
586 SsaEnv* if_match_env = Steal(decoder->zone(), ssa_env_);
587 if_no_match_env->control = if_no_match;
588 if_match_env->control = if_match;
589
590 // If the tags match we extract the values from the exception object and
591 // push them onto the operand stack using the passed {values} vector.
592 SetEnv(if_match_env);
593 base::SmallVector<TFNode*, 8> caught_values(values.size());
594 Vector<TFNode*> caught_vector = VectorOf(caught_values);
595 BUILD(GetExceptionValues, exception.node, imm.exception, caught_vector);
596 for (size_t i = 0, e = values.size(); i < e; ++i) {
597 values[i].node = caught_vector[i];
598 }
599 BrOrRet(decoder, depth);
600
601 // If the tags don't match we fall-through here.
602 SetEnv(if_no_match_env);
603 }
604
Catch(FullDecoder * decoder,Control * block,Value * exception)605 void Catch(FullDecoder* decoder, Control* block, Value* exception) {
606 DCHECK(block->is_try_catch());
607 DCHECK_EQ(decoder->control_at(0), block);
608
609 current_catch_ = block->previous_catch; // Pop try scope.
610
611 // The catch block is unreachable if no possible throws in the try block
612 // exist. We only build a landing pad if some node in the try block can
613 // (possibly) throw. Otherwise the catch environments remain empty.
614 if (!block->try_info->might_throw()) {
615 decoder->SetSucceedingCodeDynamicallyUnreachable();
616 return;
617 }
618
619 SetEnv(block->try_info->catch_env);
620 DCHECK_NOT_NULL(block->try_info->exception);
621 exception->node = block->try_info->exception;
622 }
623
AtomicOp(FullDecoder * decoder,WasmOpcode opcode,Vector<Value> args,const MemoryAccessImmediate<validate> & imm,Value * result)624 void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
625 const MemoryAccessImmediate<validate>& imm, Value* result) {
626 base::SmallVector<TFNode*, 8> inputs(args.size());
627 GetNodes(inputs.begin(), args);
628 TFNode* node = BUILD(AtomicOp, opcode, inputs.begin(), imm.alignment,
629 imm.offset, decoder->position());
630 if (result) result->node = node;
631 }
632
AtomicFence(FullDecoder * decoder)633 void AtomicFence(FullDecoder* decoder) { BUILD(AtomicFence); }
634
MemoryInit(FullDecoder * decoder,const MemoryInitImmediate<validate> & imm,const Value & dst,const Value & src,const Value & size)635 void MemoryInit(FullDecoder* decoder,
636 const MemoryInitImmediate<validate>& imm, const Value& dst,
637 const Value& src, const Value& size) {
638 BUILD(MemoryInit, imm.data_segment_index, dst.node, src.node, size.node,
639 decoder->position());
640 }
641
DataDrop(FullDecoder * decoder,const DataDropImmediate<validate> & imm)642 void DataDrop(FullDecoder* decoder, const DataDropImmediate<validate>& imm) {
643 BUILD(DataDrop, imm.index, decoder->position());
644 }
645
MemoryCopy(FullDecoder * decoder,const MemoryCopyImmediate<validate> & imm,const Value & dst,const Value & src,const Value & size)646 void MemoryCopy(FullDecoder* decoder,
647 const MemoryCopyImmediate<validate>& imm, const Value& dst,
648 const Value& src, const Value& size) {
649 BUILD(MemoryCopy, dst.node, src.node, size.node, decoder->position());
650 }
651
MemoryFill(FullDecoder * decoder,const MemoryIndexImmediate<validate> & imm,const Value & dst,const Value & value,const Value & size)652 void MemoryFill(FullDecoder* decoder,
653 const MemoryIndexImmediate<validate>& imm, const Value& dst,
654 const Value& value, const Value& size) {
655 BUILD(MemoryFill, dst.node, value.node, size.node, decoder->position());
656 }
657
TableInit(FullDecoder * decoder,const TableInitImmediate<validate> & imm,Vector<Value> args)658 void TableInit(FullDecoder* decoder, const TableInitImmediate<validate>& imm,
659 Vector<Value> args) {
660 BUILD(TableInit, imm.table.index, imm.elem_segment_index, args[0].node,
661 args[1].node, args[2].node, decoder->position());
662 }
663
ElemDrop(FullDecoder * decoder,const ElemDropImmediate<validate> & imm)664 void ElemDrop(FullDecoder* decoder, const ElemDropImmediate<validate>& imm) {
665 BUILD(ElemDrop, imm.index, decoder->position());
666 }
667
TableCopy(FullDecoder * decoder,const TableCopyImmediate<validate> & imm,Vector<Value> args)668 void TableCopy(FullDecoder* decoder, const TableCopyImmediate<validate>& imm,
669 Vector<Value> args) {
670 BUILD(TableCopy, imm.table_dst.index, imm.table_src.index, args[0].node,
671 args[1].node, args[2].node, decoder->position());
672 }
673
TableGrow(FullDecoder * decoder,const TableIndexImmediate<validate> & imm,const Value & value,const Value & delta,Value * result)674 void TableGrow(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
675 const Value& value, const Value& delta, Value* result) {
676 result->node = BUILD(TableGrow, imm.index, value.node, delta.node);
677 }
678
TableSize(FullDecoder * decoder,const TableIndexImmediate<validate> & imm,Value * result)679 void TableSize(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
680 Value* result) {
681 result->node = BUILD(TableSize, imm.index);
682 }
683
TableFill(FullDecoder * decoder,const TableIndexImmediate<validate> & imm,const Value & start,const Value & value,const Value & count)684 void TableFill(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
685 const Value& start, const Value& value, const Value& count) {
686 BUILD(TableFill, imm.index, start.node, value.node, count.node);
687 }
688
StructNewWithRtt(FullDecoder * decoder,const StructIndexImmediate<validate> & imm,const Value & rtt,const Value args[],Value * result)689 void StructNewWithRtt(FullDecoder* decoder,
690 const StructIndexImmediate<validate>& imm,
691 const Value& rtt, const Value args[], Value* result) {
692 uint32_t field_count = imm.struct_type->field_count();
693 base::SmallVector<TFNode*, 16> arg_nodes(field_count);
694 for (uint32_t i = 0; i < field_count; i++) {
695 arg_nodes[i] = args[i].node;
696 }
697 result->node = BUILD(StructNewWithRtt, imm.index, imm.struct_type, rtt.node,
698 VectorOf(arg_nodes));
699 }
StructNewDefault(FullDecoder * decoder,const StructIndexImmediate<validate> & imm,const Value & rtt,Value * result)700 void StructNewDefault(FullDecoder* decoder,
701 const StructIndexImmediate<validate>& imm,
702 const Value& rtt, Value* result) {
703 uint32_t field_count = imm.struct_type->field_count();
704 base::SmallVector<TFNode*, 16> arg_nodes(field_count);
705 for (uint32_t i = 0; i < field_count; i++) {
706 arg_nodes[i] = DefaultValue(imm.struct_type->field(i));
707 }
708 result->node = BUILD(StructNewWithRtt, imm.index, imm.struct_type, rtt.node,
709 VectorOf(arg_nodes));
710 }
711
StructGet(FullDecoder * decoder,const Value & struct_object,const FieldIndexImmediate<validate> & field,bool is_signed,Value * result)712 void StructGet(FullDecoder* decoder, const Value& struct_object,
713 const FieldIndexImmediate<validate>& field, bool is_signed,
714 Value* result) {
715 CheckForNull null_check = struct_object.type.is_nullable()
716 ? CheckForNull::kWithNullCheck
717 : CheckForNull::kWithoutNullCheck;
718 result->node =
719 BUILD(StructGet, struct_object.node, field.struct_index.struct_type,
720 field.index, null_check, is_signed, decoder->position());
721 }
722
StructSet(FullDecoder * decoder,const Value & struct_object,const FieldIndexImmediate<validate> & field,const Value & field_value)723 void StructSet(FullDecoder* decoder, const Value& struct_object,
724 const FieldIndexImmediate<validate>& field,
725 const Value& field_value) {
726 CheckForNull null_check = struct_object.type.is_nullable()
727 ? CheckForNull::kWithNullCheck
728 : CheckForNull::kWithoutNullCheck;
729 BUILD(StructSet, struct_object.node, field.struct_index.struct_type,
730 field.index, field_value.node, null_check, decoder->position());
731 }
732
ArrayNewWithRtt(FullDecoder * decoder,const ArrayIndexImmediate<validate> & imm,const Value & length,const Value & initial_value,const Value & rtt,Value * result)733 void ArrayNewWithRtt(FullDecoder* decoder,
734 const ArrayIndexImmediate<validate>& imm,
735 const Value& length, const Value& initial_value,
736 const Value& rtt, Value* result) {
737 result->node = BUILD(ArrayNewWithRtt, imm.index, imm.array_type,
738 length.node, initial_value.node, rtt.node);
739 }
740
ArrayNewDefault(FullDecoder * decoder,const ArrayIndexImmediate<validate> & imm,const Value & length,const Value & rtt,Value * result)741 void ArrayNewDefault(FullDecoder* decoder,
742 const ArrayIndexImmediate<validate>& imm,
743 const Value& length, const Value& rtt, Value* result) {
744 TFNode* initial_value = DefaultValue(imm.array_type->element_type());
745 result->node = BUILD(ArrayNewWithRtt, imm.index, imm.array_type,
746 length.node, initial_value, rtt.node);
747 }
748
ArrayGet(FullDecoder * decoder,const Value & array_obj,const ArrayIndexImmediate<validate> & imm,const Value & index,bool is_signed,Value * result)749 void ArrayGet(FullDecoder* decoder, const Value& array_obj,
750 const ArrayIndexImmediate<validate>& imm, const Value& index,
751 bool is_signed, Value* result) {
752 CheckForNull null_check = array_obj.type.is_nullable()
753 ? CheckForNull::kWithNullCheck
754 : CheckForNull::kWithoutNullCheck;
755 result->node = BUILD(ArrayGet, array_obj.node, imm.array_type, index.node,
756 null_check, is_signed, decoder->position());
757 }
758
ArraySet(FullDecoder * decoder,const Value & array_obj,const ArrayIndexImmediate<validate> & imm,const Value & index,const Value & value)759 void ArraySet(FullDecoder* decoder, const Value& array_obj,
760 const ArrayIndexImmediate<validate>& imm, const Value& index,
761 const Value& value) {
762 CheckForNull null_check = array_obj.type.is_nullable()
763 ? CheckForNull::kWithNullCheck
764 : CheckForNull::kWithoutNullCheck;
765 BUILD(ArraySet, array_obj.node, imm.array_type, index.node, value.node,
766 null_check, decoder->position());
767 }
768
ArrayLen(FullDecoder * decoder,const Value & array_obj,Value * result)769 void ArrayLen(FullDecoder* decoder, const Value& array_obj, Value* result) {
770 result->node = BUILD(ArrayLen, array_obj.node, decoder->position());
771 }
772
I31New(FullDecoder * decoder,const Value & input,Value * result)773 void I31New(FullDecoder* decoder, const Value& input, Value* result) {
774 result->node = BUILD(I31New, input.node);
775 }
776
I31GetS(FullDecoder * decoder,const Value & input,Value * result)777 void I31GetS(FullDecoder* decoder, const Value& input, Value* result) {
778 result->node = BUILD(I31GetS, input.node);
779 }
780
I31GetU(FullDecoder * decoder,const Value & input,Value * result)781 void I31GetU(FullDecoder* decoder, const Value& input, Value* result) {
782 result->node = BUILD(I31GetU, input.node);
783 }
784
RttCanon(FullDecoder * decoder,const HeapTypeImmediate<validate> & imm,Value * result)785 void RttCanon(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
786 Value* result) {
787 result->node = BUILD(RttCanon, imm.type);
788 }
789
RttSub(FullDecoder * decoder,const HeapTypeImmediate<validate> & imm,const Value & parent,Value * result)790 void RttSub(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
791 const Value& parent, Value* result) {
792 result->node = BUILD(RttSub, imm.type, parent.node);
793 }
794
RefTest(FullDecoder * decoder,const Value & object,const Value & rtt,Value * result)795 void RefTest(FullDecoder* decoder, const Value& object, const Value& rtt,
796 Value* result) {
797 using CheckForI31 = compiler::WasmGraphBuilder::CheckForI31;
798 using RttIsI31 = compiler::WasmGraphBuilder::RttIsI31;
799 CheckForNull null_check = object.type.is_nullable()
800 ? CheckForNull::kWithNullCheck
801 : CheckForNull::kWithoutNullCheck;
802 CheckForI31 i31_check =
803 IsSubtypeOf(kWasmI31Ref, object.type, decoder->module_)
804 ? CheckForI31::kWithI31Check
805 : CheckForI31::kNoI31Check;
806 RttIsI31 rtt_is_i31 = rtt.type.heap_representation() == HeapType::kI31
807 ? RttIsI31::kRttIsI31
808 : RttIsI31::kRttIsNotI31;
809 result->node = BUILD(RefTest, object.node, rtt.node, null_check, i31_check,
810 rtt_is_i31);
811 }
812
RefCast(FullDecoder * decoder,const Value & object,const Value & rtt,Value * result)813 void RefCast(FullDecoder* decoder, const Value& object, const Value& rtt,
814 Value* result) {
815 using CheckForI31 = compiler::WasmGraphBuilder::CheckForI31;
816 using RttIsI31 = compiler::WasmGraphBuilder::RttIsI31;
817 CheckForNull null_check = object.type.is_nullable()
818 ? CheckForNull::kWithNullCheck
819 : CheckForNull::kWithoutNullCheck;
820 CheckForI31 i31_check =
821 IsSubtypeOf(kWasmI31Ref, object.type, decoder->module_)
822 ? CheckForI31::kWithI31Check
823 : CheckForI31::kNoI31Check;
824 RttIsI31 rtt_is_i31 = rtt.type.heap_representation() == HeapType::kI31
825 ? RttIsI31::kRttIsI31
826 : RttIsI31::kRttIsNotI31;
827 result->node = BUILD(RefCast, object.node, rtt.node, null_check, i31_check,
828 rtt_is_i31, decoder->position());
829 }
830
BrOnCast(FullDecoder * decoder,const Value & object,const Value & rtt,Value * value_on_branch,uint32_t depth)831 void BrOnCast(FullDecoder* decoder, const Value& object, const Value& rtt,
832 Value* value_on_branch, uint32_t depth) {
833 using CheckForI31 = compiler::WasmGraphBuilder::CheckForI31;
834 using RttIsI31 = compiler::WasmGraphBuilder::RttIsI31;
835 CheckForNull null_check = object.type.is_nullable()
836 ? CheckForNull::kWithNullCheck
837 : CheckForNull::kWithoutNullCheck;
838 CheckForI31 i31_check =
839 IsSubtypeOf(kWasmI31Ref, object.type, decoder->module_)
840 ? CheckForI31::kWithI31Check
841 : CheckForI31::kNoI31Check;
842 RttIsI31 rtt_is_i31 = rtt.type.heap_representation() == HeapType::kI31
843 ? RttIsI31::kRttIsI31
844 : RttIsI31::kRttIsNotI31;
845 SsaEnv* match_env = Split(decoder->zone(), ssa_env_);
846 SsaEnv* no_match_env = Steal(decoder->zone(), ssa_env_);
847 no_match_env->SetNotMerged();
848 BUILD(BrOnCast, object.node, rtt.node, null_check, i31_check, rtt_is_i31,
849 &match_env->control, &match_env->effect, &no_match_env->control,
850 &no_match_env->effect);
851 builder_->SetControl(no_match_env->control);
852 SetEnv(match_env);
853 value_on_branch->node = object.node;
854 BrOrRet(decoder, depth);
855 SetEnv(no_match_env);
856 }
857
PassThrough(FullDecoder * decoder,const Value & from,Value * to)858 void PassThrough(FullDecoder* decoder, const Value& from, Value* to) {
859 to->node = from.node;
860 }
861
862 private:
863 SsaEnv* ssa_env_ = nullptr;
864 compiler::WasmGraphBuilder* builder_;
865 uint32_t current_catch_ = kNullCatch;
866
effect()867 TFNode* effect() { return builder_->effect(); }
868
control()869 TFNode* control() { return builder_->control(); }
870
current_try_info(FullDecoder * decoder)871 TryInfo* current_try_info(FullDecoder* decoder) {
872 return decoder->control_at(decoder->control_depth() - 1 - current_catch_)
873 ->try_info;
874 }
875
GetNodes(TFNode ** nodes,Value * values,size_t count)876 void GetNodes(TFNode** nodes, Value* values, size_t count) {
877 for (size_t i = 0; i < count; ++i) {
878 nodes[i] = values[i].node;
879 }
880 }
881
GetNodes(TFNode ** nodes,Vector<Value> values)882 void GetNodes(TFNode** nodes, Vector<Value> values) {
883 GetNodes(nodes, values.begin(), values.size());
884 }
885
SetEnv(SsaEnv * env)886 void SetEnv(SsaEnv* env) {
887 if (FLAG_trace_wasm_decoder) {
888 char state = 'X';
889 if (env) {
890 switch (env->state) {
891 case SsaEnv::kReached:
892 state = 'R';
893 break;
894 case SsaEnv::kUnreachable:
895 state = 'U';
896 break;
897 case SsaEnv::kMerged:
898 state = 'M';
899 break;
900 case SsaEnv::kControlEnd:
901 state = 'E';
902 break;
903 }
904 }
905 PrintF("{set_env = %p, state = %c", env, state);
906 if (env && env->control) {
907 PrintF(", control = ");
908 compiler::WasmGraphBuilder::PrintDebugName(env->control);
909 }
910 PrintF("}\n");
911 }
912 if (ssa_env_) {
913 ssa_env_->control = control();
914 ssa_env_->effect = effect();
915 }
916 ssa_env_ = env;
917 builder_->SetEffectControl(env->effect, env->control);
918 builder_->set_instance_cache(&env->instance_cache);
919 }
920
CheckForException(FullDecoder * decoder,TFNode * node)921 TFNode* CheckForException(FullDecoder* decoder, TFNode* node) {
922 if (node == nullptr) return nullptr;
923
924 const bool inside_try_scope = current_catch_ != kNullCatch;
925
926 if (!inside_try_scope) return node;
927
928 TFNode* if_success = nullptr;
929 TFNode* if_exception = nullptr;
930 if (!builder_->ThrowsException(node, &if_success, &if_exception)) {
931 return node;
932 }
933
934 SsaEnv* success_env = Steal(decoder->zone(), ssa_env_);
935 success_env->control = if_success;
936
937 SsaEnv* exception_env = Split(decoder->zone(), success_env);
938 exception_env->control = if_exception;
939 exception_env->effect = if_exception;
940 SetEnv(exception_env);
941 TryInfo* try_info = current_try_info(decoder);
942 Goto(decoder, try_info->catch_env);
943 if (try_info->exception == nullptr) {
944 DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state);
945 try_info->exception = if_exception;
946 } else {
947 DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state);
948 try_info->exception = builder_->CreateOrMergeIntoPhi(
949 MachineRepresentation::kWord32, try_info->catch_env->control,
950 try_info->exception, if_exception);
951 }
952
953 SetEnv(success_env);
954 return node;
955 }
956
DefaultValue(ValueType type)957 TFNode* DefaultValue(ValueType type) {
958 DCHECK(type.is_defaultable());
959 switch (type.kind()) {
960 case ValueType::kI8:
961 case ValueType::kI16:
962 case ValueType::kI32:
963 return builder_->Int32Constant(0);
964 case ValueType::kI64:
965 return builder_->Int64Constant(0);
966 case ValueType::kF32:
967 return builder_->Float32Constant(0);
968 case ValueType::kF64:
969 return builder_->Float64Constant(0);
970 case ValueType::kS128:
971 return builder_->S128Zero();
972 case ValueType::kOptRef:
973 return builder_->RefNull();
974 case ValueType::kRtt:
975 case ValueType::kStmt:
976 case ValueType::kBottom:
977 case ValueType::kRef:
978 UNREACHABLE();
979 }
980 }
981
MergeValuesInto(FullDecoder * decoder,Control * c,Merge<Value> * merge,Value * values)982 void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge,
983 Value* values) {
984 DCHECK(merge == &c->start_merge || merge == &c->end_merge);
985
986 SsaEnv* target = c->end_env;
987 const bool first = target->state == SsaEnv::kUnreachable;
988 Goto(decoder, target);
989
990 if (merge->arity == 0) return;
991
992 for (uint32_t i = 0; i < merge->arity; ++i) {
993 Value& val = values[i];
994 Value& old = (*merge)[i];
995 DCHECK_NOT_NULL(val.node);
996 DCHECK(val.type == kWasmBottom || val.type.machine_representation() ==
997 old.type.machine_representation());
998 old.node = first ? val.node
999 : builder_->CreateOrMergeIntoPhi(
1000 old.type.machine_representation(), target->control,
1001 old.node, val.node);
1002 }
1003 }
1004
MergeValuesInto(FullDecoder * decoder,Control * c,Merge<Value> * merge)1005 void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge) {
1006 #ifdef DEBUG
1007 uint32_t avail =
1008 decoder->stack_size() - decoder->control_at(0)->stack_depth;
1009 DCHECK_GE(avail, merge->arity);
1010 #endif
1011 Value* stack_values =
1012 merge->arity > 0 ? decoder->stack_value(merge->arity) : nullptr;
1013 MergeValuesInto(decoder, c, merge, stack_values);
1014 }
1015
Goto(FullDecoder * decoder,SsaEnv * to)1016 void Goto(FullDecoder* decoder, SsaEnv* to) {
1017 DCHECK_NOT_NULL(to);
1018 switch (to->state) {
1019 case SsaEnv::kUnreachable: { // Overwrite destination.
1020 to->state = SsaEnv::kReached;
1021 to->locals = ssa_env_->locals;
1022 to->control = control();
1023 to->effect = effect();
1024 to->instance_cache = ssa_env_->instance_cache;
1025 break;
1026 }
1027 case SsaEnv::kReached: { // Create a new merge.
1028 to->state = SsaEnv::kMerged;
1029 // Merge control.
1030 TFNode* controls[] = {to->control, control()};
1031 TFNode* merge = builder_->Merge(2, controls);
1032 to->control = merge;
1033 // Merge effects.
1034 TFNode* old_effect = effect();
1035 if (old_effect != to->effect) {
1036 TFNode* inputs[] = {to->effect, old_effect, merge};
1037 to->effect = builder_->EffectPhi(2, inputs);
1038 }
1039 // Merge SSA values.
1040 for (int i = decoder->num_locals() - 1; i >= 0; i--) {
1041 TFNode* a = to->locals[i];
1042 TFNode* b = ssa_env_->locals[i];
1043 if (a != b) {
1044 TFNode* inputs[] = {a, b, merge};
1045 to->locals[i] = builder_->Phi(decoder->local_type(i), 2, inputs);
1046 }
1047 }
1048 // Start a new merge from the instance cache.
1049 builder_->NewInstanceCacheMerge(&to->instance_cache,
1050 &ssa_env_->instance_cache, merge);
1051 break;
1052 }
1053 case SsaEnv::kMerged: {
1054 TFNode* merge = to->control;
1055 // Extend the existing merge control node.
1056 builder_->AppendToMerge(merge, control());
1057 // Merge effects.
1058 to->effect =
1059 builder_->CreateOrMergeIntoEffectPhi(merge, to->effect, effect());
1060 // Merge locals.
1061 for (int i = decoder->num_locals() - 1; i >= 0; i--) {
1062 to->locals[i] = builder_->CreateOrMergeIntoPhi(
1063 decoder->local_type(i).machine_representation(), merge,
1064 to->locals[i], ssa_env_->locals[i]);
1065 }
1066 // Merge the instance caches.
1067 builder_->MergeInstanceCacheInto(&to->instance_cache,
1068 &ssa_env_->instance_cache, merge);
1069 break;
1070 }
1071 default:
1072 UNREACHABLE();
1073 }
1074 return ssa_env_->Kill();
1075 }
1076
PrepareForLoop(FullDecoder * decoder)1077 void PrepareForLoop(FullDecoder* decoder) {
1078 ssa_env_->state = SsaEnv::kMerged;
1079
1080 builder_->SetControl(builder_->Loop(control()));
1081 TFNode* effect_inputs[] = {effect(), control()};
1082 builder_->SetEffect(builder_->EffectPhi(1, effect_inputs));
1083 builder_->TerminateLoop(effect(), control());
1084 // The '+ 1' here is to be able to set the instance cache as assigned.
1085 BitVector* assigned = WasmDecoder<validate>::AnalyzeLoopAssignment(
1086 decoder, decoder->pc(), decoder->num_locals() + 1, decoder->zone());
1087 if (decoder->failed()) return;
1088 DCHECK_NOT_NULL(assigned);
1089
1090 // Only introduce phis for variables assigned in this loop.
1091 int instance_cache_index = decoder->num_locals();
1092 for (int i = decoder->num_locals() - 1; i >= 0; i--) {
1093 if (!assigned->Contains(i)) continue;
1094 TFNode* inputs[] = {ssa_env_->locals[i], control()};
1095 ssa_env_->locals[i] = builder_->Phi(decoder->local_type(i), 1, inputs);
1096 }
1097 // Introduce phis for instance cache pointers if necessary.
1098 if (assigned->Contains(instance_cache_index)) {
1099 builder_->PrepareInstanceCacheForLoop(&ssa_env_->instance_cache,
1100 control());
1101 }
1102
1103 SetEnv(Split(decoder->zone(), ssa_env_));
1104 builder_->StackCheck(decoder->position());
1105 }
1106
1107 // Create a complete copy of {from}.
Split(Zone * zone,SsaEnv * from)1108 SsaEnv* Split(Zone* zone, SsaEnv* from) {
1109 DCHECK_NOT_NULL(from);
1110 if (from == ssa_env_) {
1111 ssa_env_->control = control();
1112 ssa_env_->effect = effect();
1113 }
1114 SsaEnv* result = zone->New<SsaEnv>(*from);
1115 result->state = SsaEnv::kReached;
1116 return result;
1117 }
1118
1119 // Create a copy of {from} that steals its state and leaves {from}
1120 // unreachable.
Steal(Zone * zone,SsaEnv * from)1121 SsaEnv* Steal(Zone* zone, SsaEnv* from) {
1122 DCHECK_NOT_NULL(from);
1123 if (from == ssa_env_) {
1124 ssa_env_->control = control();
1125 ssa_env_->effect = effect();
1126 }
1127 SsaEnv* result = zone->New<SsaEnv>(std::move(*from));
1128 result->state = SsaEnv::kReached;
1129 return result;
1130 }
1131
1132 // Create an unreachable environment.
UnreachableEnv(Zone * zone)1133 SsaEnv* UnreachableEnv(Zone* zone) {
1134 return zone->New<SsaEnv>(zone, SsaEnv::kUnreachable, nullptr, nullptr, 0);
1135 }
1136
DoCall(FullDecoder * decoder,CallMode call_mode,uint32_t table_index,CheckForNull null_check,TFNode * caller_node,const FunctionSig * sig,uint32_t sig_index,const Value args[],Value returns[])1137 void DoCall(FullDecoder* decoder, CallMode call_mode, uint32_t table_index,
1138 CheckForNull null_check, TFNode* caller_node,
1139 const FunctionSig* sig, uint32_t sig_index, const Value args[],
1140 Value returns[]) {
1141 size_t param_count = sig->parameter_count();
1142 size_t return_count = sig->return_count();
1143 base::SmallVector<TFNode*, 16> arg_nodes(param_count + 1);
1144 base::SmallVector<TFNode*, 1> return_nodes(return_count);
1145 arg_nodes[0] = caller_node;
1146 for (size_t i = 0; i < param_count; ++i) {
1147 arg_nodes[i + 1] = args[i].node;
1148 }
1149 switch (call_mode) {
1150 case kIndirect:
1151 BUILD(CallIndirect, table_index, sig_index, VectorOf(arg_nodes),
1152 VectorOf(return_nodes), decoder->position());
1153 break;
1154 case kDirect:
1155 BUILD(CallDirect, sig_index, VectorOf(arg_nodes),
1156 VectorOf(return_nodes), decoder->position());
1157 break;
1158 case kRef:
1159 BUILD(CallRef, sig_index, VectorOf(arg_nodes), VectorOf(return_nodes),
1160 null_check, decoder->position());
1161 break;
1162 }
1163 for (size_t i = 0; i < return_count; ++i) {
1164 returns[i].node = return_nodes[i];
1165 }
1166 // The invoked function could have used grow_memory, so we need to
1167 // reload mem_size and mem_start.
1168 LoadContextIntoSsa(ssa_env_);
1169 }
1170
DoReturnCall(FullDecoder * decoder,CallMode call_mode,uint32_t table_index,CheckForNull null_check,TFNode * index_node,const FunctionSig * sig,uint32_t sig_index,const Value args[])1171 void DoReturnCall(FullDecoder* decoder, CallMode call_mode,
1172 uint32_t table_index, CheckForNull null_check,
1173 TFNode* index_node, const FunctionSig* sig,
1174 uint32_t sig_index, const Value args[]) {
1175 size_t arg_count = sig->parameter_count();
1176 base::SmallVector<TFNode*, 16> arg_nodes(arg_count + 1);
1177 arg_nodes[0] = index_node;
1178 for (size_t i = 0; i < arg_count; ++i) {
1179 arg_nodes[i + 1] = args[i].node;
1180 }
1181 switch (call_mode) {
1182 case kIndirect:
1183 BUILD(ReturnCallIndirect, table_index, sig_index, VectorOf(arg_nodes),
1184 decoder->position());
1185 break;
1186 case kDirect:
1187 BUILD(ReturnCall, sig_index, VectorOf(arg_nodes), decoder->position());
1188 break;
1189 case kRef:
1190 BUILD(ReturnCallRef, sig_index, VectorOf(arg_nodes), null_check,
1191 decoder->position());
1192 }
1193 }
1194 };
1195
1196 } // namespace
1197
BuildTFGraph(AccountingAllocator * allocator,const WasmFeatures & enabled,const WasmModule * module,compiler::WasmGraphBuilder * builder,WasmFeatures * detected,const FunctionBody & body,compiler::NodeOriginTable * node_origins)1198 DecodeResult BuildTFGraph(AccountingAllocator* allocator,
1199 const WasmFeatures& enabled, const WasmModule* module,
1200 compiler::WasmGraphBuilder* builder,
1201 WasmFeatures* detected, const FunctionBody& body,
1202 compiler::NodeOriginTable* node_origins) {
1203 Zone zone(allocator, ZONE_NAME);
1204 WasmFullDecoder<Decoder::kFullValidation, WasmGraphBuildingInterface> decoder(
1205 &zone, module, enabled, detected, body, builder);
1206 if (node_origins) {
1207 builder->AddBytecodePositionDecorator(node_origins, &decoder);
1208 }
1209 decoder.Decode();
1210 if (node_origins) {
1211 builder->RemoveBytecodePositionDecorator();
1212 }
1213 return decoder.toResult(nullptr);
1214 }
1215
1216 #undef BUILD
1217
1218 } // namespace wasm
1219 } // namespace internal
1220 } // namespace v8
1221