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