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