V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
graph-builder-interface.cc
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  bool reached() const { return state >= kReached; }
40  void Kill(State new_state = kControlEnd) {
41  state = new_state;
42  locals = nullptr;
43  control = nullptr;
44  effect = nullptr;
45  instance_cache = {};
46  }
47  void SetNotMerged() {
48  if (state == kMerged) state = kReached;
49  }
50 };
51 
52 #define BUILD(func, ...) \
53  ([&] { \
54  DCHECK(ssa_env_->reached()); \
55  DCHECK(decoder->ok()); \
56  return CheckForException(decoder, builder_->func(__VA_ARGS__)); \
57  })()
58 
59 constexpr uint32_t kNullCatch = static_cast<uint32_t>(-1);
60 
61 class WasmGraphBuildingInterface {
62  public:
63  static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
64  using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>;
65 
66  struct Value : public ValueWithNamedConstructors<Value> {
67  TFNode* node;
68  };
69 
70  struct TryInfo : public ZoneObject {
71  SsaEnv* catch_env;
72  TFNode* exception = nullptr;
73 
74  explicit TryInfo(SsaEnv* c) : catch_env(c) {}
75  };
76 
77  struct Control : public ControlWithNamedConstructors<Control, Value> {
78  SsaEnv* end_env; // end environment for the construct.
79  SsaEnv* false_env; // false environment (only for if).
80  TryInfo* try_info; // information used for compiling try statements.
81  int32_t previous_catch; // previous Control (on the stack) with a catch.
82  };
83 
84  explicit WasmGraphBuildingInterface(compiler::WasmGraphBuilder* builder)
85  : builder_(builder) {}
86 
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  ssa_env->effect = start;
103  ssa_env->control = start;
104  // Initialize effect and control before initializing the locals default
105  // values (which might require instance loads) or loading the context.
106  builder_->set_effect_ptr(&ssa_env->effect);
107  builder_->set_control_ptr(&ssa_env->control);
108  // Initialize the instance parameter (index 0).
109  builder_->set_instance_node(builder_->Param(kWasmInstanceParameterIndex));
110  // Initialize local variables. Parameters are shifted by 1 because of the
111  // the instance parameter.
112  uint32_t index = 0;
113  for (; index < decoder->sig_->parameter_count(); ++index) {
114  ssa_env->locals[index] = builder_->Param(index + 1);
115  }
116  while (index < num_locals) {
117  ValueType type = decoder->GetLocalType(index);
118  TFNode* node = DefaultValue(type);
119  while (index < num_locals && decoder->GetLocalType(index) == type) {
120  // Do a whole run of like-typed locals at a time.
121  ssa_env->locals[index++] = node;
122  }
123  }
124  LoadContextIntoSsa(ssa_env);
125  SetEnv(ssa_env);
126  }
127 
128  // Reload the instance cache entries into the Ssa Environment.
129  void LoadContextIntoSsa(SsaEnv* ssa_env) {
130  if (!ssa_env || !ssa_env->reached()) return;
131  builder_->InitInstanceCache(&ssa_env->instance_cache);
132  }
133 
134  void StartFunctionBody(FullDecoder* decoder, Control* block) {
135  SsaEnv* break_env = ssa_env_;
136  SetEnv(Steal(decoder->zone(), break_env));
137  block->end_env = break_env;
138  }
139 
140  void FinishFunction(FullDecoder*) { builder_->PatchInStackCheckIfNeeded(); }
141 
142  void OnFirstError(FullDecoder*) {}
143 
144  void NextInstruction(FullDecoder*, WasmOpcode) {}
145 
146  void Block(FullDecoder* decoder, Control* block) {
147  // The break environment is the outer environment.
148  block->end_env = ssa_env_;
149  SetEnv(Steal(decoder->zone(), ssa_env_));
150  }
151 
152  void Loop(FullDecoder* decoder, Control* block) {
153  SsaEnv* finish_try_env = Steal(decoder->zone(), ssa_env_);
154  block->end_env = finish_try_env;
155  // The continue environment is the inner environment.
156  SetEnv(PrepareForLoop(decoder, finish_try_env));
157  ssa_env_->SetNotMerged();
158  if (!decoder->ok()) return;
159  // Wrap input merge into phis.
160  for (uint32_t i = 0; i < block->start_merge.arity; ++i) {
161  Value& val = block->start_merge[i];
162  val.node = builder_->Phi(val.type, 1, &val.node, block->end_env->control);
163  }
164  }
165 
166  void Try(FullDecoder* decoder, Control* block) {
167  SsaEnv* outer_env = ssa_env_;
168  SsaEnv* catch_env = Split(decoder, outer_env);
169  // Mark catch environment as unreachable, since only accessable
170  // through catch unwinding (i.e. landing pads).
171  catch_env->state = SsaEnv::kUnreachable;
172  SsaEnv* try_env = Steal(decoder->zone(), outer_env);
173  SetEnv(try_env);
174  TryInfo* try_info = new (decoder->zone()) TryInfo(catch_env);
175  block->end_env = outer_env;
176  block->try_info = try_info;
177  block->previous_catch = current_catch_;
178  current_catch_ = static_cast<int32_t>(decoder->control_depth() - 1);
179  }
180 
181  void If(FullDecoder* decoder, const Value& cond, Control* if_block) {
182  TFNode* if_true = nullptr;
183  TFNode* if_false = nullptr;
184  if (ssa_env_->reached()) {
185  BUILD(BranchNoHint, cond.node, &if_true, &if_false);
186  }
187  SsaEnv* end_env = ssa_env_;
188  SsaEnv* false_env = Split(decoder, ssa_env_);
189  false_env->control = if_false;
190  SsaEnv* true_env = Steal(decoder->zone(), ssa_env_);
191  true_env->control = if_true;
192  if_block->end_env = end_env;
193  if_block->false_env = false_env;
194  SetEnv(true_env);
195  }
196 
197  void FallThruTo(FullDecoder* decoder, Control* c) {
198  DCHECK(!c->is_loop());
199  MergeValuesInto(decoder, c, &c->end_merge);
200  }
201 
202  void PopControl(FullDecoder* decoder, Control* block) {
203  if (!block->is_loop()) SetEnv(block->end_env);
204  }
205 
206  void EndControl(FullDecoder* decoder, Control* block) { ssa_env_->Kill(); }
207 
208  void UnOp(FullDecoder* decoder, WasmOpcode opcode, FunctionSig* sig,
209  const Value& value, Value* result) {
210  result->node = BUILD(Unop, opcode, value.node, decoder->position());
211  }
212 
213  void BinOp(FullDecoder* decoder, WasmOpcode opcode, FunctionSig* sig,
214  const Value& lhs, const Value& rhs, Value* result) {
215  auto node = BUILD(Binop, opcode, lhs.node, rhs.node, decoder->position());
216  if (result) result->node = node;
217  }
218 
219  void I32Const(FullDecoder* decoder, Value* result, int32_t value) {
220  result->node = builder_->Int32Constant(value);
221  }
222 
223  void I64Const(FullDecoder* decoder, Value* result, int64_t value) {
224  result->node = builder_->Int64Constant(value);
225  }
226 
227  void F32Const(FullDecoder* decoder, Value* result, float value) {
228  result->node = builder_->Float32Constant(value);
229  }
230 
231  void F64Const(FullDecoder* decoder, Value* result, double value) {
232  result->node = builder_->Float64Constant(value);
233  }
234 
235  void RefNull(FullDecoder* decoder, Value* result) {
236  result->node = builder_->RefNull();
237  }
238 
239  void Drop(FullDecoder* decoder, const Value& value) {}
240 
241  void DoReturn(FullDecoder* decoder, Vector<Value> values, bool implicit) {
242  if (implicit) {
243  DCHECK_EQ(1, decoder->control_depth());
244  SetEnv(decoder->control_at(0)->end_env);
245  }
246  size_t num_values = values.size();
247  TFNode** buffer = GetNodes(values);
248  for (size_t i = 0; i < num_values; ++i) {
249  buffer[i] = values[i].node;
250  }
251  BUILD(Return, static_cast<uint32_t>(values.size()), buffer);
252  }
253 
254  void GetLocal(FullDecoder* decoder, Value* result,
255  const LocalIndexImmediate<validate>& imm) {
256  if (!ssa_env_->locals) return; // unreachable
257  result->node = ssa_env_->locals[imm.index];
258  }
259 
260  void SetLocal(FullDecoder* decoder, const Value& value,
261  const LocalIndexImmediate<validate>& imm) {
262  if (!ssa_env_->locals) return; // unreachable
263  ssa_env_->locals[imm.index] = value.node;
264  }
265 
266  void TeeLocal(FullDecoder* decoder, const Value& value, Value* result,
267  const LocalIndexImmediate<validate>& imm) {
268  result->node = value.node;
269  if (!ssa_env_->locals) return; // unreachable
270  ssa_env_->locals[imm.index] = value.node;
271  }
272 
273  void GetGlobal(FullDecoder* decoder, Value* result,
274  const GlobalIndexImmediate<validate>& imm) {
275  result->node = BUILD(GetGlobal, imm.index);
276  }
277 
278  void SetGlobal(FullDecoder* decoder, const Value& value,
279  const GlobalIndexImmediate<validate>& imm) {
280  BUILD(SetGlobal, imm.index, value.node);
281  }
282 
283  void Unreachable(FullDecoder* decoder) {
284  BUILD(Unreachable, decoder->position());
285  }
286 
287  void Select(FullDecoder* decoder, const Value& cond, const Value& fval,
288  const Value& tval, Value* result) {
289  TFNode* controls[2];
290  BUILD(BranchNoHint, cond.node, &controls[0], &controls[1]);
291  TFNode* merge = BUILD(Merge, 2, controls);
292  TFNode* vals[2] = {tval.node, fval.node};
293  TFNode* phi = BUILD(Phi, tval.type, 2, vals, merge);
294  result->node = phi;
295  ssa_env_->control = merge;
296  }
297 
298  void Br(FullDecoder* decoder, Control* target) {
299  MergeValuesInto(decoder, target, target->br_merge());
300  }
301 
302  void BrIf(FullDecoder* decoder, const Value& cond, Control* target) {
303  SsaEnv* fenv = ssa_env_;
304  SsaEnv* tenv = Split(decoder, fenv);
305  fenv->SetNotMerged();
306  BUILD(BranchNoHint, cond.node, &tenv->control, &fenv->control);
307  ssa_env_ = tenv;
308  Br(decoder, target);
309  ssa_env_ = fenv;
310  }
311 
312  void BrTable(FullDecoder* decoder, const BranchTableImmediate<validate>& imm,
313  const Value& key) {
314  if (imm.table_count == 0) {
315  // Only a default target. Do the equivalent of br.
316  uint32_t target = BranchTableIterator<validate>(decoder, imm).next();
317  Br(decoder, decoder->control_at(target));
318  return;
319  }
320 
321  SsaEnv* break_env = ssa_env_;
322  // Build branches to the various blocks based on the table.
323  TFNode* sw = BUILD(Switch, imm.table_count + 1, key.node);
324 
325  SsaEnv* copy = Steal(decoder->zone(), break_env);
326  ssa_env_ = copy;
327  BranchTableIterator<validate> iterator(decoder, imm);
328  while (iterator.has_next()) {
329  uint32_t i = iterator.cur_index();
330  uint32_t target = iterator.next();
331  ssa_env_ = Split(decoder, copy);
332  ssa_env_->control =
333  (i == imm.table_count) ? BUILD(IfDefault, sw) : BUILD(IfValue, i, sw);
334  Br(decoder, decoder->control_at(target));
335  }
336  DCHECK(decoder->ok());
337  ssa_env_ = break_env;
338  }
339 
340  void Else(FullDecoder* decoder, Control* if_block) {
341  SetEnv(if_block->false_env);
342  }
343 
344  void LoadMem(FullDecoder* decoder, LoadType type,
345  const MemoryAccessImmediate<validate>& imm, const Value& index,
346  Value* result) {
347  result->node =
348  BUILD(LoadMem, type.value_type(), type.mem_type(), index.node,
349  imm.offset, imm.alignment, decoder->position());
350  }
351 
352  void StoreMem(FullDecoder* decoder, StoreType type,
353  const MemoryAccessImmediate<validate>& imm, const Value& index,
354  const Value& value) {
355  BUILD(StoreMem, type.mem_rep(), index.node, imm.offset, imm.alignment,
356  value.node, decoder->position(), type.value_type());
357  }
358 
359  void CurrentMemoryPages(FullDecoder* decoder, Value* result) {
360  result->node = BUILD(CurrentMemoryPages);
361  }
362 
363  void MemoryGrow(FullDecoder* decoder, const Value& value, Value* result) {
364  result->node = BUILD(MemoryGrow, value.node);
365  // Always reload the instance cache after growing memory.
366  LoadContextIntoSsa(ssa_env_);
367  }
368 
369  void CallDirect(FullDecoder* decoder,
370  const CallFunctionImmediate<validate>& imm,
371  const Value args[], Value returns[]) {
372  DoCall(decoder, nullptr, imm.sig, imm.index, args, returns);
373  }
374 
375  void CallIndirect(FullDecoder* decoder, const Value& index,
376  const CallIndirectImmediate<validate>& imm,
377  const Value args[], Value returns[]) {
378  DoCall(decoder, index.node, imm.sig, imm.sig_index, args, returns);
379  }
380 
381  void SimdOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
382  Value* result) {
383  TFNode** inputs = GetNodes(args);
384  TFNode* node = BUILD(SimdOp, opcode, inputs);
385  if (result) result->node = node;
386  }
387 
388  void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode,
389  const SimdLaneImmediate<validate> imm, Vector<Value> inputs,
390  Value* result) {
391  TFNode** nodes = GetNodes(inputs);
392  result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes);
393  }
394 
395  void SimdShiftOp(FullDecoder* decoder, WasmOpcode opcode,
396  const SimdShiftImmediate<validate> imm, const Value& input,
397  Value* result) {
398  TFNode* inputs[] = {input.node};
399  result->node = BUILD(SimdShiftOp, opcode, imm.shift, inputs);
400  }
401 
402  void Simd8x16ShuffleOp(FullDecoder* decoder,
403  const Simd8x16ShuffleImmediate<validate>& imm,
404  const Value& input0, const Value& input1,
405  Value* result) {
406  TFNode* input_nodes[] = {input0.node, input1.node};
407  result->node = BUILD(Simd8x16ShuffleOp, imm.shuffle, input_nodes);
408  }
409 
410  void Throw(FullDecoder* decoder, const ExceptionIndexImmediate<validate>& imm,
411  const Vector<Value>& value_args) {
412  int count = value_args.length();
413  ZoneVector<TFNode*> args(count, decoder->zone());
414  for (int i = 0; i < count; ++i) {
415  args[i] = value_args[i].node;
416  }
417  BUILD(Throw, imm.index, imm.exception, VectorOf(args));
418  builder_->TerminateThrow(ssa_env_->effect, ssa_env_->control);
419  }
420 
421  void Rethrow(FullDecoder* decoder, Control* block) {
422  DCHECK(block->is_try_catchall() || block->is_try_catch());
423  TFNode* exception = block->try_info->exception;
424  BUILD(Rethrow, exception);
425  builder_->TerminateThrow(ssa_env_->effect, ssa_env_->control);
426  }
427 
428  void CatchException(FullDecoder* decoder,
429  const ExceptionIndexImmediate<validate>& imm,
430  Control* block, Vector<Value> values) {
431  DCHECK(block->is_try_catch());
432  TFNode* exception = block->try_info->exception;
433  current_catch_ = block->previous_catch; // Pop try scope.
434  SsaEnv* catch_env = block->try_info->catch_env;
435  SetEnv(catch_env);
436 
437  // The catch block is unreachable if no possible throws in the try block
438  // exist. We only build a landing pad if some node in the try block can
439  // (possibly) throw. Otherwise the catch environments remain empty.
440  DCHECK_EQ(exception != nullptr, ssa_env_->reached());
441  if (exception == nullptr) {
442  block->reachability = kSpecOnlyReachable;
443  return;
444  }
445 
446  TFNode* if_catch = nullptr;
447  TFNode* if_no_catch = nullptr;
448 
449  // Get the exception tag and see if it matches the expected one.
450  TFNode* caught_tag = BUILD(GetExceptionTag, exception);
451  TFNode* exception_tag = BUILD(LoadExceptionTagFromTable, imm.index);
452  TFNode* compare = BUILD(ExceptionTagEqual, caught_tag, exception_tag);
453  BUILD(BranchNoHint, compare, &if_catch, &if_no_catch);
454 
455  // If the tags don't match we continue with the next tag by setting the
456  // false environment as the new {TryInfo::catch_env} here.
457  SsaEnv* if_no_catch_env = Split(decoder, ssa_env_);
458  if_no_catch_env->control = if_no_catch;
459  SsaEnv* if_catch_env = Steal(decoder->zone(), ssa_env_);
460  if_catch_env->control = if_catch;
461  block->try_info->catch_env = if_no_catch_env;
462 
463  // If the tags match we extract the values from the exception object and
464  // push them onto the operand stack using the passed {values} vector.
465  SetEnv(if_catch_env);
466  // TODO(mstarzinger): Can't use BUILD() here, GetExceptionValues() returns
467  // TFNode** rather than TFNode*. Fix to add landing pads.
468  TFNode** caught_values =
469  builder_->GetExceptionValues(exception, imm.exception);
470  for (size_t i = 0, e = values.size(); i < e; ++i) {
471  values[i].node = caught_values[i];
472  }
473  }
474 
475  void CatchAll(FullDecoder* decoder, Control* block) {
476  DCHECK(block->is_try_catchall() || block->is_try_catch());
477  TFNode* exception = block->try_info->exception;
478  current_catch_ = block->previous_catch; // Pop try scope.
479  SsaEnv* catch_env = block->try_info->catch_env;
480  SetEnv(catch_env);
481 
482  // The catch block is unreachable if no possible throws in the try block
483  // exist. We only build a landing pad if some node in the try block can
484  // (possibly) throw. Otherwise the catch environments remain empty.
485  DCHECK_EQ(exception != nullptr, ssa_env_->reached());
486  if (exception == nullptr) {
487  block->reachability = kSpecOnlyReachable;
488  return;
489  }
490  }
491 
492  void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
493  const MemoryAccessImmediate<validate>& imm, Value* result) {
494  TFNode** inputs = GetNodes(args);
495  TFNode* node = BUILD(AtomicOp, opcode, inputs, imm.alignment, imm.offset,
496  decoder->position());
497  if (result) result->node = node;
498  }
499 
500  void MemoryInit(FullDecoder* decoder,
501  const MemoryInitImmediate<validate>& imm,
502  Vector<Value> args) {
503  BUILD(Unreachable, decoder->position());
504  }
505  void MemoryDrop(FullDecoder* decoder,
506  const MemoryDropImmediate<validate>& imm) {
507  BUILD(Unreachable, decoder->position());
508  }
509  void MemoryCopy(FullDecoder* decoder,
510  const MemoryIndexImmediate<validate>& imm,
511  Vector<Value> args) {
512  BUILD(Unreachable, decoder->position());
513  }
514  void MemoryFill(FullDecoder* decoder,
515  const MemoryIndexImmediate<validate>& imm,
516  Vector<Value> args) {
517  BUILD(Unreachable, decoder->position());
518  }
519  void TableInit(FullDecoder* decoder, const TableInitImmediate<validate>& imm,
520  Vector<Value> args) {
521  BUILD(Unreachable, decoder->position());
522  }
523  void TableDrop(FullDecoder* decoder,
524  const TableDropImmediate<validate>& imm) {
525  BUILD(Unreachable, decoder->position());
526  }
527  void TableCopy(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
528  Vector<Value> args) {
529  BUILD(Unreachable, decoder->position());
530  }
531 
532  private:
533  SsaEnv* ssa_env_;
534  compiler::WasmGraphBuilder* builder_;
535  uint32_t current_catch_ = kNullCatch;
536 
537  TryInfo* current_try_info(FullDecoder* decoder) {
538  return decoder->control_at(decoder->control_depth() - 1 - current_catch_)
539  ->try_info;
540  }
541 
542  TFNode** GetNodes(Value* values, size_t count) {
543  TFNode** nodes = builder_->Buffer(count);
544  for (size_t i = 0; i < count; ++i) {
545  nodes[i] = values[i].node;
546  }
547  return nodes;
548  }
549 
550  TFNode** GetNodes(Vector<Value> values) {
551  return GetNodes(values.start(), values.size());
552  }
553 
554  void SetEnv(SsaEnv* env) {
555 #if DEBUG
556  if (FLAG_trace_wasm_decoder) {
557  char state = 'X';
558  if (env) {
559  switch (env->state) {
560  case SsaEnv::kReached:
561  state = 'R';
562  break;
563  case SsaEnv::kUnreachable:
564  state = 'U';
565  break;
566  case SsaEnv::kMerged:
567  state = 'M';
568  break;
569  case SsaEnv::kControlEnd:
570  state = 'E';
571  break;
572  }
573  }
574  PrintF("{set_env = %p, state = %c", static_cast<void*>(env), state);
575  if (env && env->control) {
576  PrintF(", control = ");
577  compiler::WasmGraphBuilder::PrintDebugName(env->control);
578  }
579  PrintF("}\n");
580  }
581 #endif
582  ssa_env_ = env;
583  // TODO(wasm): combine the control and effect pointers with instance cache.
584  builder_->set_control_ptr(&env->control);
585  builder_->set_effect_ptr(&env->effect);
586  builder_->set_instance_cache(&env->instance_cache);
587  }
588 
589  TFNode* CheckForException(FullDecoder* decoder, TFNode* node) {
590  if (node == nullptr) return nullptr;
591 
592  const bool inside_try_scope = current_catch_ != kNullCatch;
593 
594  if (!inside_try_scope) return node;
595 
596  TFNode* if_success = nullptr;
597  TFNode* if_exception = nullptr;
598  if (!builder_->ThrowsException(node, &if_success, &if_exception)) {
599  return node;
600  }
601 
602  SsaEnv* success_env = Steal(decoder->zone(), ssa_env_);
603  success_env->control = if_success;
604 
605  SsaEnv* exception_env = Split(decoder, success_env);
606  exception_env->control = if_exception;
607  TryInfo* try_info = current_try_info(decoder);
608  Goto(decoder, exception_env, try_info->catch_env);
609  TFNode* exception = try_info->exception;
610  if (exception == nullptr) {
611  DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state);
612  try_info->exception = if_exception;
613  } else {
614  DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state);
615  try_info->exception = builder_->CreateOrMergeIntoPhi(
616  MachineRepresentation::kWord32, try_info->catch_env->control,
617  try_info->exception, if_exception);
618  }
619 
620  SetEnv(success_env);
621  return node;
622  }
623 
624  TFNode* DefaultValue(ValueType type) {
625  switch (type) {
626  case kWasmI32:
627  return builder_->Int32Constant(0);
628  case kWasmI64:
629  return builder_->Int64Constant(0);
630  case kWasmF32:
631  return builder_->Float32Constant(0);
632  case kWasmF64:
633  return builder_->Float64Constant(0);
634  case kWasmS128:
635  return builder_->S128Zero();
636  case kWasmAnyRef:
637  case kWasmExceptRef:
638  return builder_->RefNull();
639  default:
640  UNREACHABLE();
641  }
642  }
643 
644  void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge) {
645  DCHECK(merge == &c->start_merge || merge == &c->end_merge);
646  if (!ssa_env_->reached()) return;
647 
648  SsaEnv* target = c->end_env;
649  const bool first = target->state == SsaEnv::kUnreachable;
650  Goto(decoder, ssa_env_, target);
651 
652  uint32_t avail =
653  decoder->stack_size() - decoder->control_at(0)->stack_depth;
654  uint32_t start = avail >= merge->arity ? 0 : merge->arity - avail;
655  for (uint32_t i = start; i < merge->arity; ++i) {
656  auto& val = decoder->GetMergeValueFromStack(c, merge, i);
657  auto& old = (*merge)[i];
658  DCHECK_NOT_NULL(val.node);
659  DCHECK(val.type == old.type || val.type == kWasmVar);
660  old.node = first ? val.node
661  : builder_->CreateOrMergeIntoPhi(
662  ValueTypes::MachineRepresentationFor(old.type),
663  target->control, old.node, val.node);
664  }
665  }
666 
667  void Goto(FullDecoder* decoder, SsaEnv* from, SsaEnv* to) {
668  DCHECK_NOT_NULL(to);
669  if (!from->reached()) return;
670  switch (to->state) {
671  case SsaEnv::kUnreachable: { // Overwrite destination.
672  to->state = SsaEnv::kReached;
673  to->locals = from->locals;
674  to->control = from->control;
675  to->effect = from->effect;
676  to->instance_cache = from->instance_cache;
677  break;
678  }
679  case SsaEnv::kReached: { // Create a new merge.
680  to->state = SsaEnv::kMerged;
681  // Merge control.
682  TFNode* controls[] = {to->control, from->control};
683  TFNode* merge = builder_->Merge(2, controls);
684  to->control = merge;
685  // Merge effects.
686  if (from->effect != to->effect) {
687  TFNode* effects[] = {to->effect, from->effect, merge};
688  to->effect = builder_->EffectPhi(2, effects, merge);
689  }
690  // Merge SSA values.
691  for (int i = decoder->NumLocals() - 1; i >= 0; i--) {
692  TFNode* a = to->locals[i];
693  TFNode* b = from->locals[i];
694  if (a != b) {
695  TFNode* vals[] = {a, b};
696  to->locals[i] =
697  builder_->Phi(decoder->GetLocalType(i), 2, vals, merge);
698  }
699  }
700  // Start a new merge from the instance cache.
701  builder_->NewInstanceCacheMerge(&to->instance_cache,
702  &from->instance_cache, merge);
703  break;
704  }
705  case SsaEnv::kMerged: {
706  TFNode* merge = to->control;
707  // Extend the existing merge control node.
708  builder_->AppendToMerge(merge, from->control);
709  // Merge effects.
710  to->effect = builder_->CreateOrMergeIntoEffectPhi(merge, to->effect,
711  from->effect);
712  // Merge locals.
713  for (int i = decoder->NumLocals() - 1; i >= 0; i--) {
714  to->locals[i] = builder_->CreateOrMergeIntoPhi(
715  ValueTypes::MachineRepresentationFor(decoder->GetLocalType(i)),
716  merge, to->locals[i], from->locals[i]);
717  }
718  // Merge the instance caches.
719  builder_->MergeInstanceCacheInto(&to->instance_cache,
720  &from->instance_cache, merge);
721  break;
722  }
723  default:
724  UNREACHABLE();
725  }
726  return from->Kill();
727  }
728 
729  SsaEnv* PrepareForLoop(FullDecoder* decoder, SsaEnv* env) {
730  if (!env->reached()) return Split(decoder, env);
731  env->state = SsaEnv::kMerged;
732 
733  env->control = builder_->Loop(env->control);
734  env->effect = builder_->EffectPhi(1, &env->effect, env->control);
735  builder_->TerminateLoop(env->effect, env->control);
736  // The '+ 1' here is to be able to set the instance cache as assigned.
737  BitVector* assigned = WasmDecoder<validate>::AnalyzeLoopAssignment(
738  decoder, decoder->pc(), decoder->total_locals() + 1, decoder->zone());
739  if (decoder->failed()) return env;
740  if (assigned != nullptr) {
741  // Only introduce phis for variables assigned in this loop.
742  int instance_cache_index = decoder->total_locals();
743  for (int i = decoder->NumLocals() - 1; i >= 0; i--) {
744  if (!assigned->Contains(i)) continue;
745  env->locals[i] = builder_->Phi(decoder->GetLocalType(i), 1,
746  &env->locals[i], env->control);
747  }
748  // Introduce phis for instance cache pointers if necessary.
749  if (assigned->Contains(instance_cache_index)) {
750  builder_->PrepareInstanceCacheForLoop(&env->instance_cache,
751  env->control);
752  }
753 
754  SsaEnv* loop_body_env = Split(decoder, env);
755  builder_->StackCheck(decoder->position(), &(loop_body_env->effect),
756  &(loop_body_env->control));
757  return loop_body_env;
758  }
759 
760  // Conservatively introduce phis for all local variables.
761  for (int i = decoder->NumLocals() - 1; i >= 0; i--) {
762  env->locals[i] = builder_->Phi(decoder->GetLocalType(i), 1,
763  &env->locals[i], env->control);
764  }
765 
766  // Conservatively introduce phis for instance cache.
767  builder_->PrepareInstanceCacheForLoop(&env->instance_cache, env->control);
768 
769  SsaEnv* loop_body_env = Split(decoder, env);
770  builder_->StackCheck(decoder->position(), &loop_body_env->effect,
771  &loop_body_env->control);
772  return loop_body_env;
773  }
774 
775  // Create a complete copy of {from}.
776  SsaEnv* Split(FullDecoder* decoder, SsaEnv* from) {
777  DCHECK_NOT_NULL(from);
778  SsaEnv* result =
779  reinterpret_cast<SsaEnv*>(decoder->zone()->New(sizeof(SsaEnv)));
780  size_t size = sizeof(TFNode*) * decoder->NumLocals();
781  result->control = from->control;
782  result->effect = from->effect;
783 
784  if (from->reached()) {
785  result->state = SsaEnv::kReached;
786  result->locals =
787  size > 0 ? reinterpret_cast<TFNode**>(decoder->zone()->New(size))
788  : nullptr;
789  memcpy(result->locals, from->locals, size);
790  result->instance_cache = from->instance_cache;
791  } else {
792  result->state = SsaEnv::kUnreachable;
793  result->locals = nullptr;
794  result->instance_cache = {};
795  }
796 
797  return result;
798  }
799 
800  // Create a copy of {from} that steals its state and leaves {from}
801  // unreachable.
802  SsaEnv* Steal(Zone* zone, SsaEnv* from) {
803  DCHECK_NOT_NULL(from);
804  if (!from->reached()) return UnreachableEnv(zone);
805  SsaEnv* result = reinterpret_cast<SsaEnv*>(zone->New(sizeof(SsaEnv)));
806  result->state = SsaEnv::kReached;
807  result->locals = from->locals;
808  result->control = from->control;
809  result->effect = from->effect;
810  result->instance_cache = from->instance_cache;
811  from->Kill(SsaEnv::kUnreachable);
812  return result;
813  }
814 
815  // Create an unreachable environment.
816  SsaEnv* UnreachableEnv(Zone* zone) {
817  SsaEnv* result = reinterpret_cast<SsaEnv*>(zone->New(sizeof(SsaEnv)));
818  result->state = SsaEnv::kUnreachable;
819  result->control = nullptr;
820  result->effect = nullptr;
821  result->locals = nullptr;
822  result->instance_cache = {};
823  return result;
824  }
825 
826  void DoCall(FullDecoder* decoder, TFNode* index_node, FunctionSig* sig,
827  uint32_t index, const Value args[], Value returns[]) {
828  int param_count = static_cast<int>(sig->parameter_count());
829  TFNode** arg_nodes = builder_->Buffer(param_count + 1);
830  TFNode** return_nodes = nullptr;
831  arg_nodes[0] = index_node;
832  for (int i = 0; i < param_count; ++i) {
833  arg_nodes[i + 1] = args[i].node;
834  }
835  if (index_node) {
836  BUILD(CallIndirect, index, arg_nodes, &return_nodes, decoder->position());
837  } else {
838  BUILD(CallDirect, index, arg_nodes, &return_nodes, decoder->position());
839  }
840  int return_count = static_cast<int>(sig->return_count());
841  for (int i = 0; i < return_count; ++i) {
842  returns[i].node = return_nodes[i];
843  }
844  // The invoked function could have used grow_memory, so we need to
845  // reload mem_size and mem_start.
846  LoadContextIntoSsa(ssa_env_);
847  }
848 };
849 
850 } // namespace
851 
852 DecodeResult BuildTFGraph(AccountingAllocator* allocator,
853  const WasmFeatures& enabled,
854  const wasm::WasmModule* module,
855  compiler::WasmGraphBuilder* builder,
856  WasmFeatures* detected, const FunctionBody& body,
857  compiler::NodeOriginTable* node_origins) {
858  Zone zone(allocator, ZONE_NAME);
859  WasmFullDecoder<Decoder::kValidate, WasmGraphBuildingInterface> decoder(
860  &zone, module, enabled, detected, body, builder);
861  if (node_origins) {
862  builder->AddBytecodePositionDecorator(node_origins, &decoder);
863  }
864  decoder.Decode();
865  if (node_origins) {
866  builder->RemoveBytecodePositionDecorator();
867  }
868  return decoder.toResult(nullptr);
869 }
870 
871 #undef BUILD
872 
873 } // namespace wasm
874 } // namespace internal
875 } // namespace v8
Definition: libplatform.h:13