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