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