Line data Source code
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.h"
9 : #include "src/handles.h"
10 : #include "src/objects-inl.h"
11 : #include "src/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/wasm-limits.h"
16 : #include "src/wasm/wasm-linkage.h"
17 : #include "src/wasm/wasm-module.h"
18 : #include "src/wasm/wasm-opcodes.h"
19 :
20 : namespace v8 {
21 : namespace internal {
22 : namespace wasm {
23 :
24 : namespace {
25 :
26 : // An SsaEnv environment carries the current local variable renaming
27 : // as well as the current effect and control dependency in the TF graph.
28 : // It maintains a control state that tracks whether the environment
29 : // is reachable, has reached a control end, or has been merged.
30 : struct SsaEnv {
31 : enum State { kControlEnd, kUnreachable, kReached, kMerged };
32 :
33 : State state;
34 : TFNode* control;
35 : TFNode* effect;
36 : compiler::WasmInstanceCacheNodes instance_cache;
37 : TFNode** locals;
38 :
39 : void Kill(State new_state = kControlEnd) {
40 968200 : state = new_state;
41 968200 : locals = nullptr;
42 968200 : control = nullptr;
43 968200 : effect = nullptr;
44 968200 : instance_cache = {};
45 : }
46 : void SetNotMerged() {
47 140458 : if (state == kMerged) state = kReached;
48 : }
49 : };
50 :
51 : #define BUILD(func, ...) \
52 : ([&] { \
53 : DCHECK(decoder->ok()); \
54 : return CheckForException(decoder, builder_->func(__VA_ARGS__)); \
55 : })()
56 :
57 : constexpr uint32_t kNullCatch = static_cast<uint32_t>(-1);
58 :
59 : class WasmGraphBuildingInterface {
60 : public:
61 : static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
62 : using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>;
63 :
64 : struct Value : public ValueBase {
65 : TFNode* node = nullptr;
66 :
67 : template <typename... Args>
68 : explicit Value(Args&&... args) V8_NOEXCEPT
69 5140234 : : ValueBase(std::forward<Args>(args)...) {}
70 : };
71 :
72 : struct TryInfo : public ZoneObject {
73 : SsaEnv* catch_env;
74 : TFNode* exception = nullptr;
75 :
76 : bool might_throw() const { return exception != nullptr; }
77 :
78 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TryInfo);
79 :
80 497 : explicit TryInfo(SsaEnv* c) : catch_env(c) {}
81 : };
82 :
83 : struct Control : public ControlBase<Value> {
84 : SsaEnv* end_env = nullptr; // end environment for the construct.
85 : SsaEnv* false_env = nullptr; // false environment (only for if).
86 : TryInfo* try_info = nullptr; // information about try statements.
87 : int32_t previous_catch = -1; // previous Control with a catch.
88 :
89 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(Control);
90 :
91 : template <typename... Args>
92 : explicit Control(Args&&... args) V8_NOEXCEPT
93 844370 : : ControlBase(std::forward<Args>(args)...) {}
94 : };
95 :
96 : explicit WasmGraphBuildingInterface(compiler::WasmGraphBuilder* builder)
97 628238 : : builder_(builder) {}
98 :
99 628746 : void StartFunction(FullDecoder* decoder) {
100 : SsaEnv* ssa_env =
101 : reinterpret_cast<SsaEnv*>(decoder->zone()->New(sizeof(SsaEnv)));
102 : uint32_t num_locals = decoder->num_locals();
103 : uint32_t env_count = num_locals;
104 629338 : size_t size = sizeof(TFNode*) * env_count;
105 629338 : ssa_env->state = SsaEnv::kReached;
106 : ssa_env->locals =
107 : size > 0 ? reinterpret_cast<TFNode**>(decoder->zone()->New(size))
108 629338 : : nullptr;
109 :
110 : // The first '+ 1' is needed by TF Start node, the second '+ 1' is for the
111 : // instance parameter.
112 629335 : TFNode* start = builder_->Start(
113 1258670 : static_cast<int>(decoder->sig_->parameter_count() + 1 + 1));
114 628135 : ssa_env->effect = start;
115 628135 : ssa_env->control = start;
116 : // Initialize effect and control before initializing the locals default
117 : // values (which might require instance loads) or loading the context.
118 628135 : builder_->set_effect_ptr(&ssa_env->effect);
119 628135 : builder_->set_control_ptr(&ssa_env->control);
120 : // Initialize the instance parameter (index 0).
121 628135 : builder_->set_instance_node(builder_->Param(kWasmInstanceParameterIndex));
122 : // Initialize local variables. Parameters are shifted by 1 because of the
123 : // the instance parameter.
124 : uint32_t index = 0;
125 1106392 : for (; index < decoder->sig_->parameter_count(); ++index) {
126 238772 : ssa_env->locals[index] = builder_->Param(index + 1);
127 : }
128 650049 : while (index < num_locals) {
129 : ValueType type = decoder->GetLocalType(index);
130 21204 : TFNode* node = DefaultValue(type);
131 1089630 : while (index < num_locals && decoder->GetLocalType(index) == type) {
132 : // Do a whole run of like-typed locals at a time.
133 355438 : ssa_env->locals[index++] = node;
134 : }
135 : }
136 : LoadContextIntoSsa(ssa_env);
137 : SetEnv(ssa_env);
138 627568 : }
139 :
140 : // Reload the instance cache entries into the Ssa Environment.
141 : void LoadContextIntoSsa(SsaEnv* ssa_env) {
142 775122 : if (ssa_env) builder_->InitInstanceCache(&ssa_env->instance_cache);
143 : }
144 :
145 : void StartFunctionBody(FullDecoder* decoder, Control* block) {}
146 :
147 618916 : void FinishFunction(FullDecoder*) { builder_->PatchInStackCheckIfNeeded(); }
148 :
149 : void OnFirstError(FullDecoder*) {}
150 :
151 : void NextInstruction(FullDecoder*, WasmOpcode) {}
152 :
153 : void Block(FullDecoder* decoder, Control* block) {
154 : // The branch environment is the outer environment.
155 167221 : block->end_env = ssa_env_;
156 167221 : SetEnv(Steal(decoder->zone(), ssa_env_));
157 : }
158 :
159 9577 : void Loop(FullDecoder* decoder, Control* block) {
160 9577 : SsaEnv* finish_try_env = Steal(decoder->zone(), ssa_env_);
161 9573 : block->end_env = finish_try_env;
162 : // The continue environment is the inner environment.
163 9573 : SetEnv(PrepareForLoop(decoder, finish_try_env));
164 9574 : ssa_env_->SetNotMerged();
165 9574 : if (!decoder->ok()) return;
166 : // Wrap input merge into phis.
167 9641 : for (uint32_t i = 0; i < block->start_merge.arity; ++i) {
168 : Value& val = block->start_merge[i];
169 38 : val.node = builder_->Phi(val.type, 1, &val.node, block->end_env->control);
170 : }
171 : }
172 :
173 497 : void Try(FullDecoder* decoder, Control* block) {
174 497 : SsaEnv* outer_env = ssa_env_;
175 497 : SsaEnv* catch_env = Split(decoder, outer_env);
176 : // Mark catch environment as unreachable, since only accessable
177 : // through catch unwinding (i.e. landing pads).
178 497 : catch_env->state = SsaEnv::kUnreachable;
179 497 : SsaEnv* try_env = Steal(decoder->zone(), outer_env);
180 : SetEnv(try_env);
181 : TryInfo* try_info = new (decoder->zone()) TryInfo(catch_env);
182 497 : block->end_env = outer_env;
183 497 : block->try_info = try_info;
184 497 : block->previous_catch = current_catch_;
185 497 : current_catch_ = static_cast<int32_t>(decoder->control_depth() - 1);
186 497 : }
187 :
188 39149 : void If(FullDecoder* decoder, const Value& cond, Control* if_block) {
189 39149 : TFNode* if_true = nullptr;
190 39149 : TFNode* if_false = nullptr;
191 78296 : BUILD(BranchNoHint, cond.node, &if_true, &if_false);
192 39155 : SsaEnv* end_env = ssa_env_;
193 39155 : SsaEnv* false_env = Split(decoder, ssa_env_);
194 39149 : false_env->control = if_false;
195 39149 : SsaEnv* true_env = Steal(decoder->zone(), ssa_env_);
196 39148 : true_env->control = if_true;
197 39148 : if_block->end_env = end_env;
198 39148 : if_block->false_env = false_env;
199 : SetEnv(true_env);
200 39148 : }
201 :
202 : void FallThruTo(FullDecoder* decoder, Control* c) {
203 : DCHECK(!c->is_loop());
204 32924 : MergeValuesInto(decoder, c, &c->end_merge);
205 : }
206 :
207 212486 : void PopControl(FullDecoder* decoder, Control* block) {
208 : // A loop just continues with the end environment. There is no merge.
209 212486 : if (block->is_loop()) return;
210 : // Any other block falls through to the parent block.
211 203294 : if (block->reachable()) FallThruTo(decoder, block);
212 203311 : if (block->is_onearmed_if()) {
213 : // Merge the else branch into the end merge.
214 20459 : SetEnv(block->false_env);
215 20459 : MergeValuesInto(decoder, block, &block->end_merge);
216 : }
217 : // Now continue with the merged environment.
218 203310 : SetEnv(block->end_env);
219 : }
220 :
221 : void EndControl(FullDecoder* decoder, Control* block) { ssa_env_->Kill(); }
222 :
223 : void UnOp(FullDecoder* decoder, WasmOpcode opcode, const Value& value,
224 : Value* result) {
225 949585 : result->node = BUILD(Unop, opcode, value.node, decoder->position());
226 : }
227 :
228 : void BinOp(FullDecoder* decoder, WasmOpcode opcode, const Value& lhs,
229 : const Value& rhs, Value* result) {
230 3352266 : auto node = BUILD(Binop, opcode, lhs.node, rhs.node, decoder->position());
231 1117256 : if (result) result->node = node;
232 : }
233 :
234 : void I32Const(FullDecoder* decoder, Value* result, int32_t value) {
235 1952232 : result->node = builder_->Int32Constant(value);
236 : }
237 :
238 : void I64Const(FullDecoder* decoder, Value* result, int64_t value) {
239 50714 : result->node = builder_->Int64Constant(value);
240 : }
241 :
242 : void F32Const(FullDecoder* decoder, Value* result, float value) {
243 118483 : result->node = builder_->Float32Constant(value);
244 : }
245 :
246 : void F64Const(FullDecoder* decoder, Value* result, double value) {
247 125429 : result->node = builder_->Float64Constant(value);
248 : }
249 :
250 : void RefNull(FullDecoder* decoder, Value* result) {
251 109 : result->node = builder_->RefNull();
252 : }
253 :
254 : void Drop(FullDecoder* decoder, const Value& value) {}
255 :
256 644397 : void DoReturn(FullDecoder* decoder, Vector<Value> values) {
257 644584 : TFNode** nodes = GetNodes(values);
258 1289164 : BUILD(Return, static_cast<uint32_t>(values.size()), nodes);
259 644851 : }
260 :
261 : void GetLocal(FullDecoder* decoder, Value* result,
262 : const LocalIndexImmediate<validate>& imm) {
263 607253 : if (!ssa_env_->locals) return; // unreachable
264 607376 : result->node = ssa_env_->locals[imm.index];
265 : }
266 :
267 : void SetLocal(FullDecoder* decoder, const Value& value,
268 : const LocalIndexImmediate<validate>& imm) {
269 356752 : if (!ssa_env_->locals) return; // unreachable
270 356758 : ssa_env_->locals[imm.index] = value.node;
271 : }
272 :
273 : void TeeLocal(FullDecoder* decoder, const Value& value, Value* result,
274 : const LocalIndexImmediate<validate>& imm) {
275 98464 : result->node = value.node;
276 98464 : if (!ssa_env_->locals) return; // unreachable
277 98464 : ssa_env_->locals[imm.index] = value.node;
278 : }
279 :
280 : void GetGlobal(FullDecoder* decoder, Value* result,
281 : const GlobalIndexImmediate<validate>& imm) {
282 70783 : result->node = BUILD(GetGlobal, imm.index);
283 : }
284 :
285 : void SetGlobal(FullDecoder* decoder, const Value& value,
286 : const GlobalIndexImmediate<validate>& imm) {
287 35250 : BUILD(SetGlobal, imm.index, value.node);
288 : }
289 :
290 : void GetTable(FullDecoder* decoder, const Value& index, Value* result,
291 : const TableIndexImmediate<validate>& imm) {
292 198 : result->node = BUILD(GetTable, imm.index, index.node, decoder->position());
293 : }
294 :
295 : void SetTable(FullDecoder* decoder, const Value& index, const Value& value,
296 : const TableIndexImmediate<validate>& imm) {
297 129 : BUILD(SetTable, imm.index, index.node, value.node, decoder->position());
298 : }
299 :
300 : void Unreachable(FullDecoder* decoder) {
301 318489 : BUILD(Unreachable, decoder->position());
302 : }
303 :
304 856 : void Select(FullDecoder* decoder, const Value& cond, const Value& fval,
305 : const Value& tval, Value* result) {
306 : TFNode* controls[2];
307 1712 : BUILD(BranchNoHint, cond.node, &controls[0], &controls[1]);
308 1716 : TFNode* merge = BUILD(Merge, 2, controls);
309 855 : TFNode* vals[2] = {tval.node, fval.node};
310 1709 : TFNode* phi = BUILD(Phi, tval.type, 2, vals, merge);
311 858 : result->node = phi;
312 858 : ssa_env_->control = merge;
313 858 : }
314 :
315 347310 : void BrOrRet(FullDecoder* decoder, uint32_t depth) {
316 694620 : if (depth == decoder->control_depth() - 1) {
317 256 : uint32_t ret_count = static_cast<uint32_t>(decoder->sig_->return_count());
318 : TFNode** values =
319 : ret_count == 0 ? nullptr
320 400 : : GetNodes(decoder->stack_value(ret_count), ret_count);
321 512 : BUILD(Return, ret_count, values);
322 : } else {
323 : Br(decoder, decoder->control_at(depth));
324 : }
325 347257 : }
326 :
327 : void Br(FullDecoder* decoder, Control* target) {
328 370107 : MergeValuesInto(decoder, target, target->br_merge());
329 : }
330 :
331 130894 : void BrIf(FullDecoder* decoder, const Value& cond, uint32_t depth) {
332 130894 : SsaEnv* fenv = ssa_env_;
333 130894 : SsaEnv* tenv = Split(decoder, fenv);
334 130884 : fenv->SetNotMerged();
335 261768 : BUILD(BranchNoHint, cond.node, &tenv->control, &fenv->control);
336 130959 : SetEnv(tenv);
337 130959 : BrOrRet(decoder, depth);
338 130918 : SetEnv(fenv);
339 130918 : }
340 :
341 5318 : void BrTable(FullDecoder* decoder, const BranchTableImmediate<validate>& imm,
342 : const Value& key) {
343 5318 : if (imm.table_count == 0) {
344 : // Only a default target. Do the equivalent of br.
345 918 : uint32_t target = BranchTableIterator<validate>(decoder, imm).next();
346 459 : BrOrRet(decoder, target);
347 460 : return;
348 : }
349 :
350 4859 : SsaEnv* branch_env = ssa_env_;
351 : // Build branches to the various blocks based on the table.
352 9718 : TFNode* sw = BUILD(Switch, imm.table_count + 1, key.node);
353 :
354 4859 : SsaEnv* copy = Steal(decoder->zone(), branch_env);
355 : SetEnv(copy);
356 4863 : BranchTableIterator<validate> iterator(decoder, imm);
357 436003 : while (iterator.has_next()) {
358 215574 : uint32_t i = iterator.cur_index();
359 215574 : uint32_t target = iterator.next();
360 215573 : SetEnv(Split(decoder, copy));
361 215571 : ssa_env_->control =
362 431142 : (i == imm.table_count) ? BUILD(IfDefault, sw) : BUILD(IfValue, i, sw);
363 215571 : BrOrRet(decoder, target);
364 : }
365 : DCHECK(decoder->ok());
366 : SetEnv(branch_env);
367 : }
368 :
369 18195 : void Else(FullDecoder* decoder, Control* if_block) {
370 18195 : if (if_block->reachable()) {
371 : // Merge the if branch into the end merge.
372 15063 : MergeValuesInto(decoder, if_block, &if_block->end_merge);
373 : }
374 18194 : SetEnv(if_block->false_env);
375 18194 : }
376 :
377 : void LoadMem(FullDecoder* decoder, LoadType type,
378 : const MemoryAccessImmediate<validate>& imm, const Value& index,
379 : Value* result) {
380 : result->node =
381 486369 : BUILD(LoadMem, type.value_type(), type.mem_type(), index.node,
382 97355 : imm.offset, imm.alignment, decoder->position());
383 : }
384 :
385 : void StoreMem(FullDecoder* decoder, StoreType type,
386 : const MemoryAccessImmediate<validate>& imm, const Value& index,
387 : const Value& value) {
388 868951 : BUILD(StoreMem, type.mem_rep(), index.node, imm.offset, imm.alignment,
389 144878 : value.node, decoder->position(), type.value_type());
390 : }
391 :
392 : void CurrentMemoryPages(FullDecoder* decoder, Value* result) {
393 980 : result->node = BUILD(CurrentMemoryPages);
394 : }
395 :
396 1308 : void MemoryGrow(FullDecoder* decoder, const Value& value, Value* result) {
397 2616 : result->node = BUILD(MemoryGrow, value.node);
398 : // Always reload the instance cache after growing memory.
399 1309 : LoadContextIntoSsa(ssa_env_);
400 1310 : }
401 :
402 : void CallDirect(FullDecoder* decoder,
403 : const CallFunctionImmediate<validate>& imm,
404 : const Value args[], Value returns[]) {
405 141074 : DoCall(decoder, 0, nullptr, imm.sig, imm.index, args, returns);
406 : }
407 :
408 : void ReturnCall(FullDecoder* decoder,
409 : const CallFunctionImmediate<validate>& imm,
410 : const Value args[]) {
411 148 : DoReturnCall(decoder, 0, nullptr, imm.sig, imm.index, args);
412 : }
413 :
414 : void CallIndirect(FullDecoder* decoder, const Value& index,
415 : const CallIndirectImmediate<validate>& imm,
416 : const Value args[], Value returns[]) {
417 : DoCall(decoder, imm.table_index, index.node, imm.sig, imm.sig_index, args,
418 3857 : returns);
419 : }
420 :
421 : void ReturnCallIndirect(FullDecoder* decoder, const Value& index,
422 : const CallIndirectImmediate<validate>& imm,
423 : const Value args[]) {
424 : DoReturnCall(decoder, imm.table_index, index.node, imm.sig, imm.sig_index,
425 71 : args);
426 : }
427 :
428 4320 : void SimdOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
429 : Value* result) {
430 4320 : TFNode** inputs = GetNodes(args);
431 8640 : TFNode* node = BUILD(SimdOp, opcode, inputs);
432 4320 : if (result) result->node = node;
433 4320 : }
434 :
435 784 : void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode,
436 : const SimdLaneImmediate<validate> imm, Vector<Value> inputs,
437 : Value* result) {
438 784 : TFNode** nodes = GetNodes(inputs);
439 1568 : result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes);
440 784 : }
441 :
442 : void SimdShiftOp(FullDecoder* decoder, WasmOpcode opcode,
443 : const SimdShiftImmediate<validate> imm, const Value& input,
444 : Value* result) {
445 1272 : TFNode* inputs[] = {input.node};
446 2544 : result->node = BUILD(SimdShiftOp, opcode, imm.shift, inputs);
447 : }
448 :
449 : void Simd8x16ShuffleOp(FullDecoder* decoder,
450 : const Simd8x16ShuffleImmediate<validate>& imm,
451 : const Value& input0, const Value& input1,
452 : Value* result) {
453 13232 : TFNode* input_nodes[] = {input0.node, input1.node};
454 26464 : result->node = BUILD(Simd8x16ShuffleOp, imm.shuffle, input_nodes);
455 : }
456 :
457 547 : void Throw(FullDecoder* decoder, const ExceptionIndexImmediate<validate>& imm,
458 : const Vector<Value>& value_args) {
459 : int count = value_args.length();
460 547 : ZoneVector<TFNode*> args(count, decoder->zone());
461 1117 : for (int i = 0; i < count; ++i) {
462 568 : args[i] = value_args[i].node;
463 : }
464 1647 : BUILD(Throw, imm.index, imm.exception, VectorOf(args));
465 548 : builder_->TerminateThrow(ssa_env_->effect, ssa_env_->control);
466 549 : }
467 :
468 404 : void Rethrow(FullDecoder* decoder, const Value& exception) {
469 809 : BUILD(Rethrow, exception.node);
470 407 : builder_->TerminateThrow(ssa_env_->effect, ssa_env_->control);
471 406 : }
472 :
473 328 : void BrOnException(FullDecoder* decoder, const Value& exception,
474 : const ExceptionIndexImmediate<validate>& imm,
475 : uint32_t depth, Vector<Value> values) {
476 328 : TFNode* if_match = nullptr;
477 328 : TFNode* if_no_match = nullptr;
478 :
479 : // Get the exception tag and see if it matches the expected one.
480 656 : TFNode* caught_tag = BUILD(GetExceptionTag, exception.node);
481 660 : TFNode* exception_tag = BUILD(LoadExceptionTagFromTable, imm.index);
482 660 : TFNode* compare = BUILD(ExceptionTagEqual, caught_tag, exception_tag);
483 658 : BUILD(BranchNoHint, compare, &if_match, &if_no_match);
484 330 : SsaEnv* if_no_match_env = Split(decoder, ssa_env_);
485 329 : SsaEnv* if_match_env = Steal(decoder->zone(), ssa_env_);
486 328 : if_no_match_env->control = if_no_match;
487 328 : if_match_env->control = if_match;
488 :
489 : // If the tags match we extract the values from the exception object and
490 : // push them onto the operand stack using the passed {values} vector.
491 : SetEnv(if_match_env);
492 : // TODO(mstarzinger): Can't use BUILD() here, GetExceptionValues() returns
493 : // TFNode** rather than TFNode*. Fix to add landing pads.
494 : TFNode** caught_values =
495 328 : builder_->GetExceptionValues(exception.node, imm.exception);
496 748 : for (size_t i = 0, e = values.size(); i < e; ++i) {
497 209 : values[i].node = caught_values[i];
498 : }
499 330 : BrOrRet(decoder, depth);
500 :
501 : // If the tags don't match we fall-through here.
502 : SetEnv(if_no_match_env);
503 330 : }
504 :
505 : void Catch(FullDecoder* decoder, Control* block, Value* exception) {
506 : DCHECK(block->is_try_catch());
507 :
508 501 : current_catch_ = block->previous_catch; // Pop try scope.
509 :
510 : // The catch block is unreachable if no possible throws in the try block
511 : // exist. We only build a landing pad if some node in the try block can
512 : // (possibly) throw. Otherwise the catch environments remain empty.
513 501 : if (!block->try_info->might_throw()) {
514 11 : block->reachability = kSpecOnlyReachable;
515 : return;
516 : }
517 :
518 490 : SetEnv(block->try_info->catch_env);
519 : DCHECK_NOT_NULL(block->try_info->exception);
520 490 : exception->node = block->try_info->exception;
521 : }
522 :
523 33135 : void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
524 : const MemoryAccessImmediate<validate>& imm, Value* result) {
525 33141 : TFNode** inputs = GetNodes(args);
526 99399 : TFNode* node = BUILD(AtomicOp, opcode, inputs, imm.alignment, imm.offset,
527 : decoder->position());
528 33780 : if (result) result->node = node;
529 33780 : }
530 :
531 : void MemoryInit(FullDecoder* decoder,
532 : const MemoryInitImmediate<validate>& imm, const Value& dst,
533 : const Value& src, const Value& size) {
534 304 : BUILD(MemoryInit, imm.data_segment_index, dst.node, src.node, size.node,
535 76 : decoder->position());
536 : }
537 : void DataDrop(FullDecoder* decoder, const DataDropImmediate<validate>& imm) {
538 147 : BUILD(DataDrop, imm.index, decoder->position());
539 : }
540 : void MemoryCopy(FullDecoder* decoder,
541 : const MemoryCopyImmediate<validate>& imm, const Value& dst,
542 : const Value& src, const Value& size) {
543 129 : BUILD(MemoryCopy, dst.node, src.node, size.node, decoder->position());
544 : }
545 : void MemoryFill(FullDecoder* decoder,
546 : const MemoryIndexImmediate<validate>& imm, const Value& dst,
547 : const Value& value, const Value& size) {
548 129 : BUILD(MemoryFill, dst.node, value.node, size.node, decoder->position());
549 : }
550 : void TableInit(FullDecoder* decoder, const TableInitImmediate<validate>& imm,
551 : Vector<Value> args) {
552 96 : BUILD(TableInit, imm.table.index, imm.elem_segment_index, args[0].node,
553 24 : args[1].node, args[2].node, decoder->position());
554 : }
555 : void ElemDrop(FullDecoder* decoder, const ElemDropImmediate<validate>& imm) {
556 81 : BUILD(ElemDrop, imm.index, decoder->position());
557 : }
558 : void TableCopy(FullDecoder* decoder, const TableCopyImmediate<validate>& imm,
559 : Vector<Value> args) {
560 204 : BUILD(TableCopy, imm.table_src.index, imm.table_dst.index, args[0].node,
561 51 : args[1].node, args[2].node, decoder->position());
562 : }
563 :
564 : private:
565 : SsaEnv* ssa_env_;
566 : compiler::WasmGraphBuilder* builder_;
567 : uint32_t current_catch_ = kNullCatch;
568 :
569 : TryInfo* current_try_info(FullDecoder* decoder) {
570 609 : return decoder->control_at(decoder->control_depth() - 1 - current_catch_)
571 609 : ->try_info;
572 : }
573 :
574 682734 : TFNode** GetNodes(Value* values, size_t count) {
575 682734 : TFNode** nodes = builder_->Buffer(count);
576 1842457 : for (size_t i = 0; i < count; ++i) {
577 579803 : nodes[i] = values[i].node;
578 : }
579 682851 : return nodes;
580 : }
581 :
582 : TFNode** GetNodes(Vector<Value> values) {
583 682636 : return GetNodes(values.start(), values.size());
584 : }
585 :
586 : void SetEnv(SsaEnv* env) {
587 : #if DEBUG
588 : if (FLAG_trace_wasm_decoder) {
589 : char state = 'X';
590 : if (env) {
591 : switch (env->state) {
592 : case SsaEnv::kReached:
593 : state = 'R';
594 : break;
595 : case SsaEnv::kUnreachable:
596 : state = 'U';
597 : break;
598 : case SsaEnv::kMerged:
599 : state = 'M';
600 : break;
601 : case SsaEnv::kControlEnd:
602 : state = 'E';
603 : break;
604 : }
605 : }
606 : PrintF("{set_env = %p, state = %c", static_cast<void*>(env), state);
607 : if (env && env->control) {
608 : PrintF(", control = ");
609 : compiler::WasmGraphBuilder::PrintDebugName(env->control);
610 : }
611 : PrintF("}\n");
612 : }
613 : #endif
614 1574877 : ssa_env_ = env;
615 : // TODO(wasm): combine the control and effect pointers with instance cache.
616 1574877 : builder_->set_control_ptr(&env->control);
617 1574877 : builder_->set_effect_ptr(&env->effect);
618 1574877 : builder_->set_instance_cache(&env->instance_cache);
619 : }
620 :
621 3075486 : TFNode* CheckForException(FullDecoder* decoder, TFNode* node) {
622 3075486 : if (node == nullptr) return nullptr;
623 :
624 2969117 : const bool inside_try_scope = current_catch_ != kNullCatch;
625 :
626 2969117 : if (!inside_try_scope) return node;
627 :
628 1193 : TFNode* if_success = nullptr;
629 1193 : TFNode* if_exception = nullptr;
630 1193 : if (!builder_->ThrowsException(node, &if_success, &if_exception)) {
631 : return node;
632 : }
633 :
634 610 : SsaEnv* success_env = Steal(decoder->zone(), ssa_env_);
635 609 : success_env->control = if_success;
636 :
637 609 : SsaEnv* exception_env = Split(decoder, success_env);
638 609 : exception_env->control = if_exception;
639 : TryInfo* try_info = current_try_info(decoder);
640 609 : Goto(decoder, exception_env, try_info->catch_env);
641 609 : TFNode* exception = try_info->exception;
642 609 : if (exception == nullptr) {
643 : DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state);
644 488 : try_info->exception = if_exception;
645 : } else {
646 : DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state);
647 242 : try_info->exception = builder_->CreateOrMergeIntoPhi(
648 121 : MachineRepresentation::kWord32, try_info->catch_env->control,
649 121 : try_info->exception, if_exception);
650 : }
651 :
652 : SetEnv(success_env);
653 609 : return node;
654 : }
655 :
656 21204 : TFNode* DefaultValue(ValueType type) {
657 21204 : switch (type) {
658 : case kWasmI32:
659 10391 : return builder_->Int32Constant(0);
660 : case kWasmI64:
661 6717 : return builder_->Int64Constant(0);
662 : case kWasmF32:
663 476 : return builder_->Float32Constant(0);
664 : case kWasmF64:
665 1299 : return builder_->Float64Constant(0);
666 : case kWasmS128:
667 2178 : return builder_->S128Zero();
668 : case kWasmAnyRef:
669 : case kWasmAnyFunc:
670 : case kWasmExceptRef:
671 143 : return builder_->RefNull();
672 : default:
673 0 : UNREACHABLE();
674 : }
675 : }
676 :
677 438487 : void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge) {
678 : DCHECK(merge == &c->start_merge || merge == &c->end_merge);
679 :
680 438487 : SsaEnv* target = c->end_env;
681 438487 : const bool first = target->state == SsaEnv::kUnreachable;
682 438487 : Goto(decoder, ssa_env_, target);
683 :
684 438484 : if (merge->arity == 0) return;
685 :
686 : uint32_t avail =
687 17198 : decoder->stack_size() - decoder->control_at(0)->stack_depth;
688 : DCHECK_GE(avail, merge->arity);
689 17198 : uint32_t start = avail >= merge->arity ? 0 : merge->arity - avail;
690 : Value* stack_values = decoder->stack_value(merge->arity);
691 51790 : for (uint32_t i = start; i < merge->arity; ++i) {
692 17291 : Value& val = stack_values[i];
693 : Value& old = (*merge)[i];
694 : DCHECK_NOT_NULL(val.node);
695 : DCHECK(val.type == old.type || val.type == kWasmVar);
696 : old.node = first ? val.node
697 14068 : : builder_->CreateOrMergeIntoPhi(
698 7034 : ValueTypes::MachineRepresentationFor(old.type),
699 24327 : target->control, old.node, val.node);
700 : }
701 : }
702 :
703 439122 : void Goto(FullDecoder* decoder, SsaEnv* from, SsaEnv* to) {
704 : DCHECK_NOT_NULL(to);
705 439122 : switch (to->state) {
706 : case SsaEnv::kUnreachable: { // Overwrite destination.
707 190732 : to->state = SsaEnv::kReached;
708 190732 : to->locals = from->locals;
709 190732 : to->control = from->control;
710 190732 : to->effect = from->effect;
711 190732 : to->instance_cache = from->instance_cache;
712 : break;
713 : }
714 : case SsaEnv::kReached: { // Create a new merge.
715 34704 : to->state = SsaEnv::kMerged;
716 : // Merge control.
717 34704 : TFNode* controls[] = {to->control, from->control};
718 34704 : TFNode* merge = builder_->Merge(2, controls);
719 34697 : to->control = merge;
720 : // Merge effects.
721 34697 : if (from->effect != to->effect) {
722 22106 : TFNode* effects[] = {to->effect, from->effect, merge};
723 22106 : to->effect = builder_->EffectPhi(2, effects, merge);
724 : }
725 : // Merge SSA values.
726 720361 : for (int i = decoder->num_locals() - 1; i >= 0; i--) {
727 685661 : TFNode* a = to->locals[i];
728 685661 : TFNode* b = from->locals[i];
729 685661 : if (a != b) {
730 60532 : TFNode* vals[] = {a, b};
731 : to->locals[i] =
732 121064 : builder_->Phi(decoder->GetLocalType(i), 2, vals, merge);
733 : }
734 : }
735 : // Start a new merge from the instance cache.
736 34700 : builder_->NewInstanceCacheMerge(&to->instance_cache,
737 34700 : &from->instance_cache, merge);
738 : break;
739 : }
740 : case SsaEnv::kMerged: {
741 213686 : TFNode* merge = to->control;
742 : // Extend the existing merge control node.
743 213686 : builder_->AppendToMerge(merge, from->control);
744 : // Merge effects.
745 213683 : to->effect = builder_->CreateOrMergeIntoEffectPhi(merge, to->effect,
746 213690 : from->effect);
747 : // Merge locals.
748 772829 : for (int i = decoder->num_locals() - 1; i >= 0; i--) {
749 2236576 : to->locals[i] = builder_->CreateOrMergeIntoPhi(
750 559144 : ValueTypes::MachineRepresentationFor(decoder->GetLocalType(i)),
751 1677427 : merge, to->locals[i], from->locals[i]);
752 : }
753 : // Merge the instance caches.
754 213685 : builder_->MergeInstanceCacheInto(&to->instance_cache,
755 213685 : &from->instance_cache, merge);
756 : break;
757 : }
758 : default:
759 0 : UNREACHABLE();
760 : }
761 439114 : return from->Kill();
762 : }
763 :
764 9573 : SsaEnv* PrepareForLoop(FullDecoder* decoder, SsaEnv* env) {
765 9573 : env->state = SsaEnv::kMerged;
766 :
767 9573 : env->control = builder_->Loop(env->control);
768 9574 : env->effect = builder_->EffectPhi(1, &env->effect, env->control);
769 9578 : builder_->TerminateLoop(env->effect, env->control);
770 : // The '+ 1' here is to be able to set the instance cache as assigned.
771 9578 : BitVector* assigned = WasmDecoder<validate>::AnalyzeLoopAssignment(
772 9578 : decoder, decoder->pc(), decoder->total_locals() + 1, decoder->zone());
773 9574 : if (decoder->failed()) return env;
774 9568 : if (assigned != nullptr) {
775 : // Only introduce phis for variables assigned in this loop.
776 9568 : int instance_cache_index = decoder->total_locals();
777 185652 : for (int i = decoder->num_locals() - 1; i >= 0; i--) {
778 176089 : if (!assigned->Contains(i)) continue;
779 73812 : env->locals[i] = builder_->Phi(decoder->GetLocalType(i), 1,
780 36901 : &env->locals[i], env->control);
781 : }
782 : // Introduce phis for instance cache pointers if necessary.
783 9563 : if (assigned->Contains(instance_cache_index)) {
784 4381 : builder_->PrepareInstanceCacheForLoop(&env->instance_cache,
785 4381 : env->control);
786 : }
787 :
788 9563 : SsaEnv* loop_body_env = Split(decoder, env);
789 19126 : builder_->StackCheck(decoder->position(), &(loop_body_env->effect),
790 9563 : &(loop_body_env->control));
791 : return loop_body_env;
792 : }
793 :
794 : // Conservatively introduce phis for all local variables.
795 0 : for (int i = decoder->num_locals() - 1; i >= 0; i--) {
796 0 : env->locals[i] = builder_->Phi(decoder->GetLocalType(i), 1,
797 0 : &env->locals[i], env->control);
798 : }
799 :
800 : // Conservatively introduce phis for instance cache.
801 0 : builder_->PrepareInstanceCacheForLoop(&env->instance_cache, env->control);
802 :
803 0 : SsaEnv* loop_body_env = Split(decoder, env);
804 0 : builder_->StackCheck(decoder->position(), &loop_body_env->effect,
805 0 : &loop_body_env->control);
806 : return loop_body_env;
807 : }
808 :
809 : // Create a complete copy of {from}.
810 396599 : SsaEnv* Split(FullDecoder* decoder, SsaEnv* from) {
811 : DCHECK_NOT_NULL(from);
812 : SsaEnv* result =
813 : reinterpret_cast<SsaEnv*>(decoder->zone()->New(sizeof(SsaEnv)));
814 396606 : size_t size = sizeof(TFNode*) * decoder->num_locals();
815 396606 : result->control = from->control;
816 396606 : result->effect = from->effect;
817 :
818 396606 : result->state = SsaEnv::kReached;
819 396606 : if (size > 0) {
820 287477 : result->locals = reinterpret_cast<TFNode**>(decoder->zone()->New(size));
821 287480 : memcpy(result->locals, from->locals, size);
822 : } else {
823 109129 : result->locals = nullptr;
824 : }
825 396609 : result->instance_cache = from->instance_cache;
826 :
827 396609 : return result;
828 : }
829 :
830 : // Create a copy of {from} that steals its state and leaves {from}
831 : // unreachable.
832 222226 : SsaEnv* Steal(Zone* zone, SsaEnv* from) {
833 : DCHECK_NOT_NULL(from);
834 : SsaEnv* result = reinterpret_cast<SsaEnv*>(zone->New(sizeof(SsaEnv)));
835 222226 : result->state = SsaEnv::kReached;
836 222226 : result->locals = from->locals;
837 222226 : result->control = from->control;
838 222226 : result->effect = from->effect;
839 222226 : result->instance_cache = from->instance_cache;
840 : from->Kill(SsaEnv::kUnreachable);
841 222226 : return result;
842 : }
843 :
844 : // Create an unreachable environment.
845 : SsaEnv* UnreachableEnv(Zone* zone) {
846 : SsaEnv* result = reinterpret_cast<SsaEnv*>(zone->New(sizeof(SsaEnv)));
847 : result->state = SsaEnv::kUnreachable;
848 : result->control = nullptr;
849 : result->effect = nullptr;
850 : result->locals = nullptr;
851 : result->instance_cache = {};
852 : return result;
853 : }
854 :
855 144875 : void DoCall(FullDecoder* decoder, uint32_t table_index, TFNode* index_node,
856 : FunctionSig* sig, uint32_t sig_index, const Value args[],
857 : Value returns[]) {
858 144875 : int param_count = static_cast<int>(sig->parameter_count());
859 144875 : TFNode** arg_nodes = builder_->Buffer(param_count + 1);
860 144919 : TFNode** return_nodes = nullptr;
861 144919 : arg_nodes[0] = index_node;
862 749263 : for (int i = 0; i < param_count; ++i) {
863 302172 : arg_nodes[i + 1] = args[i].node;
864 : }
865 144919 : if (index_node) {
866 15435 : BUILD(CallIndirect, table_index, sig_index, arg_nodes, &return_nodes,
867 3857 : decoder->position());
868 : } else {
869 564284 : BUILD(CallDirect, sig_index, arg_nodes, &return_nodes,
870 141062 : decoder->position());
871 : }
872 144968 : int return_count = static_cast<int>(sig->return_count());
873 397872 : for (int i = 0; i < return_count; ++i) {
874 126452 : returns[i].node = return_nodes[i];
875 : }
876 : // The invoked function could have used grow_memory, so we need to
877 : // reload mem_size and mem_start.
878 144968 : LoadContextIntoSsa(ssa_env_);
879 145037 : }
880 :
881 219 : void DoReturnCall(FullDecoder* decoder, uint32_t table_index,
882 : TFNode* index_node, FunctionSig* sig, uint32_t sig_index,
883 : const Value args[]) {
884 219 : int arg_count = static_cast<int>(sig->parameter_count());
885 219 : TFNode** arg_nodes = builder_->Buffer(arg_count + 1);
886 219 : arg_nodes[0] = index_node;
887 1185 : for (int i = 0; i < arg_count; ++i) {
888 483 : arg_nodes[i + 1] = args[i].node;
889 : }
890 219 : if (index_node) {
891 284 : BUILD(ReturnCallIndirect, table_index, sig_index, arg_nodes,
892 71 : decoder->position());
893 : } else {
894 444 : BUILD(ReturnCall, sig_index, arg_nodes, decoder->position());
895 : }
896 218 : }
897 : };
898 :
899 : } // namespace
900 :
901 628434 : DecodeResult BuildTFGraph(AccountingAllocator* allocator,
902 : const WasmFeatures& enabled, const WasmModule* module,
903 : compiler::WasmGraphBuilder* builder,
904 : WasmFeatures* detected, const FunctionBody& body,
905 : compiler::NodeOriginTable* node_origins) {
906 1256316 : Zone zone(allocator, ZONE_NAME);
907 : WasmFullDecoder<Decoder::kValidate, WasmGraphBuildingInterface> decoder(
908 : &zone, module, enabled, detected, body, builder);
909 628238 : if (node_origins) {
910 8 : builder->AddBytecodePositionDecorator(node_origins, &decoder);
911 : }
912 628238 : decoder.Decode();
913 627357 : if (node_origins) {
914 8 : builder->RemoveBytecodePositionDecorator();
915 : }
916 1884865 : return decoder.toResult(nullptr);
917 : }
918 :
919 : #undef BUILD
920 :
921 : } // namespace wasm
922 : } // namespace internal
923 121996 : } // namespace v8
|