• 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/compiler/wasm-compiler.h"
6 
7 #include <memory>
8 
9 #include "src/assembler-inl.h"
10 #include "src/base/platform/elapsed-timer.h"
11 #include "src/base/platform/platform.h"
12 #include "src/builtins/builtins.h"
13 #include "src/code-factory.h"
14 #include "src/code-stubs.h"
15 #include "src/compiler/access-builder.h"
16 #include "src/compiler/common-operator.h"
17 #include "src/compiler/compiler-source-position-table.h"
18 #include "src/compiler/diamond.h"
19 #include "src/compiler/graph-visualizer.h"
20 #include "src/compiler/graph.h"
21 #include "src/compiler/instruction-selector.h"
22 #include "src/compiler/int64-lowering.h"
23 #include "src/compiler/js-graph.h"
24 #include "src/compiler/js-operator.h"
25 #include "src/compiler/linkage.h"
26 #include "src/compiler/machine-operator.h"
27 #include "src/compiler/node-matchers.h"
28 #include "src/compiler/pipeline.h"
29 #include "src/compiler/simd-scalar-lowering.h"
30 #include "src/compiler/zone-stats.h"
31 #include "src/factory.h"
32 #include "src/isolate-inl.h"
33 #include "src/log-inl.h"
34 #include "src/wasm/function-body-decoder.h"
35 #include "src/wasm/wasm-limits.h"
36 #include "src/wasm/wasm-module.h"
37 #include "src/wasm/wasm-objects.h"
38 #include "src/wasm/wasm-opcodes.h"
39 #include "src/wasm/wasm-text.h"
40 
41 // TODO(titzer): pull WASM_64 up to a common header.
42 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
43 #define WASM_64 1
44 #else
45 #define WASM_64 0
46 #endif
47 
48 namespace v8 {
49 namespace internal {
50 namespace compiler {
51 
52 namespace {
UnsupportedOpcode(wasm::WasmOpcode opcode)53 const Operator* UnsupportedOpcode(wasm::WasmOpcode opcode) {
54   V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", opcode,
55            wasm::WasmOpcodes::OpcodeName(opcode));
56   return nullptr;
57 }
58 
MergeControlToEnd(JSGraph * jsgraph,Node * node)59 void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
60   Graph* g = jsgraph->graph();
61   if (g->end()) {
62     NodeProperties::MergeControlToEnd(g, jsgraph->common(), node);
63   } else {
64     g->SetEnd(g->NewNode(jsgraph->common()->End(1), node));
65   }
66 }
67 
68 // Only call this function for code which is not reused across instantiations,
69 // as we do not patch the embedded context.
BuildCallToRuntimeWithContext(Runtime::FunctionId f,JSGraph * jsgraph,Node * context,Node ** parameters,int parameter_count,Node ** effect_ptr,Node * control)70 Node* BuildCallToRuntimeWithContext(Runtime::FunctionId f, JSGraph* jsgraph,
71                                     Node* context, Node** parameters,
72                                     int parameter_count, Node** effect_ptr,
73                                     Node* control) {
74   const Runtime::Function* fun = Runtime::FunctionForId(f);
75   CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
76       jsgraph->zone(), f, fun->nargs, Operator::kNoProperties,
77       CallDescriptor::kNoFlags);
78   // CEntryStubConstant nodes have to be created and cached in the main
79   // thread. At the moment this is only done for CEntryStubConstant(1).
80   DCHECK_EQ(1, fun->result_size);
81   // At the moment we only allow 3 parameters. If more parameters are needed,
82   // increase this constant accordingly.
83   static const int kMaxParams = 3;
84   DCHECK_GE(kMaxParams, parameter_count);
85   Node* inputs[kMaxParams + 6];
86   int count = 0;
87   inputs[count++] = jsgraph->CEntryStubConstant(fun->result_size);
88   for (int i = 0; i < parameter_count; i++) {
89     inputs[count++] = parameters[i];
90   }
91   inputs[count++] = jsgraph->ExternalConstant(
92       ExternalReference(f, jsgraph->isolate()));         // ref
93   inputs[count++] = jsgraph->Int32Constant(fun->nargs);  // arity
94   inputs[count++] = context;                             // context
95   inputs[count++] = *effect_ptr;
96   inputs[count++] = control;
97 
98   Node* node =
99       jsgraph->graph()->NewNode(jsgraph->common()->Call(desc), count, inputs);
100   *effect_ptr = node;
101   return node;
102 }
103 
BuildCallToRuntime(Runtime::FunctionId f,JSGraph * jsgraph,Node ** parameters,int parameter_count,Node ** effect_ptr,Node * control)104 Node* BuildCallToRuntime(Runtime::FunctionId f, JSGraph* jsgraph,
105                          Node** parameters, int parameter_count,
106                          Node** effect_ptr, Node* control) {
107   return BuildCallToRuntimeWithContext(f, jsgraph, jsgraph->NoContextConstant(),
108                                        parameters, parameter_count, effect_ptr,
109                                        control);
110 }
111 
112 }  // namespace
113 
114 // TODO(eholk): Support trap handlers on other platforms.
115 #if V8_TARGET_ARCH_X64 && V8_OS_LINUX
116 const bool kTrapHandlerSupported = true;
117 #else
118 const bool kTrapHandlerSupported = false;
119 #endif
120 
121 // A helper that handles building graph fragments for trapping.
122 // To avoid generating a ton of redundant code that just calls the runtime
123 // to trap, we generate a per-trap-reason block of code that all trap sites
124 // in this function will branch to.
125 class WasmTrapHelper : public ZoneObject {
126  public:
WasmTrapHelper(WasmGraphBuilder * builder)127   explicit WasmTrapHelper(WasmGraphBuilder* builder)
128       : builder_(builder),
129         jsgraph_(builder->jsgraph()),
130         graph_(builder->jsgraph() ? builder->jsgraph()->graph() : nullptr) {}
131 
132   // Make the current control path trap to unreachable.
Unreachable(wasm::WasmCodePosition position)133   void Unreachable(wasm::WasmCodePosition position) {
134     ConnectTrap(wasm::kTrapUnreachable, position);
135   }
136 
137   // Always trap with the given reason.
TrapAlways(wasm::TrapReason reason,wasm::WasmCodePosition position)138   void TrapAlways(wasm::TrapReason reason, wasm::WasmCodePosition position) {
139     ConnectTrap(reason, position);
140   }
141 
142   // Add a check that traps if {node} is equal to {val}.
TrapIfEq32(wasm::TrapReason reason,Node * node,int32_t val,wasm::WasmCodePosition position)143   Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val,
144                    wasm::WasmCodePosition position) {
145     Int32Matcher m(node);
146     if (m.HasValue() && !m.Is(val)) return graph()->start();
147     if (val == 0) {
148       AddTrapIfFalse(reason, node, position);
149     } else {
150       AddTrapIfTrue(reason,
151                     graph()->NewNode(jsgraph()->machine()->Word32Equal(), node,
152                                      jsgraph()->Int32Constant(val)),
153                     position);
154     }
155     return builder_->Control();
156   }
157 
158   // Add a check that traps if {node} is zero.
ZeroCheck32(wasm::TrapReason reason,Node * node,wasm::WasmCodePosition position)159   Node* ZeroCheck32(wasm::TrapReason reason, Node* node,
160                     wasm::WasmCodePosition position) {
161     return TrapIfEq32(reason, node, 0, position);
162   }
163 
164   // Add a check that traps if {node} is equal to {val}.
TrapIfEq64(wasm::TrapReason reason,Node * node,int64_t val,wasm::WasmCodePosition position)165   Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val,
166                    wasm::WasmCodePosition position) {
167     Int64Matcher m(node);
168     if (m.HasValue() && !m.Is(val)) return graph()->start();
169     AddTrapIfTrue(reason, graph()->NewNode(jsgraph()->machine()->Word64Equal(),
170                                            node, jsgraph()->Int64Constant(val)),
171                   position);
172     return builder_->Control();
173   }
174 
175   // Add a check that traps if {node} is zero.
ZeroCheck64(wasm::TrapReason reason,Node * node,wasm::WasmCodePosition position)176   Node* ZeroCheck64(wasm::TrapReason reason, Node* node,
177                     wasm::WasmCodePosition position) {
178     return TrapIfEq64(reason, node, 0, position);
179   }
180 
GetBuiltinIdForTrap(wasm::TrapReason reason)181   Builtins::Name GetBuiltinIdForTrap(wasm::TrapReason reason) {
182     if (builder_->module_ && !builder_->module_->instance->context.is_null()) {
183       switch (reason) {
184 #define TRAPREASON_TO_MESSAGE(name) \
185   case wasm::k##name:               \
186     return Builtins::kThrowWasm##name;
187         FOREACH_WASM_TRAPREASON(TRAPREASON_TO_MESSAGE)
188 #undef TRAPREASON_TO_MESSAGE
189         default:
190           UNREACHABLE();
191           return Builtins::builtin_count;
192       }
193     } else {
194       // We use Runtime::kNumFunctions as a marker to tell the code generator
195       // to generate a call to a testing c-function instead of a runtime
196       // function. This code should only be called from a cctest.
197       return Builtins::builtin_count;
198     }
199   }
200 
201 #if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM ||      \
202     V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || \
203     V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390 ||    \
204     V8_TARGET_ARCH_S390X || V8_TARGET_ARCH_X87
205 #define WASM_TRAP_IF_SUPPORTED
206 #endif
207 
208   // Add a trap if {cond} is true.
AddTrapIfTrue(wasm::TrapReason reason,Node * cond,wasm::WasmCodePosition position)209   void AddTrapIfTrue(wasm::TrapReason reason, Node* cond,
210                      wasm::WasmCodePosition position) {
211 #ifdef WASM_TRAP_IF_SUPPORTED
212     if (FLAG_wasm_trap_if) {
213       int32_t trap_id = GetBuiltinIdForTrap(reason);
214       Node* node = graph()->NewNode(common()->TrapIf(trap_id), cond,
215                                     builder_->Effect(), builder_->Control());
216       *builder_->control_ = node;
217       builder_->SetSourcePosition(node, position);
218       return;
219     }
220 #endif  // WASM_TRAP_IF_SUPPORTED
221     BuildTrapIf(reason, cond, true, position);
222   }
223 
224   // Add a trap if {cond} is false.
AddTrapIfFalse(wasm::TrapReason reason,Node * cond,wasm::WasmCodePosition position)225   void AddTrapIfFalse(wasm::TrapReason reason, Node* cond,
226                       wasm::WasmCodePosition position) {
227 #ifdef WASM_TRAP_IF_SUPPORTED
228     if (FLAG_wasm_trap_if) {
229       int32_t trap_id = GetBuiltinIdForTrap(reason);
230 
231       Node* node = graph()->NewNode(common()->TrapUnless(trap_id), cond,
232                                     builder_->Effect(), builder_->Control());
233       *builder_->control_ = node;
234       builder_->SetSourcePosition(node, position);
235       return;
236     }
237 #endif  // WASM_TRAP_IF_SUPPORTED
238 
239     BuildTrapIf(reason, cond, false, position);
240   }
241 
242   // Add a trap if {cond} is true or false according to {iftrue}.
BuildTrapIf(wasm::TrapReason reason,Node * cond,bool iftrue,wasm::WasmCodePosition position)243   void BuildTrapIf(wasm::TrapReason reason, Node* cond, bool iftrue,
244                    wasm::WasmCodePosition position) {
245     Node** effect_ptr = builder_->effect_;
246     Node** control_ptr = builder_->control_;
247     Node* before = *effect_ptr;
248     BranchHint hint = iftrue ? BranchHint::kFalse : BranchHint::kTrue;
249     Node* branch = graph()->NewNode(common()->Branch(hint), cond, *control_ptr);
250     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
251     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
252 
253     *control_ptr = iftrue ? if_true : if_false;
254     ConnectTrap(reason, position);
255     *control_ptr = iftrue ? if_false : if_true;
256     *effect_ptr = before;
257   }
258 
GetTrapValue(wasm::FunctionSig * sig)259   Node* GetTrapValue(wasm::FunctionSig* sig) {
260     if (sig->return_count() > 0) {
261       return GetTrapValue(sig->GetReturn());
262     } else {
263       return jsgraph()->Int32Constant(0xdeadbeef);
264     }
265   }
266 
GetTrapValue(wasm::ValueType type)267   Node* GetTrapValue(wasm::ValueType type) {
268     switch (type) {
269       case wasm::kWasmI32:
270         return jsgraph()->Int32Constant(0xdeadbeef);
271       case wasm::kWasmI64:
272         return jsgraph()->Int64Constant(0xdeadbeefdeadbeef);
273       case wasm::kWasmF32:
274         return jsgraph()->Float32Constant(bit_cast<float>(0xdeadbeef));
275       case wasm::kWasmF64:
276         return jsgraph()->Float64Constant(bit_cast<double>(0xdeadbeefdeadbeef));
277         break;
278       case wasm::kWasmS128:
279         return builder_->CreateS128Value(0xdeadbeef);
280         break;
281       default:
282         UNREACHABLE();
283         return nullptr;
284     }
285   }
286 
287  private:
288   WasmGraphBuilder* builder_;
289   JSGraph* jsgraph_;
290   Graph* graph_;
291   Node* trap_merge_ = nullptr;
292   Node* trap_effect_;
293   Node* trap_reason_;
294   Node* trap_position_;
295 
jsgraph()296   JSGraph* jsgraph() { return jsgraph_; }
graph()297   Graph* graph() { return jsgraph_->graph(); }
common()298   CommonOperatorBuilder* common() { return jsgraph()->common(); }
299 
ConnectTrap(wasm::TrapReason reason,wasm::WasmCodePosition position)300   void ConnectTrap(wasm::TrapReason reason, wasm::WasmCodePosition position) {
301     DCHECK(position != wasm::kNoCodePosition);
302     Node* reason_node = builder_->Int32Constant(
303         wasm::WasmOpcodes::TrapReasonToMessageId(reason));
304     Node* position_node = builder_->Int32Constant(position);
305     if (trap_merge_ == nullptr) {
306       // Create trap code for the first time.
307       return BuildTrapCode(reason_node, position_node);
308     }
309     // Connect the current control and effect to the existing trap code.
310     builder_->AppendToMerge(trap_merge_, builder_->Control());
311     builder_->AppendToPhi(trap_effect_, builder_->Effect());
312     builder_->AppendToPhi(trap_reason_, reason_node);
313     builder_->AppendToPhi(trap_position_, position_node);
314   }
315 
BuildTrapCode(Node * reason_node,Node * position_node)316   void BuildTrapCode(Node* reason_node, Node* position_node) {
317     Node** control_ptr = builder_->control_;
318     Node** effect_ptr = builder_->effect_;
319     wasm::ModuleEnv* module = builder_->module_;
320     DCHECK(trap_merge_ == NULL);
321     *control_ptr = trap_merge_ =
322         graph()->NewNode(common()->Merge(1), *control_ptr);
323     *effect_ptr = trap_effect_ =
324         graph()->NewNode(common()->EffectPhi(1), *effect_ptr, *control_ptr);
325     trap_reason_ =
326         graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 1),
327                          reason_node, *control_ptr);
328     trap_position_ =
329         graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 1),
330                          position_node, *control_ptr);
331 
332     Node* trap_reason_smi = builder_->BuildChangeInt32ToSmi(trap_reason_);
333     Node* trap_position_smi = builder_->BuildChangeInt32ToSmi(trap_position_);
334 
335     if (module && !module->instance->context.is_null()) {
336       Node* parameters[] = {trap_reason_smi,     // message id
337                             trap_position_smi};  // byte position
338       BuildCallToRuntime(Runtime::kThrowWasmError, jsgraph(), parameters,
339                          arraysize(parameters), effect_ptr, *control_ptr);
340     }
341     if (false) {
342       // End the control flow with a throw
343       Node* thrw =
344           graph()->NewNode(common()->Throw(), jsgraph()->ZeroConstant(),
345                            *effect_ptr, *control_ptr);
346       MergeControlToEnd(jsgraph(), thrw);
347     } else {
348       // End the control flow with returning 0xdeadbeef
349       Node* ret_value = GetTrapValue(builder_->GetFunctionSignature());
350       builder_->Return(ret_value);
351     }
352   }
353 };
354 
WasmGraphBuilder(wasm::ModuleEnv * module_env,Zone * zone,JSGraph * jsgraph,wasm::FunctionSig * sig,compiler::SourcePositionTable * source_position_table)355 WasmGraphBuilder::WasmGraphBuilder(
356     wasm::ModuleEnv* module_env, Zone* zone, JSGraph* jsgraph,
357     wasm::FunctionSig* sig,
358     compiler::SourcePositionTable* source_position_table)
359     : zone_(zone),
360       jsgraph_(jsgraph),
361       module_(module_env),
362       signature_tables_(zone),
363       function_tables_(zone),
364       function_table_sizes_(zone),
365       cur_buffer_(def_buffer_),
366       cur_bufsize_(kDefaultBufferSize),
367       trap_(new (zone) WasmTrapHelper(this)),
368       sig_(sig),
369       source_position_table_(source_position_table) {
370   for (size_t i = 0; i < sig->parameter_count(); i++) {
371     if (sig->GetParam(i) == wasm::kWasmS128) has_simd_ = true;
372   }
373   for (size_t i = 0; i < sig->return_count(); i++) {
374     if (sig->GetReturn(i) == wasm::kWasmS128) has_simd_ = true;
375   }
376   DCHECK_NOT_NULL(jsgraph_);
377 }
378 
Error()379 Node* WasmGraphBuilder::Error() { return jsgraph()->Dead(); }
380 
Start(unsigned params)381 Node* WasmGraphBuilder::Start(unsigned params) {
382   Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
383   graph()->SetStart(start);
384   return start;
385 }
386 
Param(unsigned index)387 Node* WasmGraphBuilder::Param(unsigned index) {
388   return graph()->NewNode(jsgraph()->common()->Parameter(index),
389                           graph()->start());
390 }
391 
Loop(Node * entry)392 Node* WasmGraphBuilder::Loop(Node* entry) {
393   return graph()->NewNode(jsgraph()->common()->Loop(1), entry);
394 }
395 
Terminate(Node * effect,Node * control)396 Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
397   Node* terminate =
398       graph()->NewNode(jsgraph()->common()->Terminate(), effect, control);
399   MergeControlToEnd(jsgraph(), terminate);
400   return terminate;
401 }
402 
InputCount(Node * node)403 unsigned WasmGraphBuilder::InputCount(Node* node) {
404   return static_cast<unsigned>(node->InputCount());
405 }
406 
IsPhiWithMerge(Node * phi,Node * merge)407 bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
408   return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
409          NodeProperties::GetControlInput(phi) == merge;
410 }
411 
ThrowsException(Node * node,Node ** if_success,Node ** if_exception)412 bool WasmGraphBuilder::ThrowsException(Node* node, Node** if_success,
413                                        Node** if_exception) {
414   if (node->op()->HasProperty(compiler::Operator::kNoThrow)) {
415     return false;
416   }
417 
418   *if_success = graph()->NewNode(jsgraph()->common()->IfSuccess(), node);
419   *if_exception =
420       graph()->NewNode(jsgraph()->common()->IfException(), node, node);
421 
422   return true;
423 }
424 
AppendToMerge(Node * merge,Node * from)425 void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) {
426   DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
427   merge->AppendInput(jsgraph()->zone(), from);
428   int new_size = merge->InputCount();
429   NodeProperties::ChangeOp(
430       merge, jsgraph()->common()->ResizeMergeOrPhi(merge->op(), new_size));
431 }
432 
AppendToPhi(Node * phi,Node * from)433 void WasmGraphBuilder::AppendToPhi(Node* phi, Node* from) {
434   DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
435   int new_size = phi->InputCount();
436   phi->InsertInput(jsgraph()->zone(), phi->InputCount() - 1, from);
437   NodeProperties::ChangeOp(
438       phi, jsgraph()->common()->ResizeMergeOrPhi(phi->op(), new_size));
439 }
440 
Merge(unsigned count,Node ** controls)441 Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
442   return graph()->NewNode(jsgraph()->common()->Merge(count), count, controls);
443 }
444 
Phi(wasm::ValueType type,unsigned count,Node ** vals,Node * control)445 Node* WasmGraphBuilder::Phi(wasm::ValueType type, unsigned count, Node** vals,
446                             Node* control) {
447   DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
448   Node** buf = Realloc(vals, count, count + 1);
449   buf[count] = control;
450   return graph()->NewNode(jsgraph()->common()->Phi(type, count), count + 1,
451                           buf);
452 }
453 
EffectPhi(unsigned count,Node ** effects,Node * control)454 Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
455                                   Node* control) {
456   DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
457   Node** buf = Realloc(effects, count, count + 1);
458   buf[count] = control;
459   return graph()->NewNode(jsgraph()->common()->EffectPhi(count), count + 1,
460                           buf);
461 }
462 
NumberConstant(int32_t value)463 Node* WasmGraphBuilder::NumberConstant(int32_t value) {
464   return jsgraph()->Constant(value);
465 }
466 
Uint32Constant(uint32_t value)467 Node* WasmGraphBuilder::Uint32Constant(uint32_t value) {
468   return jsgraph()->Uint32Constant(value);
469 }
470 
Int32Constant(int32_t value)471 Node* WasmGraphBuilder::Int32Constant(int32_t value) {
472   return jsgraph()->Int32Constant(value);
473 }
474 
Int64Constant(int64_t value)475 Node* WasmGraphBuilder::Int64Constant(int64_t value) {
476   return jsgraph()->Int64Constant(value);
477 }
478 
StackCheck(wasm::WasmCodePosition position,Node ** effect,Node ** control)479 void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
480                                   Node** effect, Node** control) {
481   if (FLAG_wasm_no_stack_checks) return;
482   // We do not generate stack checks for cctests.
483   if (!module_ || module_->instance->context.is_null()) return;
484   if (effect == nullptr) effect = effect_;
485   if (control == nullptr) control = control_;
486 
487   Node* limit = graph()->NewNode(
488       jsgraph()->machine()->Load(MachineType::Pointer()),
489       jsgraph()->ExternalConstant(
490           ExternalReference::address_of_stack_limit(jsgraph()->isolate())),
491       jsgraph()->IntPtrConstant(0), *effect, *control);
492   Node* pointer = graph()->NewNode(jsgraph()->machine()->LoadStackPointer());
493 
494   Node* check =
495       graph()->NewNode(jsgraph()->machine()->UintLessThan(), limit, pointer);
496 
497   Diamond stack_check(graph(), jsgraph()->common(), check, BranchHint::kTrue);
498   stack_check.Chain(*control);
499   Node* effect_true = *effect;
500 
501   Handle<Code> code = jsgraph()->isolate()->builtins()->WasmStackGuard();
502   CallInterfaceDescriptor idesc =
503       WasmRuntimeCallDescriptor(jsgraph()->isolate());
504   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
505       jsgraph()->isolate(), jsgraph()->zone(), idesc, 0,
506       CallDescriptor::kNoFlags, Operator::kNoProperties);
507   Node* stub_code = jsgraph()->HeapConstant(code);
508 
509   Node* context = jsgraph()->NoContextConstant();
510   Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
511                                 context, *effect, stack_check.if_false);
512 
513   SetSourcePosition(call, position);
514 
515   Node* ephi = graph()->NewNode(jsgraph()->common()->EffectPhi(2), effect_true,
516                                 call, stack_check.merge);
517 
518   *control = stack_check.merge;
519   *effect = ephi;
520 }
521 
Binop(wasm::WasmOpcode opcode,Node * left,Node * right,wasm::WasmCodePosition position)522 Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
523                               wasm::WasmCodePosition position) {
524   const Operator* op;
525   MachineOperatorBuilder* m = jsgraph()->machine();
526   switch (opcode) {
527     case wasm::kExprI32Add:
528       op = m->Int32Add();
529       break;
530     case wasm::kExprI32Sub:
531       op = m->Int32Sub();
532       break;
533     case wasm::kExprI32Mul:
534       op = m->Int32Mul();
535       break;
536     case wasm::kExprI32DivS:
537       return BuildI32DivS(left, right, position);
538     case wasm::kExprI32DivU:
539       return BuildI32DivU(left, right, position);
540     case wasm::kExprI32RemS:
541       return BuildI32RemS(left, right, position);
542     case wasm::kExprI32RemU:
543       return BuildI32RemU(left, right, position);
544     case wasm::kExprI32And:
545       op = m->Word32And();
546       break;
547     case wasm::kExprI32Ior:
548       op = m->Word32Or();
549       break;
550     case wasm::kExprI32Xor:
551       op = m->Word32Xor();
552       break;
553     case wasm::kExprI32Shl:
554       op = m->Word32Shl();
555       right = MaskShiftCount32(right);
556       break;
557     case wasm::kExprI32ShrU:
558       op = m->Word32Shr();
559       right = MaskShiftCount32(right);
560       break;
561     case wasm::kExprI32ShrS:
562       op = m->Word32Sar();
563       right = MaskShiftCount32(right);
564       break;
565     case wasm::kExprI32Ror:
566       op = m->Word32Ror();
567       right = MaskShiftCount32(right);
568       break;
569     case wasm::kExprI32Rol:
570       right = MaskShiftCount32(right);
571       return BuildI32Rol(left, right);
572     case wasm::kExprI32Eq:
573       op = m->Word32Equal();
574       break;
575     case wasm::kExprI32Ne:
576       return Invert(Binop(wasm::kExprI32Eq, left, right));
577     case wasm::kExprI32LtS:
578       op = m->Int32LessThan();
579       break;
580     case wasm::kExprI32LeS:
581       op = m->Int32LessThanOrEqual();
582       break;
583     case wasm::kExprI32LtU:
584       op = m->Uint32LessThan();
585       break;
586     case wasm::kExprI32LeU:
587       op = m->Uint32LessThanOrEqual();
588       break;
589     case wasm::kExprI32GtS:
590       op = m->Int32LessThan();
591       std::swap(left, right);
592       break;
593     case wasm::kExprI32GeS:
594       op = m->Int32LessThanOrEqual();
595       std::swap(left, right);
596       break;
597     case wasm::kExprI32GtU:
598       op = m->Uint32LessThan();
599       std::swap(left, right);
600       break;
601     case wasm::kExprI32GeU:
602       op = m->Uint32LessThanOrEqual();
603       std::swap(left, right);
604       break;
605     case wasm::kExprI64And:
606       op = m->Word64And();
607       break;
608     case wasm::kExprI64Add:
609       op = m->Int64Add();
610       break;
611     case wasm::kExprI64Sub:
612       op = m->Int64Sub();
613       break;
614     case wasm::kExprI64Mul:
615       op = m->Int64Mul();
616       break;
617     case wasm::kExprI64DivS:
618       return BuildI64DivS(left, right, position);
619     case wasm::kExprI64DivU:
620       return BuildI64DivU(left, right, position);
621     case wasm::kExprI64RemS:
622       return BuildI64RemS(left, right, position);
623     case wasm::kExprI64RemU:
624       return BuildI64RemU(left, right, position);
625     case wasm::kExprI64Ior:
626       op = m->Word64Or();
627       break;
628     case wasm::kExprI64Xor:
629       op = m->Word64Xor();
630       break;
631     case wasm::kExprI64Shl:
632       op = m->Word64Shl();
633       right = MaskShiftCount64(right);
634       break;
635     case wasm::kExprI64ShrU:
636       op = m->Word64Shr();
637       right = MaskShiftCount64(right);
638       break;
639     case wasm::kExprI64ShrS:
640       op = m->Word64Sar();
641       right = MaskShiftCount64(right);
642       break;
643     case wasm::kExprI64Eq:
644       op = m->Word64Equal();
645       break;
646     case wasm::kExprI64Ne:
647       return Invert(Binop(wasm::kExprI64Eq, left, right));
648     case wasm::kExprI64LtS:
649       op = m->Int64LessThan();
650       break;
651     case wasm::kExprI64LeS:
652       op = m->Int64LessThanOrEqual();
653       break;
654     case wasm::kExprI64LtU:
655       op = m->Uint64LessThan();
656       break;
657     case wasm::kExprI64LeU:
658       op = m->Uint64LessThanOrEqual();
659       break;
660     case wasm::kExprI64GtS:
661       op = m->Int64LessThan();
662       std::swap(left, right);
663       break;
664     case wasm::kExprI64GeS:
665       op = m->Int64LessThanOrEqual();
666       std::swap(left, right);
667       break;
668     case wasm::kExprI64GtU:
669       op = m->Uint64LessThan();
670       std::swap(left, right);
671       break;
672     case wasm::kExprI64GeU:
673       op = m->Uint64LessThanOrEqual();
674       std::swap(left, right);
675       break;
676     case wasm::kExprI64Ror:
677       op = m->Word64Ror();
678       right = MaskShiftCount64(right);
679       break;
680     case wasm::kExprI64Rol:
681       return BuildI64Rol(left, right);
682     case wasm::kExprF32CopySign:
683       return BuildF32CopySign(left, right);
684     case wasm::kExprF64CopySign:
685       return BuildF64CopySign(left, right);
686     case wasm::kExprF32Add:
687       op = m->Float32Add();
688       break;
689     case wasm::kExprF32Sub:
690       op = m->Float32Sub();
691       break;
692     case wasm::kExprF32Mul:
693       op = m->Float32Mul();
694       break;
695     case wasm::kExprF32Div:
696       op = m->Float32Div();
697       break;
698     case wasm::kExprF32Eq:
699       op = m->Float32Equal();
700       break;
701     case wasm::kExprF32Ne:
702       return Invert(Binop(wasm::kExprF32Eq, left, right));
703     case wasm::kExprF32Lt:
704       op = m->Float32LessThan();
705       break;
706     case wasm::kExprF32Ge:
707       op = m->Float32LessThanOrEqual();
708       std::swap(left, right);
709       break;
710     case wasm::kExprF32Gt:
711       op = m->Float32LessThan();
712       std::swap(left, right);
713       break;
714     case wasm::kExprF32Le:
715       op = m->Float32LessThanOrEqual();
716       break;
717     case wasm::kExprF64Add:
718       op = m->Float64Add();
719       break;
720     case wasm::kExprF64Sub:
721       op = m->Float64Sub();
722       break;
723     case wasm::kExprF64Mul:
724       op = m->Float64Mul();
725       break;
726     case wasm::kExprF64Div:
727       op = m->Float64Div();
728       break;
729     case wasm::kExprF64Eq:
730       op = m->Float64Equal();
731       break;
732     case wasm::kExprF64Ne:
733       return Invert(Binop(wasm::kExprF64Eq, left, right));
734     case wasm::kExprF64Lt:
735       op = m->Float64LessThan();
736       break;
737     case wasm::kExprF64Le:
738       op = m->Float64LessThanOrEqual();
739       break;
740     case wasm::kExprF64Gt:
741       op = m->Float64LessThan();
742       std::swap(left, right);
743       break;
744     case wasm::kExprF64Ge:
745       op = m->Float64LessThanOrEqual();
746       std::swap(left, right);
747       break;
748     case wasm::kExprF32Min:
749       op = m->Float32Min();
750       break;
751     case wasm::kExprF64Min:
752       op = m->Float64Min();
753       break;
754     case wasm::kExprF32Max:
755       op = m->Float32Max();
756       break;
757     case wasm::kExprF64Max:
758       op = m->Float64Max();
759       break;
760     case wasm::kExprF64Pow:
761       return BuildF64Pow(left, right);
762     case wasm::kExprF64Atan2:
763       op = m->Float64Atan2();
764       break;
765     case wasm::kExprF64Mod:
766       return BuildF64Mod(left, right);
767     case wasm::kExprI32AsmjsDivS:
768       return BuildI32AsmjsDivS(left, right);
769     case wasm::kExprI32AsmjsDivU:
770       return BuildI32AsmjsDivU(left, right);
771     case wasm::kExprI32AsmjsRemS:
772       return BuildI32AsmjsRemS(left, right);
773     case wasm::kExprI32AsmjsRemU:
774       return BuildI32AsmjsRemU(left, right);
775     case wasm::kExprI32AsmjsStoreMem8:
776       return BuildAsmjsStoreMem(MachineType::Int8(), left, right);
777     case wasm::kExprI32AsmjsStoreMem16:
778       return BuildAsmjsStoreMem(MachineType::Int16(), left, right);
779     case wasm::kExprI32AsmjsStoreMem:
780       return BuildAsmjsStoreMem(MachineType::Int32(), left, right);
781     case wasm::kExprF32AsmjsStoreMem:
782       return BuildAsmjsStoreMem(MachineType::Float32(), left, right);
783     case wasm::kExprF64AsmjsStoreMem:
784       return BuildAsmjsStoreMem(MachineType::Float64(), left, right);
785     default:
786       op = UnsupportedOpcode(opcode);
787   }
788   return graph()->NewNode(op, left, right);
789 }
790 
Unop(wasm::WasmOpcode opcode,Node * input,wasm::WasmCodePosition position)791 Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input,
792                              wasm::WasmCodePosition position) {
793   const Operator* op;
794   MachineOperatorBuilder* m = jsgraph()->machine();
795   switch (opcode) {
796     case wasm::kExprI32Eqz:
797       op = m->Word32Equal();
798       return graph()->NewNode(op, input, jsgraph()->Int32Constant(0));
799     case wasm::kExprF32Abs:
800       op = m->Float32Abs();
801       break;
802     case wasm::kExprF32Neg: {
803       op = m->Float32Neg();
804       break;
805     }
806     case wasm::kExprF32Sqrt:
807       op = m->Float32Sqrt();
808       break;
809     case wasm::kExprF64Abs:
810       op = m->Float64Abs();
811       break;
812     case wasm::kExprF64Neg: {
813       op = m->Float64Neg();
814       break;
815     }
816     case wasm::kExprF64Sqrt:
817       op = m->Float64Sqrt();
818       break;
819     case wasm::kExprI32SConvertF64:
820       return BuildI32SConvertF64(input, position);
821     case wasm::kExprI32UConvertF64:
822       return BuildI32UConvertF64(input, position);
823     case wasm::kExprI32AsmjsSConvertF64:
824       return BuildI32AsmjsSConvertF64(input);
825     case wasm::kExprI32AsmjsUConvertF64:
826       return BuildI32AsmjsUConvertF64(input);
827     case wasm::kExprF32ConvertF64:
828       op = m->TruncateFloat64ToFloat32();
829       break;
830     case wasm::kExprF64SConvertI32:
831       op = m->ChangeInt32ToFloat64();
832       break;
833     case wasm::kExprF64UConvertI32:
834       op = m->ChangeUint32ToFloat64();
835       break;
836     case wasm::kExprF32SConvertI32:
837       op = m->RoundInt32ToFloat32();
838       break;
839     case wasm::kExprF32UConvertI32:
840       op = m->RoundUint32ToFloat32();
841       break;
842     case wasm::kExprI32SConvertF32:
843       return BuildI32SConvertF32(input, position);
844     case wasm::kExprI32UConvertF32:
845       return BuildI32UConvertF32(input, position);
846     case wasm::kExprI32AsmjsSConvertF32:
847       return BuildI32AsmjsSConvertF32(input);
848     case wasm::kExprI32AsmjsUConvertF32:
849       return BuildI32AsmjsUConvertF32(input);
850     case wasm::kExprF64ConvertF32:
851       op = m->ChangeFloat32ToFloat64();
852       break;
853     case wasm::kExprF32ReinterpretI32:
854       op = m->BitcastInt32ToFloat32();
855       break;
856     case wasm::kExprI32ReinterpretF32:
857       op = m->BitcastFloat32ToInt32();
858       break;
859     case wasm::kExprI32Clz:
860       op = m->Word32Clz();
861       break;
862     case wasm::kExprI32Ctz: {
863       if (m->Word32Ctz().IsSupported()) {
864         op = m->Word32Ctz().op();
865         break;
866       } else if (m->Word32ReverseBits().IsSupported()) {
867         Node* reversed = graph()->NewNode(m->Word32ReverseBits().op(), input);
868         Node* result = graph()->NewNode(m->Word32Clz(), reversed);
869         return result;
870       } else {
871         return BuildI32Ctz(input);
872       }
873     }
874     case wasm::kExprI32Popcnt: {
875       if (m->Word32Popcnt().IsSupported()) {
876         op = m->Word32Popcnt().op();
877         break;
878       } else {
879         return BuildI32Popcnt(input);
880       }
881     }
882     case wasm::kExprF32Floor: {
883       if (!m->Float32RoundDown().IsSupported()) return BuildF32Floor(input);
884       op = m->Float32RoundDown().op();
885       break;
886     }
887     case wasm::kExprF32Ceil: {
888       if (!m->Float32RoundUp().IsSupported()) return BuildF32Ceil(input);
889       op = m->Float32RoundUp().op();
890       break;
891     }
892     case wasm::kExprF32Trunc: {
893       if (!m->Float32RoundTruncate().IsSupported()) return BuildF32Trunc(input);
894       op = m->Float32RoundTruncate().op();
895       break;
896     }
897     case wasm::kExprF32NearestInt: {
898       if (!m->Float32RoundTiesEven().IsSupported())
899         return BuildF32NearestInt(input);
900       op = m->Float32RoundTiesEven().op();
901       break;
902     }
903     case wasm::kExprF64Floor: {
904       if (!m->Float64RoundDown().IsSupported()) return BuildF64Floor(input);
905       op = m->Float64RoundDown().op();
906       break;
907     }
908     case wasm::kExprF64Ceil: {
909       if (!m->Float64RoundUp().IsSupported()) return BuildF64Ceil(input);
910       op = m->Float64RoundUp().op();
911       break;
912     }
913     case wasm::kExprF64Trunc: {
914       if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input);
915       op = m->Float64RoundTruncate().op();
916       break;
917     }
918     case wasm::kExprF64NearestInt: {
919       if (!m->Float64RoundTiesEven().IsSupported())
920         return BuildF64NearestInt(input);
921       op = m->Float64RoundTiesEven().op();
922       break;
923     }
924     case wasm::kExprF64Acos: {
925       return BuildF64Acos(input);
926     }
927     case wasm::kExprF64Asin: {
928       return BuildF64Asin(input);
929     }
930     case wasm::kExprF64Atan:
931       op = m->Float64Atan();
932       break;
933     case wasm::kExprF64Cos: {
934       op = m->Float64Cos();
935       break;
936     }
937     case wasm::kExprF64Sin: {
938       op = m->Float64Sin();
939       break;
940     }
941     case wasm::kExprF64Tan: {
942       op = m->Float64Tan();
943       break;
944     }
945     case wasm::kExprF64Exp: {
946       op = m->Float64Exp();
947       break;
948     }
949     case wasm::kExprF64Log:
950       op = m->Float64Log();
951       break;
952     case wasm::kExprI32ConvertI64:
953       op = m->TruncateInt64ToInt32();
954       break;
955     case wasm::kExprI64SConvertI32:
956       op = m->ChangeInt32ToInt64();
957       break;
958     case wasm::kExprI64UConvertI32:
959       op = m->ChangeUint32ToUint64();
960       break;
961     case wasm::kExprF64ReinterpretI64:
962       op = m->BitcastInt64ToFloat64();
963       break;
964     case wasm::kExprI64ReinterpretF64:
965       op = m->BitcastFloat64ToInt64();
966       break;
967     case wasm::kExprI64Clz:
968       op = m->Word64Clz();
969       break;
970     case wasm::kExprI64Ctz: {
971       OptionalOperator ctz64 = m->Word64Ctz();
972       if (ctz64.IsSupported()) {
973         op = ctz64.op();
974         break;
975       } else if (m->Is32() && m->Word32Ctz().IsSupported()) {
976         op = ctz64.placeholder();
977         break;
978       } else if (m->Word64ReverseBits().IsSupported()) {
979         Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input);
980         Node* result = graph()->NewNode(m->Word64Clz(), reversed);
981         return result;
982       } else {
983         return BuildI64Ctz(input);
984       }
985     }
986     case wasm::kExprI64Popcnt: {
987       OptionalOperator popcnt64 = m->Word64Popcnt();
988       if (popcnt64.IsSupported()) {
989         op = popcnt64.op();
990       } else if (m->Is32() && m->Word32Popcnt().IsSupported()) {
991         op = popcnt64.placeholder();
992       } else {
993         return BuildI64Popcnt(input);
994       }
995       break;
996     }
997     case wasm::kExprI64Eqz:
998       op = m->Word64Equal();
999       return graph()->NewNode(op, input, jsgraph()->Int64Constant(0));
1000     case wasm::kExprF32SConvertI64:
1001       if (m->Is32()) {
1002         return BuildF32SConvertI64(input);
1003       }
1004       op = m->RoundInt64ToFloat32();
1005       break;
1006     case wasm::kExprF32UConvertI64:
1007       if (m->Is32()) {
1008         return BuildF32UConvertI64(input);
1009       }
1010       op = m->RoundUint64ToFloat32();
1011       break;
1012     case wasm::kExprF64SConvertI64:
1013       if (m->Is32()) {
1014         return BuildF64SConvertI64(input);
1015       }
1016       op = m->RoundInt64ToFloat64();
1017       break;
1018     case wasm::kExprF64UConvertI64:
1019       if (m->Is32()) {
1020         return BuildF64UConvertI64(input);
1021       }
1022       op = m->RoundUint64ToFloat64();
1023       break;
1024     case wasm::kExprI64SConvertF32:
1025       return BuildI64SConvertF32(input, position);
1026     case wasm::kExprI64SConvertF64:
1027       return BuildI64SConvertF64(input, position);
1028     case wasm::kExprI64UConvertF32:
1029       return BuildI64UConvertF32(input, position);
1030     case wasm::kExprI64UConvertF64:
1031       return BuildI64UConvertF64(input, position);
1032     case wasm::kExprI32AsmjsLoadMem8S:
1033       return BuildAsmjsLoadMem(MachineType::Int8(), input);
1034     case wasm::kExprI32AsmjsLoadMem8U:
1035       return BuildAsmjsLoadMem(MachineType::Uint8(), input);
1036     case wasm::kExprI32AsmjsLoadMem16S:
1037       return BuildAsmjsLoadMem(MachineType::Int16(), input);
1038     case wasm::kExprI32AsmjsLoadMem16U:
1039       return BuildAsmjsLoadMem(MachineType::Uint16(), input);
1040     case wasm::kExprI32AsmjsLoadMem:
1041       return BuildAsmjsLoadMem(MachineType::Int32(), input);
1042     case wasm::kExprF32AsmjsLoadMem:
1043       return BuildAsmjsLoadMem(MachineType::Float32(), input);
1044     case wasm::kExprF64AsmjsLoadMem:
1045       return BuildAsmjsLoadMem(MachineType::Float64(), input);
1046     default:
1047       op = UnsupportedOpcode(opcode);
1048   }
1049   return graph()->NewNode(op, input);
1050 }
1051 
Float32Constant(float value)1052 Node* WasmGraphBuilder::Float32Constant(float value) {
1053   return jsgraph()->Float32Constant(value);
1054 }
1055 
Float64Constant(double value)1056 Node* WasmGraphBuilder::Float64Constant(double value) {
1057   return jsgraph()->Float64Constant(value);
1058 }
1059 
HeapConstant(Handle<HeapObject> value)1060 Node* WasmGraphBuilder::HeapConstant(Handle<HeapObject> value) {
1061   return jsgraph()->HeapConstant(value);
1062 }
1063 
1064 namespace {
Branch(JSGraph * jsgraph,Node * cond,Node ** true_node,Node ** false_node,Node * control,BranchHint hint)1065 Node* Branch(JSGraph* jsgraph, Node* cond, Node** true_node, Node** false_node,
1066              Node* control, BranchHint hint) {
1067   DCHECK_NOT_NULL(cond);
1068   DCHECK_NOT_NULL(control);
1069   Node* branch =
1070       jsgraph->graph()->NewNode(jsgraph->common()->Branch(hint), cond, control);
1071   *true_node = jsgraph->graph()->NewNode(jsgraph->common()->IfTrue(), branch);
1072   *false_node = jsgraph->graph()->NewNode(jsgraph->common()->IfFalse(), branch);
1073   return branch;
1074 }
1075 }  // namespace
1076 
BranchNoHint(Node * cond,Node ** true_node,Node ** false_node)1077 Node* WasmGraphBuilder::BranchNoHint(Node* cond, Node** true_node,
1078                                      Node** false_node) {
1079   return Branch(jsgraph(), cond, true_node, false_node, *control_,
1080                 BranchHint::kNone);
1081 }
1082 
BranchExpectTrue(Node * cond,Node ** true_node,Node ** false_node)1083 Node* WasmGraphBuilder::BranchExpectTrue(Node* cond, Node** true_node,
1084                                          Node** false_node) {
1085   return Branch(jsgraph(), cond, true_node, false_node, *control_,
1086                 BranchHint::kTrue);
1087 }
1088 
BranchExpectFalse(Node * cond,Node ** true_node,Node ** false_node)1089 Node* WasmGraphBuilder::BranchExpectFalse(Node* cond, Node** true_node,
1090                                           Node** false_node) {
1091   return Branch(jsgraph(), cond, true_node, false_node, *control_,
1092                 BranchHint::kFalse);
1093 }
1094 
Switch(unsigned count,Node * key)1095 Node* WasmGraphBuilder::Switch(unsigned count, Node* key) {
1096   return graph()->NewNode(jsgraph()->common()->Switch(count), key, *control_);
1097 }
1098 
IfValue(int32_t value,Node * sw)1099 Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) {
1100   DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
1101   return graph()->NewNode(jsgraph()->common()->IfValue(value), sw);
1102 }
1103 
IfDefault(Node * sw)1104 Node* WasmGraphBuilder::IfDefault(Node* sw) {
1105   DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
1106   return graph()->NewNode(jsgraph()->common()->IfDefault(), sw);
1107 }
1108 
Return(unsigned count,Node ** vals)1109 Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
1110   DCHECK_NOT_NULL(*control_);
1111   DCHECK_NOT_NULL(*effect_);
1112 
1113   static const int kStackAllocatedNodeBufferSize = 8;
1114   Node* stack_buffer[kStackAllocatedNodeBufferSize];
1115   std::vector<Node*> heap_buffer;
1116 
1117   Node** buf = stack_buffer;
1118   if (count + 3 > kStackAllocatedNodeBufferSize) {
1119     heap_buffer.resize(count + 3);
1120     buf = heap_buffer.data();
1121   }
1122 
1123   buf[0] = jsgraph()->Int32Constant(0);
1124   memcpy(buf + 1, vals, sizeof(void*) * count);
1125   buf[count + 1] = *effect_;
1126   buf[count + 2] = *control_;
1127   Node* ret =
1128       graph()->NewNode(jsgraph()->common()->Return(count), count + 3, buf);
1129 
1130   MergeControlToEnd(jsgraph(), ret);
1131   return ret;
1132 }
1133 
ReturnVoid()1134 Node* WasmGraphBuilder::ReturnVoid() { return Return(0, Buffer(0)); }
1135 
Unreachable(wasm::WasmCodePosition position)1136 Node* WasmGraphBuilder::Unreachable(wasm::WasmCodePosition position) {
1137   trap_->Unreachable(position);
1138   return nullptr;
1139 }
1140 
MaskShiftCount32(Node * node)1141 Node* WasmGraphBuilder::MaskShiftCount32(Node* node) {
1142   static const int32_t kMask32 = 0x1f;
1143   if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
1144     // Shifts by constants are so common we pattern-match them here.
1145     Int32Matcher match(node);
1146     if (match.HasValue()) {
1147       int32_t masked = (match.Value() & kMask32);
1148       if (match.Value() != masked) node = jsgraph()->Int32Constant(masked);
1149     } else {
1150       node = graph()->NewNode(jsgraph()->machine()->Word32And(), node,
1151                               jsgraph()->Int32Constant(kMask32));
1152     }
1153   }
1154   return node;
1155 }
1156 
MaskShiftCount64(Node * node)1157 Node* WasmGraphBuilder::MaskShiftCount64(Node* node) {
1158   static const int64_t kMask64 = 0x3f;
1159   if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
1160     // Shifts by constants are so common we pattern-match them here.
1161     Int64Matcher match(node);
1162     if (match.HasValue()) {
1163       int64_t masked = (match.Value() & kMask64);
1164       if (match.Value() != masked) node = jsgraph()->Int64Constant(masked);
1165     } else {
1166       node = graph()->NewNode(jsgraph()->machine()->Word64And(), node,
1167                               jsgraph()->Int64Constant(kMask64));
1168     }
1169   }
1170   return node;
1171 }
1172 
ReverseBytesSupported(MachineOperatorBuilder * m,size_t size_in_bytes)1173 static bool ReverseBytesSupported(MachineOperatorBuilder* m,
1174                                   size_t size_in_bytes) {
1175   switch (size_in_bytes) {
1176     case 4:
1177       return m->Word32ReverseBytes().IsSupported();
1178     case 8:
1179       return m->Word64ReverseBytes().IsSupported();
1180     default:
1181       break;
1182   }
1183   return false;
1184 }
1185 
BuildChangeEndianness(Node * node,MachineType memtype,wasm::ValueType wasmtype)1186 Node* WasmGraphBuilder::BuildChangeEndianness(Node* node, MachineType memtype,
1187                                               wasm::ValueType wasmtype) {
1188   Node* result;
1189   Node* value = node;
1190   MachineOperatorBuilder* m = jsgraph()->machine();
1191   int valueSizeInBytes = 1 << ElementSizeLog2Of(memtype.representation());
1192   int valueSizeInBits = 8 * valueSizeInBytes;
1193   bool isFloat = false;
1194 
1195   switch (memtype.representation()) {
1196     case MachineRepresentation::kFloat64:
1197       value = graph()->NewNode(m->BitcastFloat64ToInt64(), node);
1198       isFloat = true;
1199     case MachineRepresentation::kWord64:
1200       result = jsgraph()->Int64Constant(0);
1201       break;
1202     case MachineRepresentation::kFloat32:
1203       value = graph()->NewNode(m->BitcastFloat32ToInt32(), node);
1204       isFloat = true;
1205     case MachineRepresentation::kWord32:
1206     case MachineRepresentation::kWord16:
1207       result = jsgraph()->Int32Constant(0);
1208       break;
1209     case MachineRepresentation::kWord8:
1210       // No need to change endianness for byte size, return original node
1211       return node;
1212       break;
1213     default:
1214       UNREACHABLE();
1215       break;
1216   }
1217 
1218   int i;
1219   uint32_t shiftCount;
1220 
1221   if (ReverseBytesSupported(m, valueSizeInBytes < 4 ? 4 : valueSizeInBytes)) {
1222     switch (valueSizeInBytes) {
1223       case 2:
1224         result =
1225             graph()->NewNode(m->Word32ReverseBytes().op(),
1226                              graph()->NewNode(m->Word32Shl(), value,
1227                                               jsgraph()->Int32Constant(16)));
1228         break;
1229       case 4:
1230         result = graph()->NewNode(m->Word32ReverseBytes().op(), value);
1231         break;
1232       case 8:
1233         result = graph()->NewNode(m->Word64ReverseBytes().op(), value);
1234         break;
1235       default:
1236         UNREACHABLE();
1237     }
1238   } else {
1239     for (i = 0, shiftCount = valueSizeInBits - 8; i < valueSizeInBits / 2;
1240          i += 8, shiftCount -= 16) {
1241       Node* shiftLower;
1242       Node* shiftHigher;
1243       Node* lowerByte;
1244       Node* higherByte;
1245 
1246       DCHECK(shiftCount > 0);
1247       DCHECK((shiftCount + 8) % 16 == 0);
1248 
1249       if (valueSizeInBits > 32) {
1250         shiftLower = graph()->NewNode(m->Word64Shl(), value,
1251                                       jsgraph()->Int64Constant(shiftCount));
1252         shiftHigher = graph()->NewNode(m->Word64Shr(), value,
1253                                        jsgraph()->Int64Constant(shiftCount));
1254         lowerByte = graph()->NewNode(
1255             m->Word64And(), shiftLower,
1256             jsgraph()->Int64Constant(static_cast<uint64_t>(0xFF)
1257                                      << (valueSizeInBits - 8 - i)));
1258         higherByte = graph()->NewNode(
1259             m->Word64And(), shiftHigher,
1260             jsgraph()->Int64Constant(static_cast<uint64_t>(0xFF) << i));
1261         result = graph()->NewNode(m->Word64Or(), result, lowerByte);
1262         result = graph()->NewNode(m->Word64Or(), result, higherByte);
1263       } else {
1264         shiftLower = graph()->NewNode(m->Word32Shl(), value,
1265                                       jsgraph()->Int32Constant(shiftCount));
1266         shiftHigher = graph()->NewNode(m->Word32Shr(), value,
1267                                        jsgraph()->Int32Constant(shiftCount));
1268         lowerByte = graph()->NewNode(
1269             m->Word32And(), shiftLower,
1270             jsgraph()->Int32Constant(static_cast<uint32_t>(0xFF)
1271                                      << (valueSizeInBits - 8 - i)));
1272         higherByte = graph()->NewNode(
1273             m->Word32And(), shiftHigher,
1274             jsgraph()->Int32Constant(static_cast<uint32_t>(0xFF) << i));
1275         result = graph()->NewNode(m->Word32Or(), result, lowerByte);
1276         result = graph()->NewNode(m->Word32Or(), result, higherByte);
1277       }
1278     }
1279   }
1280 
1281   if (isFloat) {
1282     switch (memtype.representation()) {
1283       case MachineRepresentation::kFloat64:
1284         result = graph()->NewNode(m->BitcastInt64ToFloat64(), result);
1285         break;
1286       case MachineRepresentation::kFloat32:
1287         result = graph()->NewNode(m->BitcastInt32ToFloat32(), result);
1288         break;
1289       default:
1290         UNREACHABLE();
1291         break;
1292     }
1293   }
1294 
1295   // We need to sign extend the value
1296   if (memtype.IsSigned()) {
1297     DCHECK(!isFloat);
1298     if (valueSizeInBits < 32) {
1299       Node* shiftBitCount;
1300       // Perform sign extension using following trick
1301       // result = (x << machine_width - type_width) >> (machine_width -
1302       // type_width)
1303       if (wasmtype == wasm::kWasmI64) {
1304         shiftBitCount = jsgraph()->Int32Constant(64 - valueSizeInBits);
1305         result = graph()->NewNode(
1306             m->Word64Sar(),
1307             graph()->NewNode(m->Word64Shl(),
1308                              graph()->NewNode(m->ChangeInt32ToInt64(), result),
1309                              shiftBitCount),
1310             shiftBitCount);
1311       } else if (wasmtype == wasm::kWasmI32) {
1312         shiftBitCount = jsgraph()->Int32Constant(32 - valueSizeInBits);
1313         result = graph()->NewNode(
1314             m->Word32Sar(),
1315             graph()->NewNode(m->Word32Shl(), result, shiftBitCount),
1316             shiftBitCount);
1317       }
1318     }
1319   }
1320 
1321   return result;
1322 }
1323 
BuildF32CopySign(Node * left,Node * right)1324 Node* WasmGraphBuilder::BuildF32CopySign(Node* left, Node* right) {
1325   Node* result = Unop(
1326       wasm::kExprF32ReinterpretI32,
1327       Binop(wasm::kExprI32Ior,
1328             Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, left),
1329                   jsgraph()->Int32Constant(0x7fffffff)),
1330             Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, right),
1331                   jsgraph()->Int32Constant(0x80000000))));
1332 
1333   return result;
1334 }
1335 
BuildF64CopySign(Node * left,Node * right)1336 Node* WasmGraphBuilder::BuildF64CopySign(Node* left, Node* right) {
1337 #if WASM_64
1338   Node* result = Unop(
1339       wasm::kExprF64ReinterpretI64,
1340       Binop(wasm::kExprI64Ior,
1341             Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, left),
1342                   jsgraph()->Int64Constant(0x7fffffffffffffff)),
1343             Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, right),
1344                   jsgraph()->Int64Constant(0x8000000000000000))));
1345 
1346   return result;
1347 #else
1348   MachineOperatorBuilder* m = jsgraph()->machine();
1349 
1350   Node* high_word_left = graph()->NewNode(m->Float64ExtractHighWord32(), left);
1351   Node* high_word_right =
1352       graph()->NewNode(m->Float64ExtractHighWord32(), right);
1353 
1354   Node* new_high_word =
1355       Binop(wasm::kExprI32Ior, Binop(wasm::kExprI32And, high_word_left,
1356                                      jsgraph()->Int32Constant(0x7fffffff)),
1357             Binop(wasm::kExprI32And, high_word_right,
1358                   jsgraph()->Int32Constant(0x80000000)));
1359 
1360   return graph()->NewNode(m->Float64InsertHighWord32(), left, new_high_word);
1361 #endif
1362 }
1363 
BuildI32SConvertF32(Node * input,wasm::WasmCodePosition position)1364 Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input,
1365                                             wasm::WasmCodePosition position) {
1366   MachineOperatorBuilder* m = jsgraph()->machine();
1367   // Truncation of the input value is needed for the overflow check later.
1368   Node* trunc = Unop(wasm::kExprF32Trunc, input);
1369   Node* result = graph()->NewNode(m->TruncateFloat32ToInt32(), trunc);
1370 
1371   // Convert the result back to f64. If we end up at a different value than the
1372   // truncated input value, then there has been an overflow and we trap.
1373   Node* check = Unop(wasm::kExprF32SConvertI32, result);
1374   Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
1375   trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
1376 
1377   return result;
1378 }
1379 
BuildI32SConvertF64(Node * input,wasm::WasmCodePosition position)1380 Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input,
1381                                             wasm::WasmCodePosition position) {
1382   MachineOperatorBuilder* m = jsgraph()->machine();
1383   // Truncation of the input value is needed for the overflow check later.
1384   Node* trunc = Unop(wasm::kExprF64Trunc, input);
1385   Node* result = graph()->NewNode(m->ChangeFloat64ToInt32(), trunc);
1386 
1387   // Convert the result back to f64. If we end up at a different value than the
1388   // truncated input value, then there has been an overflow and we trap.
1389   Node* check = Unop(wasm::kExprF64SConvertI32, result);
1390   Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
1391   trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
1392 
1393   return result;
1394 }
1395 
BuildI32UConvertF32(Node * input,wasm::WasmCodePosition position)1396 Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input,
1397                                             wasm::WasmCodePosition position) {
1398   MachineOperatorBuilder* m = jsgraph()->machine();
1399   // Truncation of the input value is needed for the overflow check later.
1400   Node* trunc = Unop(wasm::kExprF32Trunc, input);
1401   Node* result = graph()->NewNode(m->TruncateFloat32ToUint32(), trunc);
1402 
1403   // Convert the result back to f32. If we end up at a different value than the
1404   // truncated input value, then there has been an overflow and we trap.
1405   Node* check = Unop(wasm::kExprF32UConvertI32, result);
1406   Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
1407   trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
1408 
1409   return result;
1410 }
1411 
BuildI32UConvertF64(Node * input,wasm::WasmCodePosition position)1412 Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input,
1413                                             wasm::WasmCodePosition position) {
1414   MachineOperatorBuilder* m = jsgraph()->machine();
1415   // Truncation of the input value is needed for the overflow check later.
1416   Node* trunc = Unop(wasm::kExprF64Trunc, input);
1417   Node* result = graph()->NewNode(m->TruncateFloat64ToUint32(), trunc);
1418 
1419   // Convert the result back to f64. If we end up at a different value than the
1420   // truncated input value, then there has been an overflow and we trap.
1421   Node* check = Unop(wasm::kExprF64UConvertI32, result);
1422   Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
1423   trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
1424 
1425   return result;
1426 }
1427 
BuildI32AsmjsSConvertF32(Node * input)1428 Node* WasmGraphBuilder::BuildI32AsmjsSConvertF32(Node* input) {
1429   MachineOperatorBuilder* m = jsgraph()->machine();
1430   // asm.js must use the wacky JS semantics.
1431   input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1432   return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1433 }
1434 
BuildI32AsmjsSConvertF64(Node * input)1435 Node* WasmGraphBuilder::BuildI32AsmjsSConvertF64(Node* input) {
1436   MachineOperatorBuilder* m = jsgraph()->machine();
1437   // asm.js must use the wacky JS semantics.
1438   return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1439 }
1440 
BuildI32AsmjsUConvertF32(Node * input)1441 Node* WasmGraphBuilder::BuildI32AsmjsUConvertF32(Node* input) {
1442   MachineOperatorBuilder* m = jsgraph()->machine();
1443   // asm.js must use the wacky JS semantics.
1444   input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1445   return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1446 }
1447 
BuildI32AsmjsUConvertF64(Node * input)1448 Node* WasmGraphBuilder::BuildI32AsmjsUConvertF64(Node* input) {
1449   MachineOperatorBuilder* m = jsgraph()->machine();
1450   // asm.js must use the wacky JS semantics.
1451   return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1452 }
1453 
BuildBitCountingCall(Node * input,ExternalReference ref,MachineRepresentation input_type)1454 Node* WasmGraphBuilder::BuildBitCountingCall(Node* input, ExternalReference ref,
1455                                              MachineRepresentation input_type) {
1456   Node* stack_slot_param =
1457       graph()->NewNode(jsgraph()->machine()->StackSlot(input_type));
1458 
1459   const Operator* store_op = jsgraph()->machine()->Store(
1460       StoreRepresentation(input_type, kNoWriteBarrier));
1461   *effect_ =
1462       graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1463                        input, *effect_, *control_);
1464 
1465   MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 1);
1466   sig_builder.AddReturn(MachineType::Int32());
1467   sig_builder.AddParam(MachineType::Pointer());
1468 
1469   Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1470   Node* args[] = {function, stack_slot_param};
1471 
1472   return BuildCCall(sig_builder.Build(), args);
1473 }
1474 
BuildI32Ctz(Node * input)1475 Node* WasmGraphBuilder::BuildI32Ctz(Node* input) {
1476   return BuildBitCountingCall(
1477       input, ExternalReference::wasm_word32_ctz(jsgraph()->isolate()),
1478       MachineRepresentation::kWord32);
1479 }
1480 
BuildI64Ctz(Node * input)1481 Node* WasmGraphBuilder::BuildI64Ctz(Node* input) {
1482   return Unop(wasm::kExprI64UConvertI32,
1483               BuildBitCountingCall(input, ExternalReference::wasm_word64_ctz(
1484                                               jsgraph()->isolate()),
1485                                    MachineRepresentation::kWord64));
1486 }
1487 
BuildI32Popcnt(Node * input)1488 Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) {
1489   return BuildBitCountingCall(
1490       input, ExternalReference::wasm_word32_popcnt(jsgraph()->isolate()),
1491       MachineRepresentation::kWord32);
1492 }
1493 
BuildI64Popcnt(Node * input)1494 Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) {
1495   return Unop(wasm::kExprI64UConvertI32,
1496               BuildBitCountingCall(input, ExternalReference::wasm_word64_popcnt(
1497                                               jsgraph()->isolate()),
1498                                    MachineRepresentation::kWord64));
1499 }
1500 
BuildF32Trunc(Node * input)1501 Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
1502   MachineType type = MachineType::Float32();
1503   ExternalReference ref =
1504       ExternalReference::wasm_f32_trunc(jsgraph()->isolate());
1505 
1506   return BuildCFuncInstruction(ref, type, input);
1507 }
1508 
BuildF32Floor(Node * input)1509 Node* WasmGraphBuilder::BuildF32Floor(Node* input) {
1510   MachineType type = MachineType::Float32();
1511   ExternalReference ref =
1512       ExternalReference::wasm_f32_floor(jsgraph()->isolate());
1513   return BuildCFuncInstruction(ref, type, input);
1514 }
1515 
BuildF32Ceil(Node * input)1516 Node* WasmGraphBuilder::BuildF32Ceil(Node* input) {
1517   MachineType type = MachineType::Float32();
1518   ExternalReference ref =
1519       ExternalReference::wasm_f32_ceil(jsgraph()->isolate());
1520   return BuildCFuncInstruction(ref, type, input);
1521 }
1522 
BuildF32NearestInt(Node * input)1523 Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) {
1524   MachineType type = MachineType::Float32();
1525   ExternalReference ref =
1526       ExternalReference::wasm_f32_nearest_int(jsgraph()->isolate());
1527   return BuildCFuncInstruction(ref, type, input);
1528 }
1529 
BuildF64Trunc(Node * input)1530 Node* WasmGraphBuilder::BuildF64Trunc(Node* input) {
1531   MachineType type = MachineType::Float64();
1532   ExternalReference ref =
1533       ExternalReference::wasm_f64_trunc(jsgraph()->isolate());
1534   return BuildCFuncInstruction(ref, type, input);
1535 }
1536 
BuildF64Floor(Node * input)1537 Node* WasmGraphBuilder::BuildF64Floor(Node* input) {
1538   MachineType type = MachineType::Float64();
1539   ExternalReference ref =
1540       ExternalReference::wasm_f64_floor(jsgraph()->isolate());
1541   return BuildCFuncInstruction(ref, type, input);
1542 }
1543 
BuildF64Ceil(Node * input)1544 Node* WasmGraphBuilder::BuildF64Ceil(Node* input) {
1545   MachineType type = MachineType::Float64();
1546   ExternalReference ref =
1547       ExternalReference::wasm_f64_ceil(jsgraph()->isolate());
1548   return BuildCFuncInstruction(ref, type, input);
1549 }
1550 
BuildF64NearestInt(Node * input)1551 Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) {
1552   MachineType type = MachineType::Float64();
1553   ExternalReference ref =
1554       ExternalReference::wasm_f64_nearest_int(jsgraph()->isolate());
1555   return BuildCFuncInstruction(ref, type, input);
1556 }
1557 
BuildF64Acos(Node * input)1558 Node* WasmGraphBuilder::BuildF64Acos(Node* input) {
1559   MachineType type = MachineType::Float64();
1560   ExternalReference ref =
1561       ExternalReference::f64_acos_wrapper_function(jsgraph()->isolate());
1562   return BuildCFuncInstruction(ref, type, input);
1563 }
1564 
BuildF64Asin(Node * input)1565 Node* WasmGraphBuilder::BuildF64Asin(Node* input) {
1566   MachineType type = MachineType::Float64();
1567   ExternalReference ref =
1568       ExternalReference::f64_asin_wrapper_function(jsgraph()->isolate());
1569   return BuildCFuncInstruction(ref, type, input);
1570 }
1571 
BuildF64Pow(Node * left,Node * right)1572 Node* WasmGraphBuilder::BuildF64Pow(Node* left, Node* right) {
1573   MachineType type = MachineType::Float64();
1574   ExternalReference ref =
1575       ExternalReference::wasm_float64_pow(jsgraph()->isolate());
1576   return BuildCFuncInstruction(ref, type, left, right);
1577 }
1578 
BuildF64Mod(Node * left,Node * right)1579 Node* WasmGraphBuilder::BuildF64Mod(Node* left, Node* right) {
1580   MachineType type = MachineType::Float64();
1581   ExternalReference ref =
1582       ExternalReference::f64_mod_wrapper_function(jsgraph()->isolate());
1583   return BuildCFuncInstruction(ref, type, left, right);
1584 }
1585 
BuildCFuncInstruction(ExternalReference ref,MachineType type,Node * input0,Node * input1)1586 Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref,
1587                                               MachineType type, Node* input0,
1588                                               Node* input1) {
1589   // We do truncation by calling a C function which calculates the result.
1590   // The input is passed to the C function as a double*'s to avoid double
1591   // parameters. For this we reserve slots on the stack, store the parameters
1592   // in those slots, pass pointers to the slot to the C function,
1593   // and after calling the C function we collect the return value from
1594   // the stack slot.
1595 
1596   Node* stack_slot_param0 =
1597       graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation()));
1598 
1599   const Operator* store_op0 = jsgraph()->machine()->Store(
1600       StoreRepresentation(type.representation(), kNoWriteBarrier));
1601   *effect_ = graph()->NewNode(store_op0, stack_slot_param0,
1602                               jsgraph()->Int32Constant(0), input0, *effect_,
1603                               *control_);
1604 
1605   Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1606   Node** args = Buffer(5);
1607   args[0] = function;
1608   args[1] = stack_slot_param0;
1609   int input_count = 1;
1610 
1611   if (input1 != nullptr) {
1612     Node* stack_slot_param1 = graph()->NewNode(
1613         jsgraph()->machine()->StackSlot(type.representation()));
1614     const Operator* store_op1 = jsgraph()->machine()->Store(
1615         StoreRepresentation(type.representation(), kNoWriteBarrier));
1616     *effect_ = graph()->NewNode(store_op1, stack_slot_param1,
1617                                 jsgraph()->Int32Constant(0), input1, *effect_,
1618                                 *control_);
1619     args[2] = stack_slot_param1;
1620     ++input_count;
1621   }
1622 
1623   Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0,
1624                                               input_count);
1625   sig_builder.AddParam(MachineType::Pointer());
1626   if (input1 != nullptr) {
1627     sig_builder.AddParam(MachineType::Pointer());
1628   }
1629   BuildCCall(sig_builder.Build(), args);
1630 
1631   const Operator* load_op = jsgraph()->machine()->Load(type);
1632 
1633   Node* load =
1634       graph()->NewNode(load_op, stack_slot_param0, jsgraph()->Int32Constant(0),
1635                        *effect_, *control_);
1636   *effect_ = load;
1637   return load;
1638 }
1639 
BuildF32SConvertI64(Node * input)1640 Node* WasmGraphBuilder::BuildF32SConvertI64(Node* input) {
1641   // TODO(titzer/bradnelson): Check handlng of asm.js case.
1642   return BuildIntToFloatConversionInstruction(
1643       input, ExternalReference::wasm_int64_to_float32(jsgraph()->isolate()),
1644       MachineRepresentation::kWord64, MachineType::Float32());
1645 }
BuildF32UConvertI64(Node * input)1646 Node* WasmGraphBuilder::BuildF32UConvertI64(Node* input) {
1647   // TODO(titzer/bradnelson): Check handlng of asm.js case.
1648   return BuildIntToFloatConversionInstruction(
1649       input, ExternalReference::wasm_uint64_to_float32(jsgraph()->isolate()),
1650       MachineRepresentation::kWord64, MachineType::Float32());
1651 }
BuildF64SConvertI64(Node * input)1652 Node* WasmGraphBuilder::BuildF64SConvertI64(Node* input) {
1653   return BuildIntToFloatConversionInstruction(
1654       input, ExternalReference::wasm_int64_to_float64(jsgraph()->isolate()),
1655       MachineRepresentation::kWord64, MachineType::Float64());
1656 }
BuildF64UConvertI64(Node * input)1657 Node* WasmGraphBuilder::BuildF64UConvertI64(Node* input) {
1658   return BuildIntToFloatConversionInstruction(
1659       input, ExternalReference::wasm_uint64_to_float64(jsgraph()->isolate()),
1660       MachineRepresentation::kWord64, MachineType::Float64());
1661 }
1662 
BuildIntToFloatConversionInstruction(Node * input,ExternalReference ref,MachineRepresentation parameter_representation,const MachineType result_type)1663 Node* WasmGraphBuilder::BuildIntToFloatConversionInstruction(
1664     Node* input, ExternalReference ref,
1665     MachineRepresentation parameter_representation,
1666     const MachineType result_type) {
1667   Node* stack_slot_param = graph()->NewNode(
1668       jsgraph()->machine()->StackSlot(parameter_representation));
1669   Node* stack_slot_result = graph()->NewNode(
1670       jsgraph()->machine()->StackSlot(result_type.representation()));
1671   const Operator* store_op = jsgraph()->machine()->Store(
1672       StoreRepresentation(parameter_representation, kNoWriteBarrier));
1673   *effect_ =
1674       graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1675                        input, *effect_, *control_);
1676   MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 2);
1677   sig_builder.AddParam(MachineType::Pointer());
1678   sig_builder.AddParam(MachineType::Pointer());
1679   Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1680   Node* args[] = {function, stack_slot_param, stack_slot_result};
1681   BuildCCall(sig_builder.Build(), args);
1682   const Operator* load_op = jsgraph()->machine()->Load(result_type);
1683   Node* load =
1684       graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1685                        *effect_, *control_);
1686   *effect_ = load;
1687   return load;
1688 }
1689 
BuildI64SConvertF32(Node * input,wasm::WasmCodePosition position)1690 Node* WasmGraphBuilder::BuildI64SConvertF32(Node* input,
1691                                             wasm::WasmCodePosition position) {
1692   if (jsgraph()->machine()->Is32()) {
1693     return BuildFloatToIntConversionInstruction(
1694         input, ExternalReference::wasm_float32_to_int64(jsgraph()->isolate()),
1695         MachineRepresentation::kFloat32, MachineType::Int64(), position);
1696   } else {
1697     Node* trunc = graph()->NewNode(
1698         jsgraph()->machine()->TryTruncateFloat32ToInt64(), input);
1699     Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1700                                     graph()->start());
1701     Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1702                                       graph()->start());
1703     trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
1704     return result;
1705   }
1706 }
1707 
BuildI64UConvertF32(Node * input,wasm::WasmCodePosition position)1708 Node* WasmGraphBuilder::BuildI64UConvertF32(Node* input,
1709                                             wasm::WasmCodePosition position) {
1710   if (jsgraph()->machine()->Is32()) {
1711     return BuildFloatToIntConversionInstruction(
1712         input, ExternalReference::wasm_float32_to_uint64(jsgraph()->isolate()),
1713         MachineRepresentation::kFloat32, MachineType::Int64(), position);
1714   } else {
1715     Node* trunc = graph()->NewNode(
1716         jsgraph()->machine()->TryTruncateFloat32ToUint64(), input);
1717     Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1718                                     graph()->start());
1719     Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1720                                       graph()->start());
1721     trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
1722     return result;
1723   }
1724 }
1725 
BuildI64SConvertF64(Node * input,wasm::WasmCodePosition position)1726 Node* WasmGraphBuilder::BuildI64SConvertF64(Node* input,
1727                                             wasm::WasmCodePosition position) {
1728   if (jsgraph()->machine()->Is32()) {
1729     return BuildFloatToIntConversionInstruction(
1730         input, ExternalReference::wasm_float64_to_int64(jsgraph()->isolate()),
1731         MachineRepresentation::kFloat64, MachineType::Int64(), position);
1732   } else {
1733     Node* trunc = graph()->NewNode(
1734         jsgraph()->machine()->TryTruncateFloat64ToInt64(), input);
1735     Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1736                                     graph()->start());
1737     Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1738                                       graph()->start());
1739     trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
1740     return result;
1741   }
1742 }
1743 
BuildI64UConvertF64(Node * input,wasm::WasmCodePosition position)1744 Node* WasmGraphBuilder::BuildI64UConvertF64(Node* input,
1745                                             wasm::WasmCodePosition position) {
1746   if (jsgraph()->machine()->Is32()) {
1747     return BuildFloatToIntConversionInstruction(
1748         input, ExternalReference::wasm_float64_to_uint64(jsgraph()->isolate()),
1749         MachineRepresentation::kFloat64, MachineType::Int64(), position);
1750   } else {
1751     Node* trunc = graph()->NewNode(
1752         jsgraph()->machine()->TryTruncateFloat64ToUint64(), input);
1753     Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1754                                     graph()->start());
1755     Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1756                                       graph()->start());
1757     trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
1758     return result;
1759   }
1760 }
1761 
BuildFloatToIntConversionInstruction(Node * input,ExternalReference ref,MachineRepresentation parameter_representation,const MachineType result_type,wasm::WasmCodePosition position)1762 Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
1763     Node* input, ExternalReference ref,
1764     MachineRepresentation parameter_representation,
1765     const MachineType result_type, wasm::WasmCodePosition position) {
1766   Node* stack_slot_param = graph()->NewNode(
1767       jsgraph()->machine()->StackSlot(parameter_representation));
1768   Node* stack_slot_result = graph()->NewNode(
1769       jsgraph()->machine()->StackSlot(result_type.representation()));
1770   const Operator* store_op = jsgraph()->machine()->Store(
1771       StoreRepresentation(parameter_representation, kNoWriteBarrier));
1772   *effect_ =
1773       graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1774                        input, *effect_, *control_);
1775   MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
1776   sig_builder.AddReturn(MachineType::Int32());
1777   sig_builder.AddParam(MachineType::Pointer());
1778   sig_builder.AddParam(MachineType::Pointer());
1779   Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1780   Node* args[] = {function, stack_slot_param, stack_slot_result};
1781   trap_->ZeroCheck32(wasm::kTrapFloatUnrepresentable,
1782                      BuildCCall(sig_builder.Build(), args), position);
1783   const Operator* load_op = jsgraph()->machine()->Load(result_type);
1784   Node* load =
1785       graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1786                        *effect_, *control_);
1787   *effect_ = load;
1788   return load;
1789 }
1790 
GrowMemory(Node * input)1791 Node* WasmGraphBuilder::GrowMemory(Node* input) {
1792   Diamond check_input_range(
1793       graph(), jsgraph()->common(),
1794       graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(), input,
1795                        jsgraph()->Uint32Constant(FLAG_wasm_max_mem_pages)),
1796       BranchHint::kTrue);
1797 
1798   check_input_range.Chain(*control_);
1799 
1800   Node* parameters[] = {BuildChangeUint32ToSmi(input)};
1801   Node* old_effect = *effect_;
1802   Node* call = BuildCallToRuntime(Runtime::kWasmGrowMemory, jsgraph(),
1803                                   parameters, arraysize(parameters), effect_,
1804                                   check_input_range.if_true);
1805 
1806   Node* result = BuildChangeSmiToInt32(call);
1807 
1808   result = check_input_range.Phi(MachineRepresentation::kWord32, result,
1809                                  jsgraph()->Int32Constant(-1));
1810   *effect_ = graph()->NewNode(jsgraph()->common()->EffectPhi(2), call,
1811                               old_effect, check_input_range.merge);
1812   *control_ = check_input_range.merge;
1813   return result;
1814 }
1815 
Throw(Node * input)1816 Node* WasmGraphBuilder::Throw(Node* input) {
1817   MachineOperatorBuilder* machine = jsgraph()->machine();
1818 
1819   // Pass the thrown value as two SMIs:
1820   //
1821   // upper = static_cast<uint32_t>(input) >> 16;
1822   // lower = input & 0xFFFF;
1823   //
1824   // This is needed because we can't safely call BuildChangeInt32ToTagged from
1825   // this method.
1826   //
1827   // TODO(wasm): figure out how to properly pass this to the runtime function.
1828   Node* upper = BuildChangeInt32ToSmi(
1829       graph()->NewNode(machine->Word32Shr(), input, Int32Constant(16)));
1830   Node* lower = BuildChangeInt32ToSmi(
1831       graph()->NewNode(machine->Word32And(), input, Int32Constant(0xFFFFu)));
1832 
1833   Node* parameters[] = {lower, upper};  // thrown value
1834   return BuildCallToRuntime(Runtime::kWasmThrow, jsgraph(), parameters,
1835                             arraysize(parameters), effect_, *control_);
1836 }
1837 
Catch(Node * input,wasm::WasmCodePosition position)1838 Node* WasmGraphBuilder::Catch(Node* input, wasm::WasmCodePosition position) {
1839   CommonOperatorBuilder* common = jsgraph()->common();
1840 
1841   Node* parameters[] = {input};  // caught value
1842   Node* value =
1843       BuildCallToRuntime(Runtime::kWasmGetCaughtExceptionValue, jsgraph(),
1844                          parameters, arraysize(parameters), effect_, *control_);
1845 
1846   Node* is_smi;
1847   Node* is_heap;
1848   BranchExpectFalse(BuildTestNotSmi(value), &is_heap, &is_smi);
1849 
1850   // is_smi
1851   Node* smi_i32 = BuildChangeSmiToInt32(value);
1852   Node* is_smi_effect = *effect_;
1853 
1854   // is_heap
1855   *control_ = is_heap;
1856   Node* heap_f64 = BuildLoadHeapNumberValue(value, is_heap);
1857 
1858   // *control_ needs to point to the current control dependency (is_heap) in
1859   // case BuildI32SConvertF64 needs to insert nodes that depend on the "current"
1860   // control node.
1861   Node* heap_i32 = BuildI32SConvertF64(heap_f64, position);
1862   // *control_ contains the control node that should be used when merging the
1863   // result for the catch clause. It may be different than *control_ because
1864   // BuildI32SConvertF64 may introduce a new control node (used for trapping if
1865   // heap_f64 cannot be converted to an i32.
1866   is_heap = *control_;
1867   Node* is_heap_effect = *effect_;
1868 
1869   Node* merge = graph()->NewNode(common->Merge(2), is_heap, is_smi);
1870   Node* effect_merge = graph()->NewNode(common->EffectPhi(2), is_heap_effect,
1871                                         is_smi_effect, merge);
1872 
1873   Node* value_i32 = graph()->NewNode(
1874       common->Phi(MachineRepresentation::kWord32, 2), heap_i32, smi_i32, merge);
1875 
1876   *control_ = merge;
1877   *effect_ = effect_merge;
1878   return value_i32;
1879 }
1880 
BuildI32DivS(Node * left,Node * right,wasm::WasmCodePosition position)1881 Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
1882                                      wasm::WasmCodePosition position) {
1883   MachineOperatorBuilder* m = jsgraph()->machine();
1884   trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position);
1885   Node* before = *control_;
1886   Node* denom_is_m1;
1887   Node* denom_is_not_m1;
1888   BranchExpectFalse(
1889       graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1890       &denom_is_m1, &denom_is_not_m1);
1891   *control_ = denom_is_m1;
1892   trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt, position);
1893   if (*control_ != denom_is_m1) {
1894     *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1895                                  *control_);
1896   } else {
1897     *control_ = before;
1898   }
1899   return graph()->NewNode(m->Int32Div(), left, right, *control_);
1900 }
1901 
BuildI32RemS(Node * left,Node * right,wasm::WasmCodePosition position)1902 Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right,
1903                                      wasm::WasmCodePosition position) {
1904   MachineOperatorBuilder* m = jsgraph()->machine();
1905 
1906   trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position);
1907 
1908   Diamond d(
1909       graph(), jsgraph()->common(),
1910       graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1911       BranchHint::kFalse);
1912   d.Chain(*control_);
1913 
1914   return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1915                graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
1916 }
1917 
BuildI32DivU(Node * left,Node * right,wasm::WasmCodePosition position)1918 Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right,
1919                                      wasm::WasmCodePosition position) {
1920   MachineOperatorBuilder* m = jsgraph()->machine();
1921   return graph()->NewNode(
1922       m->Uint32Div(), left, right,
1923       trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position));
1924 }
1925 
BuildI32RemU(Node * left,Node * right,wasm::WasmCodePosition position)1926 Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right,
1927                                      wasm::WasmCodePosition position) {
1928   MachineOperatorBuilder* m = jsgraph()->machine();
1929   return graph()->NewNode(
1930       m->Uint32Mod(), left, right,
1931       trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position));
1932 }
1933 
BuildI32AsmjsDivS(Node * left,Node * right)1934 Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) {
1935   MachineOperatorBuilder* m = jsgraph()->machine();
1936 
1937   Int32Matcher mr(right);
1938   if (mr.HasValue()) {
1939     if (mr.Value() == 0) {
1940       return jsgraph()->Int32Constant(0);
1941     } else if (mr.Value() == -1) {
1942       // The result is the negation of the left input.
1943       return graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
1944     }
1945     return graph()->NewNode(m->Int32Div(), left, right, *control_);
1946   }
1947 
1948   // asm.js semantics return 0 on divide or mod by zero.
1949   if (m->Int32DivIsSafe()) {
1950     // The hardware instruction does the right thing (e.g. arm).
1951     return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
1952   }
1953 
1954   // Check denominator for zero.
1955   Diamond z(
1956       graph(), jsgraph()->common(),
1957       graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1958       BranchHint::kFalse);
1959 
1960   // Check numerator for -1. (avoid minint / -1 case).
1961   Diamond n(
1962       graph(), jsgraph()->common(),
1963       graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1964       BranchHint::kFalse);
1965 
1966   Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
1967   Node* neg =
1968       graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
1969 
1970   return n.Phi(
1971       MachineRepresentation::kWord32, neg,
1972       z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0), div));
1973 }
1974 
BuildI32AsmjsRemS(Node * left,Node * right)1975 Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) {
1976   CommonOperatorBuilder* c = jsgraph()->common();
1977   MachineOperatorBuilder* m = jsgraph()->machine();
1978   Node* const zero = jsgraph()->Int32Constant(0);
1979 
1980   Int32Matcher mr(right);
1981   if (mr.HasValue()) {
1982     if (mr.Value() == 0 || mr.Value() == -1) {
1983       return zero;
1984     }
1985     return graph()->NewNode(m->Int32Mod(), left, right, *control_);
1986   }
1987 
1988   // General case for signed integer modulus, with optimization for (unknown)
1989   // power of 2 right hand side.
1990   //
1991   //   if 0 < right then
1992   //     msk = right - 1
1993   //     if right & msk != 0 then
1994   //       left % right
1995   //     else
1996   //       if left < 0 then
1997   //         -(-left & msk)
1998   //       else
1999   //         left & msk
2000   //   else
2001   //     if right < -1 then
2002   //       left % right
2003   //     else
2004   //       zero
2005   //
2006   // Note: We do not use the Diamond helper class here, because it really hurts
2007   // readability with nested diamonds.
2008   Node* const minus_one = jsgraph()->Int32Constant(-1);
2009 
2010   const Operator* const merge_op = c->Merge(2);
2011   const Operator* const phi_op = c->Phi(MachineRepresentation::kWord32, 2);
2012 
2013   Node* check0 = graph()->NewNode(m->Int32LessThan(), zero, right);
2014   Node* branch0 =
2015       graph()->NewNode(c->Branch(BranchHint::kTrue), check0, graph()->start());
2016 
2017   Node* if_true0 = graph()->NewNode(c->IfTrue(), branch0);
2018   Node* true0;
2019   {
2020     Node* msk = graph()->NewNode(m->Int32Add(), right, minus_one);
2021 
2022     Node* check1 = graph()->NewNode(m->Word32And(), right, msk);
2023     Node* branch1 = graph()->NewNode(c->Branch(), check1, if_true0);
2024 
2025     Node* if_true1 = graph()->NewNode(c->IfTrue(), branch1);
2026     Node* true1 = graph()->NewNode(m->Int32Mod(), left, right, if_true1);
2027 
2028     Node* if_false1 = graph()->NewNode(c->IfFalse(), branch1);
2029     Node* false1;
2030     {
2031       Node* check2 = graph()->NewNode(m->Int32LessThan(), left, zero);
2032       Node* branch2 =
2033           graph()->NewNode(c->Branch(BranchHint::kFalse), check2, if_false1);
2034 
2035       Node* if_true2 = graph()->NewNode(c->IfTrue(), branch2);
2036       Node* true2 = graph()->NewNode(
2037           m->Int32Sub(), zero,
2038           graph()->NewNode(m->Word32And(),
2039                            graph()->NewNode(m->Int32Sub(), zero, left), msk));
2040 
2041       Node* if_false2 = graph()->NewNode(c->IfFalse(), branch2);
2042       Node* false2 = graph()->NewNode(m->Word32And(), left, msk);
2043 
2044       if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
2045       false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
2046     }
2047 
2048     if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
2049     true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
2050   }
2051 
2052   Node* if_false0 = graph()->NewNode(c->IfFalse(), branch0);
2053   Node* false0;
2054   {
2055     Node* check1 = graph()->NewNode(m->Int32LessThan(), right, minus_one);
2056     Node* branch1 =
2057         graph()->NewNode(c->Branch(BranchHint::kTrue), check1, if_false0);
2058 
2059     Node* if_true1 = graph()->NewNode(c->IfTrue(), branch1);
2060     Node* true1 = graph()->NewNode(m->Int32Mod(), left, right, if_true1);
2061 
2062     Node* if_false1 = graph()->NewNode(c->IfFalse(), branch1);
2063     Node* false1 = zero;
2064 
2065     if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
2066     false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
2067   }
2068 
2069   Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
2070   return graph()->NewNode(phi_op, true0, false0, merge0);
2071 }
2072 
BuildI32AsmjsDivU(Node * left,Node * right)2073 Node* WasmGraphBuilder::BuildI32AsmjsDivU(Node* left, Node* right) {
2074   MachineOperatorBuilder* m = jsgraph()->machine();
2075   // asm.js semantics return 0 on divide or mod by zero.
2076   if (m->Uint32DivIsSafe()) {
2077     // The hardware instruction does the right thing (e.g. arm).
2078     return graph()->NewNode(m->Uint32Div(), left, right, graph()->start());
2079   }
2080 
2081   // Explicit check for x % 0.
2082   Diamond z(
2083       graph(), jsgraph()->common(),
2084       graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
2085       BranchHint::kFalse);
2086 
2087   return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
2088                graph()->NewNode(jsgraph()->machine()->Uint32Div(), left, right,
2089                                 z.if_false));
2090 }
2091 
BuildI32AsmjsRemU(Node * left,Node * right)2092 Node* WasmGraphBuilder::BuildI32AsmjsRemU(Node* left, Node* right) {
2093   MachineOperatorBuilder* m = jsgraph()->machine();
2094   // asm.js semantics return 0 on divide or mod by zero.
2095   // Explicit check for x % 0.
2096   Diamond z(
2097       graph(), jsgraph()->common(),
2098       graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
2099       BranchHint::kFalse);
2100 
2101   Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
2102                                z.if_false);
2103   return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
2104                rem);
2105 }
2106 
BuildI64DivS(Node * left,Node * right,wasm::WasmCodePosition position)2107 Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
2108                                      wasm::WasmCodePosition position) {
2109   if (jsgraph()->machine()->Is32()) {
2110     return BuildDiv64Call(
2111         left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
2112         MachineType::Int64(), wasm::kTrapDivByZero, position);
2113   }
2114   trap_->ZeroCheck64(wasm::kTrapDivByZero, right, position);
2115   Node* before = *control_;
2116   Node* denom_is_m1;
2117   Node* denom_is_not_m1;
2118   BranchExpectFalse(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
2119                                      jsgraph()->Int64Constant(-1)),
2120                     &denom_is_m1, &denom_is_not_m1);
2121   *control_ = denom_is_m1;
2122   trap_->TrapIfEq64(wasm::kTrapDivUnrepresentable, left,
2123                     std::numeric_limits<int64_t>::min(), position);
2124   if (*control_ != denom_is_m1) {
2125     *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
2126                                  *control_);
2127   } else {
2128     *control_ = before;
2129   }
2130   return graph()->NewNode(jsgraph()->machine()->Int64Div(), left, right,
2131                           *control_);
2132 }
2133 
BuildI64RemS(Node * left,Node * right,wasm::WasmCodePosition position)2134 Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right,
2135                                      wasm::WasmCodePosition position) {
2136   if (jsgraph()->machine()->Is32()) {
2137     return BuildDiv64Call(
2138         left, right, ExternalReference::wasm_int64_mod(jsgraph()->isolate()),
2139         MachineType::Int64(), wasm::kTrapRemByZero, position);
2140   }
2141   trap_->ZeroCheck64(wasm::kTrapRemByZero, right, position);
2142   Diamond d(jsgraph()->graph(), jsgraph()->common(),
2143             graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
2144                              jsgraph()->Int64Constant(-1)));
2145 
2146   d.Chain(*control_);
2147 
2148   Node* rem = graph()->NewNode(jsgraph()->machine()->Int64Mod(), left, right,
2149                                d.if_false);
2150 
2151   return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
2152                rem);
2153 }
2154 
BuildI64DivU(Node * left,Node * right,wasm::WasmCodePosition position)2155 Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right,
2156                                      wasm::WasmCodePosition position) {
2157   if (jsgraph()->machine()->Is32()) {
2158     return BuildDiv64Call(
2159         left, right, ExternalReference::wasm_uint64_div(jsgraph()->isolate()),
2160         MachineType::Int64(), wasm::kTrapDivByZero, position);
2161   }
2162   return graph()->NewNode(
2163       jsgraph()->machine()->Uint64Div(), left, right,
2164       trap_->ZeroCheck64(wasm::kTrapDivByZero, right, position));
2165 }
BuildI64RemU(Node * left,Node * right,wasm::WasmCodePosition position)2166 Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right,
2167                                      wasm::WasmCodePosition position) {
2168   if (jsgraph()->machine()->Is32()) {
2169     return BuildDiv64Call(
2170         left, right, ExternalReference::wasm_uint64_mod(jsgraph()->isolate()),
2171         MachineType::Int64(), wasm::kTrapRemByZero, position);
2172   }
2173   return graph()->NewNode(
2174       jsgraph()->machine()->Uint64Mod(), left, right,
2175       trap_->ZeroCheck64(wasm::kTrapRemByZero, right, position));
2176 }
2177 
BuildDiv64Call(Node * left,Node * right,ExternalReference ref,MachineType result_type,int trap_zero,wasm::WasmCodePosition position)2178 Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
2179                                        ExternalReference ref,
2180                                        MachineType result_type, int trap_zero,
2181                                        wasm::WasmCodePosition position) {
2182   Node* stack_slot_dst = graph()->NewNode(
2183       jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
2184   Node* stack_slot_src = graph()->NewNode(
2185       jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
2186 
2187   const Operator* store_op = jsgraph()->machine()->Store(
2188       StoreRepresentation(MachineRepresentation::kWord64, kNoWriteBarrier));
2189   *effect_ =
2190       graph()->NewNode(store_op, stack_slot_dst, jsgraph()->Int32Constant(0),
2191                        left, *effect_, *control_);
2192   *effect_ =
2193       graph()->NewNode(store_op, stack_slot_src, jsgraph()->Int32Constant(0),
2194                        right, *effect_, *control_);
2195 
2196   MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
2197   sig_builder.AddReturn(MachineType::Int32());
2198   sig_builder.AddParam(MachineType::Pointer());
2199   sig_builder.AddParam(MachineType::Pointer());
2200 
2201   Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
2202   Node* args[] = {function, stack_slot_dst, stack_slot_src};
2203 
2204   Node* call = BuildCCall(sig_builder.Build(), args);
2205 
2206   // TODO(wasm): This can get simpler if we have a specialized runtime call to
2207   // throw WASM exceptions by trap code instead of by string.
2208   trap_->ZeroCheck32(static_cast<wasm::TrapReason>(trap_zero), call, position);
2209   trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position);
2210   const Operator* load_op = jsgraph()->machine()->Load(result_type);
2211   Node* load =
2212       graph()->NewNode(load_op, stack_slot_dst, jsgraph()->Int32Constant(0),
2213                        *effect_, *control_);
2214   *effect_ = load;
2215   return load;
2216 }
2217 
BuildCCall(MachineSignature * sig,Node ** args)2218 Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
2219   const size_t params = sig->parameter_count();
2220   const size_t extra = 2;  // effect and control inputs.
2221   const size_t count = 1 + params + extra;
2222 
2223   // Reallocate the buffer to make space for extra inputs.
2224   args = Realloc(args, 1 + params, count);
2225 
2226   // Add effect and control inputs.
2227   args[params + 1] = *effect_;
2228   args[params + 2] = *control_;
2229 
2230   CallDescriptor* desc =
2231       Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig);
2232 
2233   const Operator* op = jsgraph()->common()->Call(desc);
2234   Node* call = graph()->NewNode(op, static_cast<int>(count), args);
2235   *effect_ = call;
2236   return call;
2237 }
2238 
BuildWasmCall(wasm::FunctionSig * sig,Node ** args,Node *** rets,wasm::WasmCodePosition position)2239 Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
2240                                       Node*** rets,
2241                                       wasm::WasmCodePosition position) {
2242   const size_t params = sig->parameter_count();
2243   const size_t extra = 2;  // effect and control inputs.
2244   const size_t count = 1 + params + extra;
2245 
2246   // Reallocate the buffer to make space for extra inputs.
2247   args = Realloc(args, 1 + params, count);
2248 
2249   // Add effect and control inputs.
2250   args[params + 1] = *effect_;
2251   args[params + 2] = *control_;
2252 
2253   CallDescriptor* descriptor =
2254       wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
2255   const Operator* op = jsgraph()->common()->Call(descriptor);
2256   Node* call = graph()->NewNode(op, static_cast<int>(count), args);
2257   SetSourcePosition(call, position);
2258 
2259   *effect_ = call;
2260   size_t ret_count = sig->return_count();
2261   if (ret_count == 0) return call;  // No return value.
2262 
2263   *rets = Buffer(ret_count);
2264   if (ret_count == 1) {
2265     // Only a single return value.
2266     (*rets)[0] = call;
2267   } else {
2268     // Create projections for all return values.
2269     for (size_t i = 0; i < ret_count; i++) {
2270       (*rets)[i] = graph()->NewNode(jsgraph()->common()->Projection(i), call,
2271                                     graph()->start());
2272     }
2273   }
2274   return call;
2275 }
2276 
CallDirect(uint32_t index,Node ** args,Node *** rets,wasm::WasmCodePosition position)2277 Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args, Node*** rets,
2278                                    wasm::WasmCodePosition position) {
2279   DCHECK_NULL(args[0]);
2280 
2281   // Add code object as constant.
2282   Handle<Code> code = module_->GetFunctionCode(index);
2283   DCHECK(!code.is_null());
2284   args[0] = HeapConstant(code);
2285   wasm::FunctionSig* sig = module_->GetFunctionSignature(index);
2286 
2287   return BuildWasmCall(sig, args, rets, position);
2288 }
2289 
CallIndirect(uint32_t sig_index,Node ** args,Node *** rets,wasm::WasmCodePosition position)2290 Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
2291                                      Node*** rets,
2292                                      wasm::WasmCodePosition position) {
2293   DCHECK_NOT_NULL(args[0]);
2294   DCHECK(module_ && module_->instance);
2295 
2296   // Assume only one table for now.
2297   uint32_t table_index = 0;
2298   wasm::FunctionSig* sig = module_->GetSignature(sig_index);
2299 
2300   DCHECK(module_->IsValidTable(table_index));
2301 
2302   EnsureFunctionTableNodes();
2303   MachineOperatorBuilder* machine = jsgraph()->machine();
2304   Node* key = args[0];
2305 
2306   // Bounds check against the table size.
2307   Node* size = function_table_sizes_[table_index];
2308   Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
2309   trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, in_bounds, position);
2310   Node* table = function_tables_[table_index];
2311   Node* signatures = signature_tables_[table_index];
2312 
2313   // Load signature from the table and check.
2314   // The table is a FixedArray; signatures are encoded as SMIs.
2315   // [sig1, sig2, sig3, ...., code1, code2, code3 ...]
2316   ElementAccess access = AccessBuilder::ForFixedArrayElement();
2317   const int fixed_offset = access.header_size - access.tag();
2318   {
2319     Node* load_sig = graph()->NewNode(
2320         machine->Load(MachineType::AnyTagged()), signatures,
2321         graph()->NewNode(machine->Int32Add(),
2322                          graph()->NewNode(machine->Word32Shl(), key,
2323                                           Int32Constant(kPointerSizeLog2)),
2324                          Int32Constant(fixed_offset)),
2325         *effect_, *control_);
2326     auto map = const_cast<wasm::SignatureMap&>(
2327         module_->module->function_tables[0].map);
2328     Node* sig_match = graph()->NewNode(
2329         machine->WordEqual(), load_sig,
2330         jsgraph()->SmiConstant(static_cast<int>(map.FindOrInsert(sig))));
2331     trap_->AddTrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position);
2332   }
2333 
2334   // Load code object from the table.
2335   Node* load_code = graph()->NewNode(
2336       machine->Load(MachineType::AnyTagged()), table,
2337       graph()->NewNode(machine->Int32Add(),
2338                        graph()->NewNode(machine->Word32Shl(), key,
2339                                         Int32Constant(kPointerSizeLog2)),
2340                        Uint32Constant(fixed_offset)),
2341       *effect_, *control_);
2342 
2343   args[0] = load_code;
2344   return BuildWasmCall(sig, args, rets, position);
2345 }
2346 
BuildI32Rol(Node * left,Node * right)2347 Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
2348   // Implement Rol by Ror since TurboFan does not have Rol opcode.
2349   // TODO(weiliang): support Word32Rol opcode in TurboFan.
2350   Int32Matcher m(right);
2351   if (m.HasValue()) {
2352     return Binop(wasm::kExprI32Ror, left,
2353                  jsgraph()->Int32Constant(32 - m.Value()));
2354   } else {
2355     return Binop(wasm::kExprI32Ror, left,
2356                  Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(32), right));
2357   }
2358 }
2359 
BuildI64Rol(Node * left,Node * right)2360 Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) {
2361   // Implement Rol by Ror since TurboFan does not have Rol opcode.
2362   // TODO(weiliang): support Word64Rol opcode in TurboFan.
2363   Int64Matcher m(right);
2364   if (m.HasValue()) {
2365     return Binop(wasm::kExprI64Ror, left,
2366                  jsgraph()->Int64Constant(64 - m.Value()));
2367   } else {
2368     return Binop(wasm::kExprI64Ror, left,
2369                  Binop(wasm::kExprI64Sub, jsgraph()->Int64Constant(64), right));
2370   }
2371 }
2372 
Invert(Node * node)2373 Node* WasmGraphBuilder::Invert(Node* node) {
2374   return Unop(wasm::kExprI32Eqz, node);
2375 }
2376 
BuildChangeInt32ToTagged(Node * value)2377 Node* WasmGraphBuilder::BuildChangeInt32ToTagged(Node* value) {
2378   MachineOperatorBuilder* machine = jsgraph()->machine();
2379   CommonOperatorBuilder* common = jsgraph()->common();
2380 
2381   if (machine->Is64()) {
2382     return BuildChangeInt32ToSmi(value);
2383   }
2384 
2385   Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value,
2386                                graph()->start());
2387 
2388   Node* ovf = graph()->NewNode(common->Projection(1), add, graph()->start());
2389   Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf,
2390                                   graph()->start());
2391 
2392   Node* if_true = graph()->NewNode(common->IfTrue(), branch);
2393   Node* vtrue = BuildAllocateHeapNumberWithValue(
2394       graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true);
2395 
2396   Node* if_false = graph()->NewNode(common->IfFalse(), branch);
2397   Node* vfalse = graph()->NewNode(common->Projection(0), add, if_false);
2398 
2399   Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false);
2400   Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
2401                                vtrue, vfalse, merge);
2402   return phi;
2403 }
2404 
BuildChangeFloat64ToTagged(Node * value)2405 Node* WasmGraphBuilder::BuildChangeFloat64ToTagged(Node* value) {
2406   MachineOperatorBuilder* machine = jsgraph()->machine();
2407   CommonOperatorBuilder* common = jsgraph()->common();
2408 
2409   Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value);
2410   Node* check_same = graph()->NewNode(
2411       machine->Float64Equal(), value,
2412       graph()->NewNode(machine->ChangeInt32ToFloat64(), value32));
2413   Node* branch_same =
2414       graph()->NewNode(common->Branch(), check_same, graph()->start());
2415 
2416   Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same);
2417   Node* vsmi;
2418   Node* if_box = graph()->NewNode(common->IfFalse(), branch_same);
2419   Node* vbox;
2420 
2421   // We only need to check for -0 if the {value} can potentially contain -0.
2422   Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32,
2423                                       jsgraph()->Int32Constant(0));
2424   Node* branch_zero =
2425       graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi);
2426 
2427   Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero);
2428   Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero);
2429 
2430   // In case of 0, we need to check the high bits for the IEEE -0 pattern.
2431   Node* check_negative = graph()->NewNode(
2432       machine->Int32LessThan(),
2433       graph()->NewNode(machine->Float64ExtractHighWord32(), value),
2434       jsgraph()->Int32Constant(0));
2435   Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse),
2436                                            check_negative, if_zero);
2437 
2438   Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative);
2439   Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative);
2440 
2441   // We need to create a box for negative 0.
2442   if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative);
2443   if_box = graph()->NewNode(common->Merge(2), if_box, if_negative);
2444 
2445   // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
2446   // machines we need to deal with potential overflow and fallback to boxing.
2447   if (machine->Is64()) {
2448     vsmi = BuildChangeInt32ToSmi(value32);
2449   } else {
2450     Node* smi_tag = graph()->NewNode(machine->Int32AddWithOverflow(), value32,
2451                                      value32, if_smi);
2452 
2453     Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag, if_smi);
2454     Node* branch_ovf =
2455         graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi);
2456 
2457     Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf);
2458     if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box);
2459 
2460     if_smi = graph()->NewNode(common->IfFalse(), branch_ovf);
2461     vsmi = graph()->NewNode(common->Projection(0), smi_tag, if_smi);
2462   }
2463 
2464   // Allocate the box for the {value}.
2465   vbox = BuildAllocateHeapNumberWithValue(value, if_box);
2466 
2467   Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box);
2468   value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi,
2469                            vbox, control);
2470   return value;
2471 }
2472 
ToJS(Node * node,wasm::ValueType type)2473 Node* WasmGraphBuilder::ToJS(Node* node, wasm::ValueType type) {
2474   switch (type) {
2475     case wasm::kWasmI32:
2476       return BuildChangeInt32ToTagged(node);
2477     case wasm::kWasmS128:
2478     case wasm::kWasmI64:
2479       UNREACHABLE();
2480     case wasm::kWasmF32:
2481       node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
2482                               node);
2483       return BuildChangeFloat64ToTagged(node);
2484     case wasm::kWasmF64:
2485       return BuildChangeFloat64ToTagged(node);
2486     case wasm::kWasmStmt:
2487       return jsgraph()->UndefinedConstant();
2488     default:
2489       UNREACHABLE();
2490       return nullptr;
2491   }
2492 }
2493 
BuildJavaScriptToNumber(Node * node,Node * context)2494 Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context) {
2495   Callable callable = CodeFactory::ToNumber(jsgraph()->isolate());
2496   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
2497       jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
2498       CallDescriptor::kNoFlags, Operator::kNoProperties);
2499   Node* stub_code = jsgraph()->HeapConstant(callable.code());
2500 
2501   Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
2502                                   node, context, *effect_, *control_);
2503 
2504   SetSourcePosition(result, 1);
2505 
2506   *effect_ = result;
2507 
2508   return result;
2509 }
2510 
CanCover(Node * value,IrOpcode::Value opcode)2511 bool CanCover(Node* value, IrOpcode::Value opcode) {
2512   if (value->opcode() != opcode) return false;
2513   bool first = true;
2514   for (Edge const edge : value->use_edges()) {
2515     if (NodeProperties::IsControlEdge(edge)) continue;
2516     if (NodeProperties::IsEffectEdge(edge)) continue;
2517     DCHECK(NodeProperties::IsValueEdge(edge));
2518     if (!first) return false;
2519     first = false;
2520   }
2521   return true;
2522 }
2523 
BuildChangeTaggedToFloat64(Node * value)2524 Node* WasmGraphBuilder::BuildChangeTaggedToFloat64(Node* value) {
2525   MachineOperatorBuilder* machine = jsgraph()->machine();
2526   CommonOperatorBuilder* common = jsgraph()->common();
2527 
2528   if (CanCover(value, IrOpcode::kJSToNumber)) {
2529     // ChangeTaggedToFloat64(JSToNumber(x)) =>
2530     //   if IsSmi(x) then ChangeSmiToFloat64(x)
2531     //   else let y = JSToNumber(x) in
2532     //     if IsSmi(y) then ChangeSmiToFloat64(y)
2533     //     else BuildLoadHeapNumberValue(y)
2534     Node* object = NodeProperties::GetValueInput(value, 0);
2535     Node* context = NodeProperties::GetContextInput(value);
2536     Node* frame_state = NodeProperties::GetFrameStateInput(value);
2537     Node* effect = NodeProperties::GetEffectInput(value);
2538     Node* control = NodeProperties::GetControlInput(value);
2539 
2540     const Operator* merge_op = common->Merge(2);
2541     const Operator* ephi_op = common->EffectPhi(2);
2542     const Operator* phi_op = common->Phi(MachineRepresentation::kFloat64, 2);
2543 
2544     Node* check1 = BuildTestNotSmi(object);
2545     Node* branch1 =
2546         graph()->NewNode(common->Branch(BranchHint::kFalse), check1, control);
2547 
2548     Node* if_true1 = graph()->NewNode(common->IfTrue(), branch1);
2549     Node* vtrue1 = graph()->NewNode(value->op(), object, context, frame_state,
2550                                     effect, if_true1);
2551     Node* etrue1 = vtrue1;
2552 
2553     Node* check2 = BuildTestNotSmi(vtrue1);
2554     Node* branch2 = graph()->NewNode(common->Branch(), check2, if_true1);
2555 
2556     Node* if_true2 = graph()->NewNode(common->IfTrue(), branch2);
2557     Node* vtrue2 = BuildLoadHeapNumberValue(vtrue1, if_true2);
2558 
2559     Node* if_false2 = graph()->NewNode(common->IfFalse(), branch2);
2560     Node* vfalse2 = BuildChangeSmiToFloat64(vtrue1);
2561 
2562     if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
2563     vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
2564 
2565     Node* if_false1 = graph()->NewNode(common->IfFalse(), branch1);
2566     Node* vfalse1 = BuildChangeSmiToFloat64(object);
2567     Node* efalse1 = effect;
2568 
2569     Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
2570     Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
2571     Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
2572 
2573     // Wire the new diamond into the graph, {JSToNumber} can still throw.
2574     NodeProperties::ReplaceUses(value, phi1, ephi1, etrue1, etrue1);
2575 
2576     // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
2577     // the node and places it inside the diamond. Come up with a helper method!
2578     for (Node* use : etrue1->uses()) {
2579       if (use->opcode() == IrOpcode::kIfSuccess) {
2580         use->ReplaceUses(merge1);
2581         NodeProperties::ReplaceControlInput(branch2, use);
2582       }
2583     }
2584     return phi1;
2585   }
2586 
2587   Node* check = BuildTestNotSmi(value);
2588   Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
2589                                   graph()->start());
2590 
2591   Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
2592 
2593   Node* vnot_smi;
2594   Node* check_undefined = graph()->NewNode(machine->WordEqual(), value,
2595                                            jsgraph()->UndefinedConstant());
2596   Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse),
2597                                             check_undefined, if_not_smi);
2598 
2599   Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined);
2600   Node* vundefined =
2601       jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
2602 
2603   Node* if_not_undefined =
2604       graph()->NewNode(common->IfFalse(), branch_undefined);
2605   Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined);
2606 
2607   if_not_smi =
2608       graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined);
2609   vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
2610                               vundefined, vheap_number, if_not_smi);
2611 
2612   Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
2613   Node* vfrom_smi = BuildChangeSmiToFloat64(value);
2614 
2615   Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
2616   Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
2617                                vnot_smi, vfrom_smi, merge);
2618 
2619   return phi;
2620 }
2621 
FromJS(Node * node,Node * context,wasm::ValueType type)2622 Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
2623                                wasm::ValueType type) {
2624   DCHECK_NE(wasm::kWasmStmt, type);
2625 
2626   // Do a JavaScript ToNumber.
2627   Node* num = BuildJavaScriptToNumber(node, context);
2628 
2629   // Change representation.
2630   SimplifiedOperatorBuilder simplified(jsgraph()->zone());
2631   num = BuildChangeTaggedToFloat64(num);
2632 
2633   switch (type) {
2634     case wasm::kWasmI32: {
2635       num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
2636                              num);
2637       break;
2638     }
2639     case wasm::kWasmS128:
2640     case wasm::kWasmI64:
2641       UNREACHABLE();
2642     case wasm::kWasmF32:
2643       num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToFloat32(),
2644                              num);
2645       break;
2646     case wasm::kWasmF64:
2647       break;
2648     default:
2649       UNREACHABLE();
2650       return nullptr;
2651   }
2652   return num;
2653 }
2654 
BuildChangeInt32ToSmi(Node * value)2655 Node* WasmGraphBuilder::BuildChangeInt32ToSmi(Node* value) {
2656   if (jsgraph()->machine()->Is64()) {
2657     value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value);
2658   }
2659   return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
2660                           BuildSmiShiftBitsConstant());
2661 }
2662 
BuildChangeSmiToInt32(Node * value)2663 Node* WasmGraphBuilder::BuildChangeSmiToInt32(Node* value) {
2664   value = graph()->NewNode(jsgraph()->machine()->WordSar(), value,
2665                            BuildSmiShiftBitsConstant());
2666   if (jsgraph()->machine()->Is64()) {
2667     value =
2668         graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value);
2669   }
2670   return value;
2671 }
2672 
BuildChangeUint32ToSmi(Node * value)2673 Node* WasmGraphBuilder::BuildChangeUint32ToSmi(Node* value) {
2674   if (jsgraph()->machine()->Is64()) {
2675     value =
2676         graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), value);
2677   }
2678   return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
2679                           BuildSmiShiftBitsConstant());
2680 }
2681 
BuildChangeSmiToFloat64(Node * value)2682 Node* WasmGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
2683   return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
2684                           BuildChangeSmiToInt32(value));
2685 }
2686 
BuildTestNotSmi(Node * value)2687 Node* WasmGraphBuilder::BuildTestNotSmi(Node* value) {
2688   STATIC_ASSERT(kSmiTag == 0);
2689   STATIC_ASSERT(kSmiTagMask == 1);
2690   return graph()->NewNode(jsgraph()->machine()->WordAnd(), value,
2691                           jsgraph()->IntPtrConstant(kSmiTagMask));
2692 }
2693 
BuildSmiShiftBitsConstant()2694 Node* WasmGraphBuilder::BuildSmiShiftBitsConstant() {
2695   return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
2696 }
2697 
BuildAllocateHeapNumberWithValue(Node * value,Node * control)2698 Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
2699                                                          Node* control) {
2700   MachineOperatorBuilder* machine = jsgraph()->machine();
2701   CommonOperatorBuilder* common = jsgraph()->common();
2702   // The AllocateHeapNumberStub does not use the context, so we can safely pass
2703   // in Smi zero here.
2704   Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
2705   Node* target = jsgraph()->HeapConstant(callable.code());
2706   Node* context = jsgraph()->NoContextConstant();
2707   Node* effect =
2708       graph()->NewNode(common->BeginRegion(RegionObservability::kNotObservable),
2709                        graph()->start());
2710   if (!allocate_heap_number_operator_.is_set()) {
2711     CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
2712         jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
2713         CallDescriptor::kNoFlags, Operator::kNoThrow);
2714     allocate_heap_number_operator_.set(common->Call(descriptor));
2715   }
2716   Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
2717                                        target, context, effect, control);
2718   Node* store =
2719       graph()->NewNode(machine->Store(StoreRepresentation(
2720                            MachineRepresentation::kFloat64, kNoWriteBarrier)),
2721                        heap_number, BuildHeapNumberValueIndexConstant(), value,
2722                        heap_number, control);
2723   return graph()->NewNode(common->FinishRegion(), heap_number, store);
2724 }
2725 
BuildLoadHeapNumberValue(Node * value,Node * control)2726 Node* WasmGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) {
2727   return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()),
2728                           value, BuildHeapNumberValueIndexConstant(),
2729                           graph()->start(), control);
2730 }
2731 
BuildHeapNumberValueIndexConstant()2732 Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
2733   return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
2734 }
2735 
IsJSCompatible(wasm::ValueType type)2736 bool IsJSCompatible(wasm::ValueType type) {
2737   return (type != wasm::kWasmI64) && (type != wasm::kWasmS128);
2738 }
2739 
HasJSCompatibleSignature(wasm::FunctionSig * sig)2740 bool HasJSCompatibleSignature(wasm::FunctionSig* sig) {
2741   for (size_t i = 0; i < sig->parameter_count(); i++) {
2742     if (!IsJSCompatible(sig->GetParam(i))) {
2743       return false;
2744     }
2745   }
2746   for (size_t i = 0; i < sig->return_count(); i++) {
2747     if (!IsJSCompatible(sig->GetReturn(i))) {
2748       return false;
2749     }
2750   }
2751   return true;
2752 }
2753 
BuildJSToWasmWrapper(Handle<Code> wasm_code,wasm::FunctionSig * sig)2754 void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
2755                                             wasm::FunctionSig* sig) {
2756   int wasm_count = static_cast<int>(sig->parameter_count());
2757   int count = wasm_count + 3;
2758   Node** args = Buffer(count);
2759 
2760   // Build the start and the JS parameter nodes.
2761   Node* start = Start(wasm_count + 5);
2762   *control_ = start;
2763   *effect_ = start;
2764 
2765   // Create the context parameter
2766   Node* context = graph()->NewNode(
2767       jsgraph()->common()->Parameter(
2768           Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"),
2769       graph()->start());
2770 
2771   if (!HasJSCompatibleSignature(sig_)) {
2772     // Throw a TypeError. Use the context of the calling javascript function
2773     // (passed as a parameter), such that the generated code is context
2774     // independent.
2775     BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, jsgraph(),
2776                                   context, nullptr, 0, effect_, *control_);
2777 
2778     // Add a dummy call to the wasm function so that the generated wrapper
2779     // contains a reference to the wrapped wasm function. Without this reference
2780     // the wasm function could not be re-imported into another wasm module.
2781     int pos = 0;
2782     args[pos++] = HeapConstant(wasm_code);
2783     args[pos++] = *effect_;
2784     args[pos++] = *control_;
2785 
2786     // We only need a dummy call descriptor.
2787     wasm::FunctionSig::Builder dummy_sig_builder(jsgraph()->zone(), 0, 0);
2788     CallDescriptor* desc = wasm::ModuleEnv::GetWasmCallDescriptor(
2789         jsgraph()->zone(), dummy_sig_builder.Build());
2790     *effect_ = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2791     Return(jsgraph()->UndefinedConstant());
2792     return;
2793   }
2794 
2795   int pos = 0;
2796   args[pos++] = HeapConstant(wasm_code);
2797 
2798   // Convert JS parameters to WASM numbers.
2799   for (int i = 0; i < wasm_count; ++i) {
2800     Node* param = Param(i + 1);
2801     Node* wasm_param = FromJS(param, context, sig->GetParam(i));
2802     args[pos++] = wasm_param;
2803   }
2804 
2805   args[pos++] = *effect_;
2806   args[pos++] = *control_;
2807 
2808   // Call the WASM code.
2809   CallDescriptor* desc =
2810       wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
2811 
2812   Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args);
2813   *effect_ = call;
2814   Node* retval = call;
2815   Node* jsval = ToJS(
2816       retval, sig->return_count() == 0 ? wasm::kWasmStmt : sig->GetReturn());
2817   Return(jsval);
2818 }
2819 
AddParameterNodes(Node ** args,int pos,int param_count,wasm::FunctionSig * sig)2820 int WasmGraphBuilder::AddParameterNodes(Node** args, int pos, int param_count,
2821                                         wasm::FunctionSig* sig) {
2822   // Convert WASM numbers to JS values.
2823   int param_index = 0;
2824   for (int i = 0; i < param_count; ++i) {
2825     Node* param = Param(param_index++);
2826     args[pos++] = ToJS(param, sig->GetParam(i));
2827   }
2828   return pos;
2829 }
2830 
BuildWasmToJSWrapper(Handle<JSReceiver> target,wasm::FunctionSig * sig)2831 void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target,
2832                                             wasm::FunctionSig* sig) {
2833   DCHECK(target->IsCallable());
2834 
2835   int wasm_count = static_cast<int>(sig->parameter_count());
2836 
2837   // Build the start and the parameter nodes.
2838   Isolate* isolate = jsgraph()->isolate();
2839   CallDescriptor* desc;
2840   Node* start = Start(wasm_count + 3);
2841   *effect_ = start;
2842   *control_ = start;
2843 
2844   if (!HasJSCompatibleSignature(sig_)) {
2845     // Throw a TypeError. Embedding the context is ok here, since this code is
2846     // regenerated at instantiation time.
2847     Node* context =
2848         jsgraph()->HeapConstant(jsgraph()->isolate()->native_context());
2849     Return(BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError,
2850                                          jsgraph(), context, nullptr, 0,
2851                                          effect_, *control_));
2852     return;
2853   }
2854 
2855   Node** args = Buffer(wasm_count + 7);
2856 
2857   Node* call;
2858   bool direct_call = false;
2859 
2860   if (target->IsJSFunction()) {
2861     Handle<JSFunction> function = Handle<JSFunction>::cast(target);
2862     if (function->shared()->internal_formal_parameter_count() == wasm_count) {
2863       direct_call = true;
2864       int pos = 0;
2865       args[pos++] = jsgraph()->Constant(target);  // target callable.
2866       // Receiver.
2867       if (is_sloppy(function->shared()->language_mode()) &&
2868           !function->shared()->native()) {
2869         args[pos++] =
2870             HeapConstant(handle(function->context()->global_proxy(), isolate));
2871       } else {
2872         args[pos++] = jsgraph()->Constant(
2873             handle(isolate->heap()->undefined_value(), isolate));
2874       }
2875 
2876       desc = Linkage::GetJSCallDescriptor(
2877           graph()->zone(), false, wasm_count + 1, CallDescriptor::kNoFlags);
2878 
2879       // Convert WASM numbers to JS values.
2880       pos = AddParameterNodes(args, pos, wasm_count, sig);
2881 
2882       args[pos++] = jsgraph()->UndefinedConstant();        // new target
2883       args[pos++] = jsgraph()->Int32Constant(wasm_count);  // argument count
2884       args[pos++] = HeapConstant(handle(function->context()));
2885       args[pos++] = *effect_;
2886       args[pos++] = *control_;
2887 
2888       call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2889     }
2890   }
2891 
2892   // We cannot call the target directly, we have to use the Call builtin.
2893   if (!direct_call) {
2894     int pos = 0;
2895     Callable callable = CodeFactory::Call(isolate);
2896     args[pos++] = jsgraph()->HeapConstant(callable.code());
2897     args[pos++] = jsgraph()->Constant(target);           // target callable
2898     args[pos++] = jsgraph()->Int32Constant(wasm_count);  // argument count
2899     args[pos++] = jsgraph()->Constant(
2900         handle(isolate->heap()->undefined_value(), isolate));  // receiver
2901 
2902     desc = Linkage::GetStubCallDescriptor(isolate, graph()->zone(),
2903                                           callable.descriptor(), wasm_count + 1,
2904                                           CallDescriptor::kNoFlags);
2905 
2906     // Convert WASM numbers to JS values.
2907     pos = AddParameterNodes(args, pos, wasm_count, sig);
2908 
2909     // The native_context is sufficient here, because all kind of callables
2910     // which depend on the context provide their own context. The context here
2911     // is only needed if the target is a constructor to throw a TypeError, if
2912     // the target is a native function, or if the target is a callable JSObject,
2913     // which can only be constructed by the runtime.
2914     args[pos++] = HeapConstant(isolate->native_context());
2915     args[pos++] = *effect_;
2916     args[pos++] = *control_;
2917 
2918     call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2919   }
2920 
2921   *effect_ = call;
2922   SetSourcePosition(call, 0);
2923 
2924   // Convert the return value back.
2925   Node* i32_zero = jsgraph()->Int32Constant(0);
2926   Node* val = sig->return_count() == 0
2927                   ? i32_zero
2928                   : FromJS(call, HeapConstant(isolate->native_context()),
2929                            sig->GetReturn());
2930   Return(val);
2931 }
2932 
BuildWasmInterpreterEntry(uint32_t function_index,wasm::FunctionSig * sig,Handle<WasmInstanceObject> instance)2933 void WasmGraphBuilder::BuildWasmInterpreterEntry(
2934     uint32_t function_index, wasm::FunctionSig* sig,
2935     Handle<WasmInstanceObject> instance) {
2936   int wasm_count = static_cast<int>(sig->parameter_count());
2937   int param_count = jsgraph()->machine()->Is64()
2938                         ? wasm_count
2939                         : Int64Lowering::GetParameterCountAfterLowering(sig);
2940 
2941   // Build the start and the parameter nodes.
2942   Node* start = Start(param_count + 3);
2943   *effect_ = start;
2944   *control_ = start;
2945 
2946   // Compute size for the argument buffer.
2947   int args_size_bytes = 0;
2948   for (int i = 0; i < wasm_count; i++) {
2949     args_size_bytes +=
2950         RoundUpToMultipleOfPowOf2(1 << ElementSizeLog2Of(sig->GetParam(i)), 8);
2951   }
2952 
2953   // The return value is also passed via this buffer:
2954   DCHECK_GE(wasm::kV8MaxWasmFunctionReturns, sig->return_count());
2955   // TODO(wasm): Handle multi-value returns.
2956   DCHECK_EQ(1, wasm::kV8MaxWasmFunctionReturns);
2957   int return_size_bytes =
2958       sig->return_count() == 0 ? 0 : 1 << ElementSizeLog2Of(sig->GetReturn(0));
2959 
2960   // Get a stack slot for the arguments.
2961   Node* arg_buffer = args_size_bytes == 0 && return_size_bytes == 0
2962                          ? jsgraph()->IntPtrConstant(0)
2963                          : graph()->NewNode(jsgraph()->machine()->StackSlot(
2964                                std::max(args_size_bytes, return_size_bytes)));
2965 
2966   // Now store all our arguments to the buffer.
2967   int param_index = 0;
2968   int offset = 0;
2969   for (int i = 0; i < wasm_count; i++) {
2970     Node* param = Param(param_index++);
2971     bool is_i64_as_two_params =
2972         jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kWasmI64;
2973 
2974     if (is_i64_as_two_params) {
2975       StoreRepresentation store_rep(wasm::kWasmI32,
2976                                     WriteBarrierKind::kNoWriteBarrier);
2977       *effect_ =
2978           graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer,
2979                            Int32Constant(offset + kInt64LowerHalfMemoryOffset),
2980                            param, *effect_, *control_);
2981 
2982       param = Param(param_index++);
2983       *effect_ =
2984           graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer,
2985                            Int32Constant(offset + kInt64UpperHalfMemoryOffset),
2986                            param, *effect_, *control_);
2987       offset += 8;
2988 
2989     } else {
2990       MachineRepresentation param_rep = sig->GetParam(i);
2991       StoreRepresentation store_rep(param_rep,
2992                                     WriteBarrierKind::kNoWriteBarrier);
2993       *effect_ =
2994           graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer,
2995                            Int32Constant(offset), param, *effect_, *control_);
2996       offset += RoundUpToMultipleOfPowOf2(1 << ElementSizeLog2Of(param_rep), 8);
2997     }
2998 
2999     DCHECK(IsAligned(offset, 8));
3000   }
3001   DCHECK_EQ(param_count, param_index);
3002   DCHECK_EQ(args_size_bytes, offset);
3003 
3004   // We are passing the raw arg_buffer here. To the GC and other parts, it looks
3005   // like a Smi (lowest bit not set). In the runtime function however, don't
3006   // call Smi::value on it, but just cast it to a byte pointer.
3007   Node* parameters[] = {
3008       jsgraph()->HeapConstant(instance),       // wasm instance
3009       jsgraph()->SmiConstant(function_index),  // function index
3010       arg_buffer,                              // argument buffer
3011   };
3012   BuildCallToRuntime(Runtime::kWasmRunInterpreter, jsgraph(), parameters,
3013                      arraysize(parameters), effect_, *control_);
3014 
3015   // Read back the return value.
3016   if (jsgraph()->machine()->Is32() && sig->return_count() > 0 &&
3017       sig->GetReturn() == wasm::kWasmI64) {
3018     MachineType load_rep = wasm::WasmOpcodes::MachineTypeFor(wasm::kWasmI32);
3019     Node* lower =
3020         graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer,
3021                          Int32Constant(0), *effect_, *control_);
3022     Node* upper =
3023         graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer,
3024                          Int32Constant(sizeof(int32_t)), *effect_, *control_);
3025     Return(upper, lower);
3026   } else {
3027     Node* val;
3028     if (sig->return_count() == 0) {
3029       val = Int32Constant(0);
3030     } else {
3031       MachineType load_rep =
3032           wasm::WasmOpcodes::MachineTypeFor(sig->GetReturn());
3033       val = graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer,
3034                              Int32Constant(0), *effect_, *control_);
3035     }
3036     Return(val);
3037   }
3038 }
3039 
MemBuffer(uint32_t offset)3040 Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
3041   DCHECK(module_ && module_->instance);
3042   if (offset == 0) {
3043     if (!mem_buffer_) {
3044       mem_buffer_ = jsgraph()->RelocatableIntPtrConstant(
3045           reinterpret_cast<uintptr_t>(module_->instance->mem_start),
3046           RelocInfo::WASM_MEMORY_REFERENCE);
3047     }
3048     return mem_buffer_;
3049   } else {
3050     return jsgraph()->RelocatableIntPtrConstant(
3051         reinterpret_cast<uintptr_t>(module_->instance->mem_start + offset),
3052         RelocInfo::WASM_MEMORY_REFERENCE);
3053   }
3054 }
3055 
CurrentMemoryPages()3056 Node* WasmGraphBuilder::CurrentMemoryPages() {
3057   Runtime::FunctionId function_id = Runtime::kWasmMemorySize;
3058   const Runtime::Function* function = Runtime::FunctionForId(function_id);
3059   CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
3060       jsgraph()->zone(), function_id, function->nargs, Operator::kNoThrow,
3061       CallDescriptor::kNoFlags);
3062   wasm::ModuleEnv* module = module_;
3063   Node* inputs[] = {
3064       jsgraph()->CEntryStubConstant(function->result_size),  // C entry
3065       jsgraph()->ExternalConstant(
3066           ExternalReference(function_id, jsgraph()->isolate())),  // ref
3067       jsgraph()->Int32Constant(function->nargs),                  // arity
3068       jsgraph()->HeapConstant(module->instance->context),         // context
3069       *effect_,
3070       *control_};
3071   Node* call = graph()->NewNode(jsgraph()->common()->Call(desc),
3072                                 static_cast<int>(arraysize(inputs)), inputs);
3073 
3074   Node* result = BuildChangeSmiToInt32(call);
3075 
3076   *effect_ = call;
3077   return result;
3078 }
3079 
MemSize(uint32_t offset)3080 Node* WasmGraphBuilder::MemSize(uint32_t offset) {
3081   DCHECK(module_ && module_->instance);
3082   uint32_t size = static_cast<uint32_t>(module_->instance->mem_size);
3083   if (offset == 0) {
3084     if (!mem_size_)
3085       mem_size_ = jsgraph()->RelocatableInt32Constant(
3086           size, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
3087     return mem_size_;
3088   } else {
3089     return jsgraph()->RelocatableInt32Constant(
3090         size + offset, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
3091   }
3092 }
3093 
EnsureFunctionTableNodes()3094 void WasmGraphBuilder::EnsureFunctionTableNodes() {
3095   if (function_tables_.size() > 0) return;
3096   size_t tables_size = module_->instance->function_tables.size();
3097   DCHECK(tables_size == module_->instance->signature_tables.size());
3098   for (size_t i = 0; i < tables_size; ++i) {
3099     auto function_handle = module_->instance->function_tables[i];
3100     auto signature_handle = module_->instance->signature_tables[i];
3101     DCHECK(!function_handle.is_null() && !signature_handle.is_null());
3102     function_tables_.push_back(HeapConstant(function_handle));
3103     signature_tables_.push_back(HeapConstant(signature_handle));
3104     uint32_t table_size = module_->module->function_tables[i].min_size;
3105     function_table_sizes_.push_back(jsgraph()->RelocatableInt32Constant(
3106         static_cast<uint32_t>(table_size),
3107         RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE));
3108   }
3109 }
3110 
GetGlobal(uint32_t index)3111 Node* WasmGraphBuilder::GetGlobal(uint32_t index) {
3112   MachineType mem_type =
3113       wasm::WasmOpcodes::MachineTypeFor(module_->GetGlobalType(index));
3114   Node* addr = jsgraph()->RelocatableIntPtrConstant(
3115       reinterpret_cast<uintptr_t>(module_->instance->globals_start +
3116                                   module_->module->globals[index].offset),
3117       RelocInfo::WASM_GLOBAL_REFERENCE);
3118   const Operator* op = jsgraph()->machine()->Load(mem_type);
3119   Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), *effect_,
3120                                 *control_);
3121   *effect_ = node;
3122   return node;
3123 }
3124 
SetGlobal(uint32_t index,Node * val)3125 Node* WasmGraphBuilder::SetGlobal(uint32_t index, Node* val) {
3126   MachineType mem_type =
3127       wasm::WasmOpcodes::MachineTypeFor(module_->GetGlobalType(index));
3128   Node* addr = jsgraph()->RelocatableIntPtrConstant(
3129       reinterpret_cast<uintptr_t>(module_->instance->globals_start +
3130                                   module_->module->globals[index].offset),
3131       RelocInfo::WASM_GLOBAL_REFERENCE);
3132   const Operator* op = jsgraph()->machine()->Store(
3133       StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
3134   Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), val,
3135                                 *effect_, *control_);
3136   *effect_ = node;
3137   return node;
3138 }
3139 
BoundsCheckMem(MachineType memtype,Node * index,uint32_t offset,wasm::WasmCodePosition position)3140 void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
3141                                       uint32_t offset,
3142                                       wasm::WasmCodePosition position) {
3143   DCHECK(module_ && module_->instance);
3144   if (FLAG_wasm_no_bounds_checks) return;
3145   uint32_t size = module_->instance->mem_size;
3146   byte memsize = wasm::WasmOpcodes::MemSize(memtype);
3147 
3148   size_t effective_size;
3149   if (size <= offset || size < (static_cast<uint64_t>(offset) + memsize)) {
3150     // Two checks are needed in the case where the offset is statically
3151     // out of bounds; one check for the offset being in bounds, and the next for
3152     // the offset + index being out of bounds for code to be patched correctly
3153     // on relocation.
3154 
3155     // Check for overflows.
3156     if ((std::numeric_limits<uint32_t>::max() - memsize) + 1 < offset) {
3157       // Always trap. Do not use TrapAlways because it does not create a valid
3158       // graph here.
3159       trap_->TrapIfEq32(wasm::kTrapMemOutOfBounds, jsgraph()->Int32Constant(0),
3160                         0, position);
3161       return;
3162     }
3163     size_t effective_offset = (offset - 1) + memsize;
3164 
3165     Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(),
3166                                   jsgraph()->IntPtrConstant(effective_offset),
3167                                   jsgraph()->RelocatableInt32Constant(
3168                                       static_cast<uint32_t>(size),
3169                                       RelocInfo::WASM_MEMORY_SIZE_REFERENCE));
3170     trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
3171     // For offset > effective size, this relies on check above to fail and
3172     // effective size can be negative, relies on wrap around.
3173     effective_size = size - offset - memsize + 1;
3174   } else {
3175     effective_size = size - offset - memsize + 1;
3176     CHECK(effective_size <= kMaxUInt32);
3177 
3178     Uint32Matcher m(index);
3179     if (m.HasValue()) {
3180       uint32_t value = m.Value();
3181       if (value < effective_size) {
3182         // The bounds check will always succeed.
3183         return;
3184       }
3185     }
3186   }
3187 
3188   Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index,
3189                                 jsgraph()->RelocatableInt32Constant(
3190                                     static_cast<uint32_t>(effective_size),
3191                                     RelocInfo::WASM_MEMORY_SIZE_REFERENCE));
3192   trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
3193 }
3194 
LoadMem(wasm::ValueType type,MachineType memtype,Node * index,uint32_t offset,uint32_t alignment,wasm::WasmCodePosition position)3195 Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype,
3196                                 Node* index, uint32_t offset,
3197                                 uint32_t alignment,
3198                                 wasm::WasmCodePosition position) {
3199   Node* load;
3200 
3201   // WASM semantics throw on OOB. Introduce explicit bounds check.
3202   if (!FLAG_wasm_trap_handler || !kTrapHandlerSupported) {
3203     BoundsCheckMem(memtype, index, offset, position);
3204   }
3205   bool aligned = static_cast<int>(alignment) >=
3206                  ElementSizeLog2Of(memtype.representation());
3207 
3208   if (aligned ||
3209       jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) {
3210     if (FLAG_wasm_trap_handler && kTrapHandlerSupported) {
3211       DCHECK(FLAG_wasm_guard_pages);
3212       Node* position_node = jsgraph()->Int32Constant(position);
3213       load = graph()->NewNode(jsgraph()->machine()->ProtectedLoad(memtype),
3214                               MemBuffer(offset), index, position_node, *effect_,
3215                               *control_);
3216     } else {
3217       load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
3218                               MemBuffer(offset), index, *effect_, *control_);
3219     }
3220   } else {
3221     // TODO(eholk): Support unaligned loads with trap handlers.
3222     DCHECK(!FLAG_wasm_trap_handler || !kTrapHandlerSupported);
3223     load = graph()->NewNode(jsgraph()->machine()->UnalignedLoad(memtype),
3224                             MemBuffer(offset), index, *effect_, *control_);
3225   }
3226 
3227   *effect_ = load;
3228 
3229 #if defined(V8_TARGET_BIG_ENDIAN)
3230   load = BuildChangeEndianness(load, memtype, type);
3231 #endif
3232 
3233   if (type == wasm::kWasmI64 &&
3234       ElementSizeLog2Of(memtype.representation()) < 3) {
3235     // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes.
3236     if (memtype.IsSigned()) {
3237       // sign extend
3238       load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
3239     } else {
3240       // zero extend
3241       load =
3242           graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load);
3243     }
3244   }
3245 
3246   return load;
3247 }
3248 
3249 
StoreMem(MachineType memtype,Node * index,uint32_t offset,uint32_t alignment,Node * val,wasm::WasmCodePosition position)3250 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
3251                                  uint32_t offset, uint32_t alignment, Node* val,
3252                                  wasm::WasmCodePosition position) {
3253   Node* store;
3254 
3255   // WASM semantics throw on OOB. Introduce explicit bounds check.
3256   if (!FLAG_wasm_trap_handler || !kTrapHandlerSupported) {
3257     BoundsCheckMem(memtype, index, offset, position);
3258   }
3259   StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
3260 
3261   bool aligned = static_cast<int>(alignment) >=
3262                  ElementSizeLog2Of(memtype.representation());
3263 
3264 #if defined(V8_TARGET_BIG_ENDIAN)
3265   val = BuildChangeEndianness(val, memtype);
3266 #endif
3267 
3268   if (aligned ||
3269       jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) {
3270     if (FLAG_wasm_trap_handler && kTrapHandlerSupported) {
3271       Node* position_node = jsgraph()->Int32Constant(position);
3272       store = graph()->NewNode(
3273           jsgraph()->machine()->ProtectedStore(memtype.representation()),
3274           MemBuffer(offset), index, val, position_node, *effect_, *control_);
3275     } else {
3276       StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
3277       store =
3278           graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
3279                            index, val, *effect_, *control_);
3280     }
3281   } else {
3282     // TODO(eholk): Support unaligned stores with trap handlers.
3283     DCHECK(!FLAG_wasm_trap_handler || !kTrapHandlerSupported);
3284     UnalignedStoreRepresentation rep(memtype.representation());
3285     store =
3286         graph()->NewNode(jsgraph()->machine()->UnalignedStore(rep),
3287                          MemBuffer(offset), index, val, *effect_, *control_);
3288   }
3289 
3290   *effect_ = store;
3291 
3292   return store;
3293 }
3294 
BuildAsmjsLoadMem(MachineType type,Node * index)3295 Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) {
3296   // TODO(turbofan): fold bounds checks for constant asm.js loads.
3297   // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
3298   const Operator* op = jsgraph()->machine()->CheckedLoad(type);
3299   Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_,
3300                                 *control_);
3301   *effect_ = load;
3302   return load;
3303 }
3304 
BuildAsmjsStoreMem(MachineType type,Node * index,Node * val)3305 Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index,
3306                                            Node* val) {
3307   // TODO(turbofan): fold bounds checks for constant asm.js stores.
3308   // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
3309   const Operator* op =
3310       jsgraph()->machine()->CheckedStore(type.representation());
3311   Node* store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val,
3312                                  *effect_, *control_);
3313   *effect_ = store;
3314   return val;
3315 }
3316 
PrintDebugName(Node * node)3317 void WasmGraphBuilder::PrintDebugName(Node* node) {
3318   PrintF("#%d:%s", node->id(), node->op()->mnemonic());
3319 }
3320 
String(const char * string)3321 Node* WasmGraphBuilder::String(const char* string) {
3322   return jsgraph()->Constant(
3323       jsgraph()->isolate()->factory()->NewStringFromAsciiChecked(string));
3324 }
3325 
graph()3326 Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
3327 
Int64LoweringForTesting()3328 void WasmGraphBuilder::Int64LoweringForTesting() {
3329   if (jsgraph()->machine()->Is32()) {
3330     Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(),
3331                     jsgraph()->common(), jsgraph()->zone(), sig_);
3332     r.LowerGraph();
3333   }
3334 }
3335 
SimdScalarLoweringForTesting()3336 void WasmGraphBuilder::SimdScalarLoweringForTesting() {
3337   SimdScalarLowering(jsgraph()->graph(), jsgraph()->machine(),
3338                      jsgraph()->common(), jsgraph()->zone(), sig_)
3339       .LowerGraph();
3340 }
3341 
SetSourcePosition(Node * node,wasm::WasmCodePosition position)3342 void WasmGraphBuilder::SetSourcePosition(Node* node,
3343                                          wasm::WasmCodePosition position) {
3344   DCHECK_NE(position, wasm::kNoCodePosition);
3345   if (source_position_table_)
3346     source_position_table_->SetSourcePosition(node, SourcePosition(position));
3347 }
3348 
CreateS128Value(int32_t value)3349 Node* WasmGraphBuilder::CreateS128Value(int32_t value) {
3350   // TODO(gdeepti): Introduce Simd128Constant to common-operator.h and use
3351   // instead of creating a SIMD Value.
3352   has_simd_ = true;
3353   return graph()->NewNode(jsgraph()->machine()->CreateInt32x4(),
3354                           Int32Constant(value), Int32Constant(value),
3355                           Int32Constant(value), Int32Constant(value));
3356 }
3357 
SimdOp(wasm::WasmOpcode opcode,const NodeVector & inputs)3358 Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
3359                                const NodeVector& inputs) {
3360   has_simd_ = true;
3361   switch (opcode) {
3362     case wasm::kExprF32x4Splat:
3363       return graph()->NewNode(jsgraph()->machine()->CreateFloat32x4(),
3364                               inputs[0], inputs[0], inputs[0], inputs[0]);
3365     case wasm::kExprF32x4SConvertI32x4:
3366       return graph()->NewNode(jsgraph()->machine()->Float32x4FromInt32x4(),
3367                               inputs[0]);
3368     case wasm::kExprF32x4UConvertI32x4:
3369       return graph()->NewNode(jsgraph()->machine()->Float32x4FromUint32x4(),
3370                               inputs[0]);
3371     case wasm::kExprF32x4Abs:
3372       return graph()->NewNode(jsgraph()->machine()->Float32x4Abs(), inputs[0]);
3373     case wasm::kExprF32x4Neg:
3374       return graph()->NewNode(jsgraph()->machine()->Float32x4Neg(), inputs[0]);
3375     case wasm::kExprF32x4Add:
3376       return graph()->NewNode(jsgraph()->machine()->Float32x4Add(), inputs[0],
3377                               inputs[1]);
3378     case wasm::kExprF32x4Sub:
3379       return graph()->NewNode(jsgraph()->machine()->Float32x4Sub(), inputs[0],
3380                               inputs[1]);
3381     case wasm::kExprF32x4Eq:
3382       return graph()->NewNode(jsgraph()->machine()->Float32x4Equal(), inputs[0],
3383                               inputs[1]);
3384     case wasm::kExprF32x4Ne:
3385       return graph()->NewNode(jsgraph()->machine()->Float32x4NotEqual(),
3386                               inputs[0], inputs[1]);
3387     case wasm::kExprI32x4Splat:
3388       return graph()->NewNode(jsgraph()->machine()->CreateInt32x4(), inputs[0],
3389                               inputs[0], inputs[0], inputs[0]);
3390     case wasm::kExprI32x4SConvertF32x4:
3391       return graph()->NewNode(jsgraph()->machine()->Int32x4FromFloat32x4(),
3392                               inputs[0]);
3393     case wasm::kExprI32x4UConvertF32x4:
3394       return graph()->NewNode(jsgraph()->machine()->Uint32x4FromFloat32x4(),
3395                               inputs[0]);
3396     case wasm::kExprI32x4Neg:
3397       return graph()->NewNode(jsgraph()->machine()->Int32x4Neg(), inputs[0]);
3398     case wasm::kExprI32x4Add:
3399       return graph()->NewNode(jsgraph()->machine()->Int32x4Add(), inputs[0],
3400                               inputs[1]);
3401     case wasm::kExprI32x4Sub:
3402       return graph()->NewNode(jsgraph()->machine()->Int32x4Sub(), inputs[0],
3403                               inputs[1]);
3404     case wasm::kExprI32x4Mul:
3405       return graph()->NewNode(jsgraph()->machine()->Int32x4Mul(), inputs[0],
3406                               inputs[1]);
3407     case wasm::kExprI32x4MinS:
3408       return graph()->NewNode(jsgraph()->machine()->Int32x4Min(), inputs[0],
3409                               inputs[1]);
3410     case wasm::kExprI32x4MaxS:
3411       return graph()->NewNode(jsgraph()->machine()->Int32x4Max(), inputs[0],
3412                               inputs[1]);
3413     case wasm::kExprI32x4Eq:
3414       return graph()->NewNode(jsgraph()->machine()->Int32x4Equal(), inputs[0],
3415                               inputs[1]);
3416     case wasm::kExprI32x4Ne:
3417       return graph()->NewNode(jsgraph()->machine()->Int32x4NotEqual(),
3418                               inputs[0], inputs[1]);
3419     case wasm::kExprI32x4LtS:
3420       return graph()->NewNode(jsgraph()->machine()->Int32x4GreaterThan(),
3421                               inputs[1], inputs[0]);
3422     case wasm::kExprI32x4LeS:
3423       return graph()->NewNode(jsgraph()->machine()->Int32x4GreaterThanOrEqual(),
3424                               inputs[1], inputs[0]);
3425     case wasm::kExprI32x4GtS:
3426       return graph()->NewNode(jsgraph()->machine()->Int32x4GreaterThan(),
3427                               inputs[0], inputs[1]);
3428     case wasm::kExprI32x4GeS:
3429       return graph()->NewNode(jsgraph()->machine()->Int32x4GreaterThanOrEqual(),
3430                               inputs[0], inputs[1]);
3431     case wasm::kExprI32x4MinU:
3432       return graph()->NewNode(jsgraph()->machine()->Uint32x4Min(), inputs[0],
3433                               inputs[1]);
3434     case wasm::kExprI32x4MaxU:
3435       return graph()->NewNode(jsgraph()->machine()->Uint32x4Max(), inputs[0],
3436                               inputs[1]);
3437     case wasm::kExprI32x4LtU:
3438       return graph()->NewNode(jsgraph()->machine()->Uint32x4GreaterThan(),
3439                               inputs[1], inputs[0]);
3440     case wasm::kExprI32x4LeU:
3441       return graph()->NewNode(
3442           jsgraph()->machine()->Uint32x4GreaterThanOrEqual(), inputs[1],
3443           inputs[0]);
3444     case wasm::kExprI32x4GtU:
3445       return graph()->NewNode(jsgraph()->machine()->Uint32x4GreaterThan(),
3446                               inputs[0], inputs[1]);
3447     case wasm::kExprI32x4GeU:
3448       return graph()->NewNode(
3449           jsgraph()->machine()->Uint32x4GreaterThanOrEqual(), inputs[0],
3450           inputs[1]);
3451     case wasm::kExprI16x8Splat:
3452       return graph()->NewNode(jsgraph()->machine()->CreateInt16x8(), inputs[0],
3453                               inputs[0], inputs[0], inputs[0], inputs[0],
3454                               inputs[0], inputs[0], inputs[0]);
3455     case wasm::kExprI16x8Neg:
3456       return graph()->NewNode(jsgraph()->machine()->Int16x8Neg(), inputs[0]);
3457     case wasm::kExprI16x8Add:
3458       return graph()->NewNode(jsgraph()->machine()->Int16x8Add(), inputs[0],
3459                               inputs[1]);
3460     case wasm::kExprI16x8AddSaturateS:
3461       return graph()->NewNode(jsgraph()->machine()->Int16x8AddSaturate(),
3462                               inputs[0], inputs[1]);
3463     case wasm::kExprI16x8Sub:
3464       return graph()->NewNode(jsgraph()->machine()->Int16x8Sub(), inputs[0],
3465                               inputs[1]);
3466     case wasm::kExprI16x8SubSaturateS:
3467       return graph()->NewNode(jsgraph()->machine()->Int16x8SubSaturate(),
3468                               inputs[0], inputs[1]);
3469     case wasm::kExprI16x8Mul:
3470       return graph()->NewNode(jsgraph()->machine()->Int16x8Mul(), inputs[0],
3471                               inputs[1]);
3472     case wasm::kExprI16x8MinS:
3473       return graph()->NewNode(jsgraph()->machine()->Int16x8Min(), inputs[0],
3474                               inputs[1]);
3475     case wasm::kExprI16x8MaxS:
3476       return graph()->NewNode(jsgraph()->machine()->Int16x8Max(), inputs[0],
3477                               inputs[1]);
3478     case wasm::kExprI16x8Eq:
3479       return graph()->NewNode(jsgraph()->machine()->Int16x8Equal(), inputs[0],
3480                               inputs[1]);
3481     case wasm::kExprI16x8Ne:
3482       return graph()->NewNode(jsgraph()->machine()->Int16x8NotEqual(),
3483                               inputs[0], inputs[1]);
3484     case wasm::kExprI16x8LtS:
3485       return graph()->NewNode(jsgraph()->machine()->Int16x8GreaterThan(),
3486                               inputs[1], inputs[0]);
3487     case wasm::kExprI16x8LeS:
3488       return graph()->NewNode(jsgraph()->machine()->Int16x8GreaterThanOrEqual(),
3489                               inputs[1], inputs[0]);
3490     case wasm::kExprI16x8GtS:
3491       return graph()->NewNode(jsgraph()->machine()->Int16x8GreaterThan(),
3492                               inputs[0], inputs[1]);
3493     case wasm::kExprI16x8GeS:
3494       return graph()->NewNode(jsgraph()->machine()->Int16x8GreaterThanOrEqual(),
3495                               inputs[0], inputs[1]);
3496     case wasm::kExprI16x8AddSaturateU:
3497       return graph()->NewNode(jsgraph()->machine()->Uint16x8AddSaturate(),
3498                               inputs[0], inputs[1]);
3499     case wasm::kExprI16x8SubSaturateU:
3500       return graph()->NewNode(jsgraph()->machine()->Uint16x8SubSaturate(),
3501                               inputs[0], inputs[1]);
3502     case wasm::kExprI16x8MinU:
3503       return graph()->NewNode(jsgraph()->machine()->Uint16x8Min(), inputs[0],
3504                               inputs[1]);
3505     case wasm::kExprI16x8MaxU:
3506       return graph()->NewNode(jsgraph()->machine()->Uint16x8Max(), inputs[0],
3507                               inputs[1]);
3508     case wasm::kExprI16x8LtU:
3509       return graph()->NewNode(jsgraph()->machine()->Uint16x8GreaterThan(),
3510                               inputs[1], inputs[0]);
3511     case wasm::kExprI16x8LeU:
3512       return graph()->NewNode(
3513           jsgraph()->machine()->Uint16x8GreaterThanOrEqual(), inputs[1],
3514           inputs[0]);
3515     case wasm::kExprI16x8GtU:
3516       return graph()->NewNode(jsgraph()->machine()->Uint16x8GreaterThan(),
3517                               inputs[0], inputs[1]);
3518     case wasm::kExprI16x8GeU:
3519       return graph()->NewNode(
3520           jsgraph()->machine()->Uint16x8GreaterThanOrEqual(), inputs[0],
3521           inputs[1]);
3522     case wasm::kExprI8x16Splat:
3523       return graph()->NewNode(jsgraph()->machine()->CreateInt8x16(), inputs[0],
3524                               inputs[0], inputs[0], inputs[0], inputs[0],
3525                               inputs[0], inputs[0], inputs[0], inputs[0],
3526                               inputs[0], inputs[0], inputs[0], inputs[0],
3527                               inputs[0], inputs[0], inputs[0]);
3528     case wasm::kExprI8x16Neg:
3529       return graph()->NewNode(jsgraph()->machine()->Int8x16Neg(), inputs[0]);
3530     case wasm::kExprI8x16Add:
3531       return graph()->NewNode(jsgraph()->machine()->Int8x16Add(), inputs[0],
3532                               inputs[1]);
3533     case wasm::kExprI8x16AddSaturateS:
3534       return graph()->NewNode(jsgraph()->machine()->Int8x16AddSaturate(),
3535                               inputs[0], inputs[1]);
3536     case wasm::kExprI8x16Sub:
3537       return graph()->NewNode(jsgraph()->machine()->Int8x16Sub(), inputs[0],
3538                               inputs[1]);
3539     case wasm::kExprI8x16SubSaturateS:
3540       return graph()->NewNode(jsgraph()->machine()->Int8x16SubSaturate(),
3541                               inputs[0], inputs[1]);
3542     case wasm::kExprI8x16Mul:
3543       return graph()->NewNode(jsgraph()->machine()->Int8x16Mul(), inputs[0],
3544                               inputs[1]);
3545     case wasm::kExprI8x16MinS:
3546       return graph()->NewNode(jsgraph()->machine()->Int8x16Min(), inputs[0],
3547                               inputs[1]);
3548     case wasm::kExprI8x16MaxS:
3549       return graph()->NewNode(jsgraph()->machine()->Int8x16Max(), inputs[0],
3550                               inputs[1]);
3551     case wasm::kExprI8x16Eq:
3552       return graph()->NewNode(jsgraph()->machine()->Int8x16Equal(), inputs[0],
3553                               inputs[1]);
3554     case wasm::kExprI8x16Ne:
3555       return graph()->NewNode(jsgraph()->machine()->Int8x16NotEqual(),
3556                               inputs[0], inputs[1]);
3557     case wasm::kExprI8x16LtS:
3558       return graph()->NewNode(jsgraph()->machine()->Int8x16GreaterThan(),
3559                               inputs[1], inputs[0]);
3560     case wasm::kExprI8x16LeS:
3561       return graph()->NewNode(jsgraph()->machine()->Int8x16GreaterThanOrEqual(),
3562                               inputs[1], inputs[0]);
3563     case wasm::kExprI8x16GtS:
3564       return graph()->NewNode(jsgraph()->machine()->Int8x16GreaterThan(),
3565                               inputs[0], inputs[1]);
3566     case wasm::kExprI8x16GeS:
3567       return graph()->NewNode(jsgraph()->machine()->Int8x16GreaterThanOrEqual(),
3568                               inputs[0], inputs[1]);
3569     case wasm::kExprI8x16AddSaturateU:
3570       return graph()->NewNode(jsgraph()->machine()->Uint8x16AddSaturate(),
3571                               inputs[0], inputs[1]);
3572     case wasm::kExprI8x16SubSaturateU:
3573       return graph()->NewNode(jsgraph()->machine()->Uint8x16SubSaturate(),
3574                               inputs[0], inputs[1]);
3575     case wasm::kExprI8x16MinU:
3576       return graph()->NewNode(jsgraph()->machine()->Uint8x16Min(), inputs[0],
3577                               inputs[1]);
3578     case wasm::kExprI8x16MaxU:
3579       return graph()->NewNode(jsgraph()->machine()->Uint8x16Max(), inputs[0],
3580                               inputs[1]);
3581     case wasm::kExprI8x16LtU:
3582       return graph()->NewNode(jsgraph()->machine()->Uint8x16GreaterThan(),
3583                               inputs[1], inputs[0]);
3584     case wasm::kExprI8x16LeU:
3585       return graph()->NewNode(
3586           jsgraph()->machine()->Uint8x16GreaterThanOrEqual(), inputs[1],
3587           inputs[0]);
3588     case wasm::kExprI8x16GtU:
3589       return graph()->NewNode(jsgraph()->machine()->Uint8x16GreaterThan(),
3590                               inputs[0], inputs[1]);
3591     case wasm::kExprI8x16GeU:
3592       return graph()->NewNode(
3593           jsgraph()->machine()->Uint8x16GreaterThanOrEqual(), inputs[0],
3594           inputs[1]);
3595     case wasm::kExprS32x4Select:
3596       return graph()->NewNode(jsgraph()->machine()->Simd32x4Select(), inputs[0],
3597                               inputs[1], inputs[2]);
3598     case wasm::kExprS16x8Select:
3599       return graph()->NewNode(jsgraph()->machine()->Simd16x8Select(), inputs[0],
3600                               inputs[1], inputs[2]);
3601     case wasm::kExprS8x16Select:
3602       return graph()->NewNode(jsgraph()->machine()->Simd8x16Select(), inputs[0],
3603                               inputs[1], inputs[2]);
3604     case wasm::kExprS128And:
3605       return graph()->NewNode(jsgraph()->machine()->Simd128And(), inputs[0],
3606                               inputs[1]);
3607     case wasm::kExprS128Or:
3608       return graph()->NewNode(jsgraph()->machine()->Simd128Or(), inputs[0],
3609                               inputs[1]);
3610     case wasm::kExprS128Xor:
3611       return graph()->NewNode(jsgraph()->machine()->Simd128Xor(), inputs[0],
3612                               inputs[1]);
3613     case wasm::kExprS128Not:
3614       return graph()->NewNode(jsgraph()->machine()->Simd128Not(), inputs[0]);
3615     default:
3616       return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
3617   }
3618 }
3619 
SimdLaneOp(wasm::WasmOpcode opcode,uint8_t lane,const NodeVector & inputs)3620 Node* WasmGraphBuilder::SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane,
3621                                    const NodeVector& inputs) {
3622   has_simd_ = true;
3623   switch (opcode) {
3624     case wasm::kExprF32x4ExtractLane:
3625       return graph()->NewNode(jsgraph()->machine()->Float32x4ExtractLane(lane),
3626                               inputs[0]);
3627     case wasm::kExprF32x4ReplaceLane:
3628       return graph()->NewNode(jsgraph()->machine()->Float32x4ReplaceLane(lane),
3629                               inputs[0], inputs[1]);
3630     case wasm::kExprI32x4ExtractLane:
3631       return graph()->NewNode(jsgraph()->machine()->Int32x4ExtractLane(lane),
3632                               inputs[0]);
3633     case wasm::kExprI32x4ReplaceLane:
3634       return graph()->NewNode(jsgraph()->machine()->Int32x4ReplaceLane(lane),
3635                               inputs[0], inputs[1]);
3636     case wasm::kExprI16x8ExtractLane:
3637       return graph()->NewNode(jsgraph()->machine()->Int16x8ExtractLane(lane),
3638                               inputs[0]);
3639     case wasm::kExprI16x8ReplaceLane:
3640       return graph()->NewNode(jsgraph()->machine()->Int16x8ReplaceLane(lane),
3641                               inputs[0], inputs[1]);
3642     case wasm::kExprI8x16ExtractLane:
3643       return graph()->NewNode(jsgraph()->machine()->Int8x16ExtractLane(lane),
3644                               inputs[0]);
3645     case wasm::kExprI8x16ReplaceLane:
3646       return graph()->NewNode(jsgraph()->machine()->Int8x16ReplaceLane(lane),
3647                               inputs[0], inputs[1]);
3648     default:
3649       return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
3650   }
3651 }
3652 
SimdShiftOp(wasm::WasmOpcode opcode,uint8_t shift,const NodeVector & inputs)3653 Node* WasmGraphBuilder::SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
3654                                     const NodeVector& inputs) {
3655   has_simd_ = true;
3656   switch (opcode) {
3657     case wasm::kExprI32x4Shl:
3658       return graph()->NewNode(
3659           jsgraph()->machine()->Int32x4ShiftLeftByScalar(shift), inputs[0]);
3660     case wasm::kExprI32x4ShrS:
3661       return graph()->NewNode(
3662           jsgraph()->machine()->Int32x4ShiftRightByScalar(shift), inputs[0]);
3663     case wasm::kExprI32x4ShrU:
3664       return graph()->NewNode(
3665           jsgraph()->machine()->Uint32x4ShiftRightByScalar(shift), inputs[0]);
3666     case wasm::kExprI16x8Shl:
3667       return graph()->NewNode(
3668           jsgraph()->machine()->Int16x8ShiftLeftByScalar(shift), inputs[0]);
3669     case wasm::kExprI16x8ShrS:
3670       return graph()->NewNode(
3671           jsgraph()->machine()->Int16x8ShiftRightByScalar(shift), inputs[0]);
3672     case wasm::kExprI16x8ShrU:
3673       return graph()->NewNode(
3674           jsgraph()->machine()->Uint16x8ShiftRightByScalar(shift), inputs[0]);
3675     case wasm::kExprI8x16Shl:
3676       return graph()->NewNode(
3677           jsgraph()->machine()->Int8x16ShiftLeftByScalar(shift), inputs[0]);
3678     case wasm::kExprI8x16ShrS:
3679       return graph()->NewNode(
3680           jsgraph()->machine()->Int8x16ShiftRightByScalar(shift), inputs[0]);
3681     case wasm::kExprI8x16ShrU:
3682       return graph()->NewNode(
3683           jsgraph()->machine()->Uint8x16ShiftRightByScalar(shift), inputs[0]);
3684     default:
3685       return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
3686   }
3687 }
3688 
SimdSwizzleOp(wasm::WasmOpcode opcode,uint32_t swizzle,const NodeVector & inputs)3689 Node* WasmGraphBuilder::SimdSwizzleOp(wasm::WasmOpcode opcode, uint32_t swizzle,
3690                                       const NodeVector& inputs) {
3691   has_simd_ = true;
3692   switch (opcode) {
3693     case wasm::kExprS32x4Swizzle:
3694       return graph()->NewNode(jsgraph()->machine()->Simd32x4Swizzle(swizzle),
3695                               inputs[0]);
3696     case wasm::kExprS16x8Swizzle:
3697       return graph()->NewNode(jsgraph()->machine()->Simd16x8Swizzle(swizzle),
3698                               inputs[0]);
3699     case wasm::kExprS8x16Swizzle:
3700       return graph()->NewNode(jsgraph()->machine()->Simd8x16Swizzle(swizzle),
3701                               inputs[0]);
3702     default:
3703       return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
3704   }
3705 }
3706 
RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,Isolate * isolate,Handle<Code> code,const char * message,uint32_t index,const wasm::WasmName & module_name,const wasm::WasmName & func_name)3707 static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
3708                                       Isolate* isolate, Handle<Code> code,
3709                                       const char* message, uint32_t index,
3710                                       const wasm::WasmName& module_name,
3711                                       const wasm::WasmName& func_name) {
3712   DCHECK(isolate->logger()->is_logging_code_events() ||
3713          isolate->is_profiling());
3714 
3715   ScopedVector<char> buffer(128);
3716   SNPrintF(buffer, "%s#%d:%.*s:%.*s", message, index, module_name.length(),
3717            module_name.start(), func_name.length(), func_name.start());
3718   Handle<String> name_str =
3719       isolate->factory()->NewStringFromAsciiChecked(buffer.start());
3720   Handle<String> script_str =
3721       isolate->factory()->NewStringFromAsciiChecked("(WASM)");
3722   Handle<SharedFunctionInfo> shared =
3723       isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
3724   PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
3725                                    *script_str, 0, 0));
3726 }
3727 
CompileJSToWasmWrapper(Isolate * isolate,const wasm::WasmModule * module,Handle<Code> wasm_code,uint32_t index)3728 Handle<Code> CompileJSToWasmWrapper(Isolate* isolate,
3729                                     const wasm::WasmModule* module,
3730                                     Handle<Code> wasm_code, uint32_t index) {
3731   const wasm::WasmFunction* func = &module->functions[index];
3732 
3733   //----------------------------------------------------------------------------
3734   // Create the Graph
3735   //----------------------------------------------------------------------------
3736   Zone zone(isolate->allocator(), ZONE_NAME);
3737   Graph graph(&zone);
3738   CommonOperatorBuilder common(&zone);
3739   MachineOperatorBuilder machine(&zone);
3740   JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
3741 
3742   Node* control = nullptr;
3743   Node* effect = nullptr;
3744 
3745   wasm::ModuleEnv module_env(module, nullptr);
3746   WasmGraphBuilder builder(&module_env, &zone, &jsgraph, func->sig);
3747   builder.set_control_ptr(&control);
3748   builder.set_effect_ptr(&effect);
3749   builder.BuildJSToWasmWrapper(wasm_code, func->sig);
3750 
3751   //----------------------------------------------------------------------------
3752   // Run the compilation pipeline.
3753   //----------------------------------------------------------------------------
3754   if (FLAG_trace_turbo_graph) {  // Simple textual RPO.
3755     OFStream os(stdout);
3756     os << "-- Graph after change lowering -- " << std::endl;
3757     os << AsRPO(graph);
3758   }
3759 
3760   // Schedule and compile to machine code.
3761   int params = static_cast<int>(
3762       module_env.GetFunctionSignature(index)->parameter_count());
3763   CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
3764       &zone, false, params + 1, CallDescriptor::kNoFlags);
3765   Code::Flags flags = Code::ComputeFlags(Code::JS_TO_WASM_FUNCTION);
3766   bool debugging =
3767 #if DEBUG
3768       true;
3769 #else
3770       FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
3771 #endif
3772   Vector<const char> func_name = ArrayVector("js-to-wasm");
3773 
3774   static unsigned id = 0;
3775   Vector<char> buffer;
3776   if (debugging) {
3777     buffer = Vector<char>::New(128);
3778     int chars = SNPrintF(buffer, "js-to-wasm#%d", id);
3779     func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
3780   }
3781 
3782   CompilationInfo info(func_name, isolate, &zone, flags);
3783   Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
3784 #ifdef ENABLE_DISASSEMBLER
3785   if (FLAG_print_opt_code && !code.is_null()) {
3786     OFStream os(stdout);
3787     code->Disassemble(buffer.start(), os);
3788   }
3789 #endif
3790   if (debugging) {
3791     buffer.Dispose();
3792   }
3793 
3794   if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
3795     char func_name[32];
3796     SNPrintF(ArrayVector(func_name), "js-to-wasm#%d", func->func_index);
3797     RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code,
3798                               "js-to-wasm", index, wasm::WasmName("export"),
3799                               CStrVector(func_name));
3800   }
3801   return code;
3802 }
3803 
CompileWasmToJSWrapper(Isolate * isolate,Handle<JSReceiver> target,wasm::FunctionSig * sig,uint32_t index,Handle<String> module_name,MaybeHandle<String> import_name,wasm::ModuleOrigin origin)3804 Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
3805                                     wasm::FunctionSig* sig, uint32_t index,
3806                                     Handle<String> module_name,
3807                                     MaybeHandle<String> import_name,
3808                                     wasm::ModuleOrigin origin) {
3809   //----------------------------------------------------------------------------
3810   // Create the Graph
3811   //----------------------------------------------------------------------------
3812   Zone zone(isolate->allocator(), ZONE_NAME);
3813   Graph graph(&zone);
3814   CommonOperatorBuilder common(&zone);
3815   MachineOperatorBuilder machine(&zone);
3816   JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
3817 
3818   Node* control = nullptr;
3819   Node* effect = nullptr;
3820 
3821   SourcePositionTable* source_position_table =
3822       origin == wasm::kAsmJsOrigin ? new (&zone) SourcePositionTable(&graph)
3823                                    : nullptr;
3824 
3825   WasmGraphBuilder builder(nullptr, &zone, &jsgraph, sig,
3826                            source_position_table);
3827   builder.set_control_ptr(&control);
3828   builder.set_effect_ptr(&effect);
3829   builder.BuildWasmToJSWrapper(target, sig);
3830 
3831   Handle<Code> code = Handle<Code>::null();
3832   {
3833     if (FLAG_trace_turbo_graph) {  // Simple textual RPO.
3834       OFStream os(stdout);
3835       os << "-- Graph after change lowering -- " << std::endl;
3836       os << AsRPO(graph);
3837     }
3838 
3839     // Schedule and compile to machine code.
3840     CallDescriptor* incoming =
3841         wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig);
3842     if (machine.Is32()) {
3843       incoming = wasm::ModuleEnv::GetI32WasmCallDescriptor(&zone, incoming);
3844     }
3845     Code::Flags flags = Code::ComputeFlags(Code::WASM_TO_JS_FUNCTION);
3846     bool debugging =
3847 #if DEBUG
3848         true;
3849 #else
3850         FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
3851 #endif
3852     Vector<const char> func_name = ArrayVector("wasm-to-js");
3853     static unsigned id = 0;
3854     Vector<char> buffer;
3855     if (debugging) {
3856       buffer = Vector<char>::New(128);
3857       int chars = SNPrintF(buffer, "wasm-to-js#%d", id);
3858       func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
3859     }
3860 
3861     CompilationInfo info(func_name, isolate, &zone, flags);
3862     code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr,
3863                                             source_position_table);
3864 #ifdef ENABLE_DISASSEMBLER
3865     if (FLAG_print_opt_code && !code.is_null()) {
3866       OFStream os(stdout);
3867       code->Disassemble(buffer.start(), os);
3868     }
3869 #endif
3870     if (debugging) {
3871       buffer.Dispose();
3872     }
3873   }
3874   if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
3875     const char* function_name = nullptr;
3876     int function_name_size = 0;
3877     if (!import_name.is_null()) {
3878       Handle<String> handle = import_name.ToHandleChecked();
3879       function_name = handle->ToCString().get();
3880       function_name_size = handle->length();
3881     }
3882     RecordFunctionCompilation(
3883         CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index,
3884         {module_name->ToCString().get(), module_name->length()},
3885         {function_name, function_name_size});
3886   }
3887 
3888   return code;
3889 }
3890 
CompileWasmInterpreterEntry(Isolate * isolate,uint32_t func_index,wasm::FunctionSig * sig,Handle<WasmInstanceObject> instance)3891 Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index,
3892                                          wasm::FunctionSig* sig,
3893                                          Handle<WasmInstanceObject> instance) {
3894   //----------------------------------------------------------------------------
3895   // Create the Graph
3896   //----------------------------------------------------------------------------
3897   Zone zone(isolate->allocator(), ZONE_NAME);
3898   Graph graph(&zone);
3899   CommonOperatorBuilder common(&zone);
3900   MachineOperatorBuilder machine(
3901       &zone, MachineType::PointerRepresentation(),
3902       InstructionSelector::SupportedMachineOperatorFlags(),
3903       InstructionSelector::AlignmentRequirements());
3904   JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
3905 
3906   Node* control = nullptr;
3907   Node* effect = nullptr;
3908 
3909   WasmGraphBuilder builder(nullptr, &zone, &jsgraph, sig);
3910   builder.set_control_ptr(&control);
3911   builder.set_effect_ptr(&effect);
3912   builder.BuildWasmInterpreterEntry(func_index, sig, instance);
3913 
3914   Handle<Code> code = Handle<Code>::null();
3915   {
3916     if (FLAG_trace_turbo_graph) {  // Simple textual RPO.
3917       OFStream os(stdout);
3918       os << "-- Wasm to interpreter graph -- " << std::endl;
3919       os << AsRPO(graph);
3920     }
3921 
3922     // Schedule and compile to machine code.
3923     CallDescriptor* incoming =
3924         wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig);
3925     if (machine.Is32()) {
3926       incoming = wasm::ModuleEnv::GetI32WasmCallDescriptor(&zone, incoming);
3927     }
3928     Code::Flags flags = Code::ComputeFlags(Code::WASM_INTERPRETER_ENTRY);
3929     EmbeddedVector<char, 32> debug_name;
3930     int name_len = SNPrintF(debug_name, "wasm-to-interpreter#%d", func_index);
3931     DCHECK(name_len > 0 && name_len < debug_name.length());
3932     debug_name.Truncate(name_len);
3933     DCHECK_EQ('\0', debug_name.start()[debug_name.length()]);
3934 
3935     CompilationInfo info(debug_name, isolate, &zone, flags);
3936     code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
3937 #ifdef ENABLE_DISASSEMBLER
3938     if (FLAG_print_opt_code && !code.is_null()) {
3939       OFStream os(stdout);
3940       code->Disassemble(debug_name.start(), os);
3941     }
3942 #endif
3943 
3944     if (isolate->logger()->is_logging_code_events() ||
3945         isolate->is_profiling()) {
3946       RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code,
3947                                 "wasm-to-interpreter", func_index,
3948                                 wasm::WasmName("module"), debug_name);
3949     }
3950   }
3951 
3952   Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(1, TENURED);
3953   Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance);
3954   deopt_data->set(0, *weak_instance);
3955   code->set_deoptimization_data(*deopt_data);
3956 
3957   return code;
3958 }
3959 
BuildGraphForWasmFunction(double * decode_ms)3960 SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
3961     double* decode_ms) {
3962   base::ElapsedTimer decode_timer;
3963   if (FLAG_trace_wasm_decode_time) {
3964     decode_timer.Start();
3965   }
3966   // Create a TF graph during decoding.
3967 
3968   Graph* graph = jsgraph_->graph();
3969   CommonOperatorBuilder* common = jsgraph_->common();
3970   MachineOperatorBuilder* machine = jsgraph_->machine();
3971   SourcePositionTable* source_position_table =
3972       new (jsgraph_->zone()) SourcePositionTable(graph);
3973   WasmGraphBuilder builder(&module_env_->module_env, jsgraph_->zone(), jsgraph_,
3974                            function_->sig, source_position_table);
3975   const byte* module_start = module_env_->wire_bytes.start();
3976   wasm::FunctionBody body = {function_->sig, module_start,
3977                              module_start + function_->code_start_offset,
3978                              module_start + function_->code_end_offset};
3979   graph_construction_result_ =
3980       wasm::BuildTFGraph(isolate_->allocator(), &builder, body);
3981 
3982   if (graph_construction_result_.failed()) {
3983     if (FLAG_trace_wasm_compiler) {
3984       OFStream os(stdout);
3985       os << "Compilation failed: " << graph_construction_result_ << std::endl;
3986     }
3987     return nullptr;
3988   }
3989 
3990   if (machine->Is32()) {
3991     Int64Lowering(graph, machine, common, jsgraph_->zone(), function_->sig)
3992         .LowerGraph();
3993   }
3994 
3995   if (builder.has_simd() && !CpuFeatures::SupportsSimd128()) {
3996     SimdScalarLowering(graph, machine, common, jsgraph_->zone(), function_->sig)
3997         .LowerGraph();
3998   }
3999 
4000   int index = static_cast<int>(function_->func_index);
4001 
4002   if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
4003     OFStream os(stdout);
4004     PrintRawWasmCode(isolate_->allocator(), body,
4005                      module_env_->module_env.module);
4006   }
4007   if (index >= FLAG_trace_wasm_text_start && index < FLAG_trace_wasm_text_end) {
4008     OFStream os(stdout);
4009     PrintWasmText(module_env_->module_env.module, module_env_->wire_bytes,
4010                   function_->func_index, os, nullptr);
4011   }
4012   if (FLAG_trace_wasm_decode_time) {
4013     *decode_ms = decode_timer.Elapsed().InMillisecondsF();
4014   }
4015   return source_position_table;
4016 }
4017 
GetTaggedFunctionName(const wasm::WasmFunction * function)4018 char* WasmCompilationUnit::GetTaggedFunctionName(
4019     const wasm::WasmFunction* function) {
4020   snprintf(function_name_, sizeof(function_name_), "wasm#%d",
4021            function->func_index);
4022   return function_name_;
4023 }
4024 
WasmCompilationUnit(wasm::ErrorThrower * thrower,Isolate * isolate,wasm::ModuleBytesEnv * module_env,const wasm::WasmFunction * function,uint32_t index)4025 WasmCompilationUnit::WasmCompilationUnit(wasm::ErrorThrower* thrower,
4026                                          Isolate* isolate,
4027                                          wasm::ModuleBytesEnv* module_env,
4028                                          const wasm::WasmFunction* function,
4029                                          uint32_t index)
4030     : thrower_(thrower),
4031       isolate_(isolate),
4032       module_env_(module_env),
4033       function_(&module_env->module_env.module->functions[index]),
4034       graph_zone_(new Zone(isolate->allocator(), ZONE_NAME)),
4035       jsgraph_(new (graph_zone()) JSGraph(
4036           isolate, new (graph_zone()) Graph(graph_zone()),
4037           new (graph_zone()) CommonOperatorBuilder(graph_zone()), nullptr,
4038           nullptr, new (graph_zone()) MachineOperatorBuilder(
4039                        graph_zone(), MachineType::PointerRepresentation(),
4040                        InstructionSelector::SupportedMachineOperatorFlags(),
4041                        InstructionSelector::AlignmentRequirements()))),
4042       compilation_zone_(isolate->allocator(), ZONE_NAME),
4043       info_(function->name_length != 0
4044                 ? module_env->wire_bytes.GetNameOrNull(function)
4045                 : CStrVector(GetTaggedFunctionName(function)),
4046             isolate, &compilation_zone_,
4047             Code::ComputeFlags(Code::WASM_FUNCTION)),
4048       job_(),
4049       index_(index),
4050       ok_(true),
4051       protected_instructions_(&compilation_zone_) {
4052   // Create and cache this node in the main thread.
4053   jsgraph_->CEntryStubConstant(1);
4054 }
4055 
ExecuteCompilation()4056 void WasmCompilationUnit::ExecuteCompilation() {
4057   // TODO(ahaas): The counters are not thread-safe at the moment.
4058   //    HistogramTimerScope wasm_compile_function_time_scope(
4059   //        isolate_->counters()->wasm_compile_function_time());
4060   if (FLAG_trace_wasm_compiler) {
4061     OFStream os(stdout);
4062     os << "Compiling WASM function "
4063        << wasm::WasmFunctionName(
4064               function_, module_env_->wire_bytes.GetNameOrNull(function_))
4065        << std::endl;
4066     os << std::endl;
4067   }
4068 
4069   double decode_ms = 0;
4070   size_t node_count = 0;
4071 
4072   std::unique_ptr<Zone> graph_zone(graph_zone_.release());
4073   SourcePositionTable* source_positions = BuildGraphForWasmFunction(&decode_ms);
4074 
4075   if (graph_construction_result_.failed()) {
4076     ok_ = false;
4077     return;
4078   }
4079 
4080   base::ElapsedTimer pipeline_timer;
4081   if (FLAG_trace_wasm_decode_time) {
4082     node_count = jsgraph_->graph()->NodeCount();
4083     pipeline_timer.Start();
4084   }
4085 
4086   // Run the compiler pipeline to generate machine code.
4087   CallDescriptor* descriptor = wasm::ModuleEnv::GetWasmCallDescriptor(
4088       &compilation_zone_, function_->sig);
4089   if (jsgraph_->machine()->Is32()) {
4090     descriptor = module_env_->module_env.GetI32WasmCallDescriptor(
4091         &compilation_zone_, descriptor);
4092   }
4093   job_.reset(Pipeline::NewWasmCompilationJob(
4094       &info_, jsgraph_, descriptor, source_positions, &protected_instructions_,
4095       module_env_->module_env.module->origin != wasm::kWasmOrigin));
4096   ok_ = job_->ExecuteJob() == CompilationJob::SUCCEEDED;
4097   // TODO(bradnelson): Improve histogram handling of size_t.
4098   // TODO(ahaas): The counters are not thread-safe at the moment.
4099   //    isolate_->counters()->wasm_compile_function_peak_memory_bytes()
4100   // ->AddSample(
4101   //        static_cast<int>(jsgraph->graph()->zone()->allocation_size()));
4102 
4103   if (FLAG_trace_wasm_decode_time) {
4104     double pipeline_ms = pipeline_timer.Elapsed().InMillisecondsF();
4105     PrintF(
4106         "wasm-compilation phase 1 ok: %u bytes, %0.3f ms decode, %zu nodes, "
4107         "%0.3f ms pipeline\n",
4108         function_->code_end_offset - function_->code_start_offset, decode_ms,
4109         node_count, pipeline_ms);
4110   }
4111 }
4112 
FinishCompilation()4113 Handle<Code> WasmCompilationUnit::FinishCompilation() {
4114   if (!ok_) {
4115     if (graph_construction_result_.failed()) {
4116       // Add the function as another context for the exception
4117       ScopedVector<char> buffer(128);
4118       wasm::WasmName name = module_env_->wire_bytes.GetName(function_);
4119       SNPrintF(buffer, "Compiling WASM function #%d:%.*s failed:",
4120                function_->func_index, name.length(), name.start());
4121       thrower_->CompileFailed(buffer.start(), graph_construction_result_);
4122     }
4123 
4124     return Handle<Code>::null();
4125   }
4126   base::ElapsedTimer codegen_timer;
4127   if (FLAG_trace_wasm_decode_time) {
4128     codegen_timer.Start();
4129   }
4130   if (job_->FinalizeJob() != CompilationJob::SUCCEEDED) {
4131     return Handle<Code>::null();
4132   }
4133   Handle<Code> code = info_.code();
4134   DCHECK(!code.is_null());
4135 
4136   if (isolate_->logger()->is_logging_code_events() ||
4137       isolate_->is_profiling()) {
4138     RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate_, code,
4139                               "WASM_function", function_->func_index,
4140                               wasm::WasmName("module"),
4141                               module_env_->wire_bytes.GetName(function_));
4142   }
4143 
4144   if (FLAG_trace_wasm_decode_time) {
4145     double codegen_ms = codegen_timer.Elapsed().InMillisecondsF();
4146     PrintF("wasm-code-generation ok: %u bytes, %0.3f ms code generation\n",
4147            function_->code_end_offset - function_->code_start_offset,
4148            codegen_ms);
4149   }
4150 
4151   return code;
4152 }
4153 
4154 }  // namespace compiler
4155 }  // namespace internal
4156 }  // namespace v8
4157