blob: 9c3858dd438f105b1418dfc16d0b88c43739d579 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/wasm-compiler.h"
6
7#include "src/isolate-inl.h"
8
9#include "src/base/platform/platform.h"
10
11#include "src/compiler/access-builder.h"
12#include "src/compiler/change-lowering.h"
13#include "src/compiler/common-operator.h"
14#include "src/compiler/diamond.h"
15#include "src/compiler/graph.h"
16#include "src/compiler/graph-visualizer.h"
17#include "src/compiler/instruction-selector.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010018#include "src/compiler/int64-lowering.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019#include "src/compiler/js-generic-lowering.h"
20#include "src/compiler/js-graph.h"
21#include "src/compiler/js-operator.h"
22#include "src/compiler/linkage.h"
23#include "src/compiler/machine-operator.h"
24#include "src/compiler/node-matchers.h"
25#include "src/compiler/pipeline.h"
26#include "src/compiler/simplified-lowering.h"
27#include "src/compiler/simplified-operator.h"
28#include "src/compiler/source-position.h"
29#include "src/compiler/typer.h"
30
31#include "src/code-factory.h"
32#include "src/code-stubs.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010033#include "src/factory.h"
34#include "src/log-inl.h"
35#include "src/profiler/cpu-profiler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036
37#include "src/wasm/ast-decoder.h"
38#include "src/wasm/wasm-module.h"
39#include "src/wasm/wasm-opcodes.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 if (wasm::WasmOpcodes::IsSupported(opcode)) {
55 V8_Fatal(__FILE__, __LINE__,
56 "Unsupported opcode #%d:%s reported as supported", opcode,
57 wasm::WasmOpcodes::OpcodeName(opcode));
58 }
59 V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", opcode,
60 wasm::WasmOpcodes::OpcodeName(opcode));
61 return nullptr;
62}
63
64
65void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
66 Graph* g = jsgraph->graph();
67 if (g->end()) {
68 NodeProperties::MergeControlToEnd(g, jsgraph->common(), node);
69 } else {
70 g->SetEnd(g->NewNode(jsgraph->common()->End(1), node));
71 }
72}
73
74
75enum TrapReason {
76 kTrapUnreachable,
77 kTrapMemOutOfBounds,
78 kTrapDivByZero,
79 kTrapDivUnrepresentable,
80 kTrapRemByZero,
81 kTrapFloatUnrepresentable,
82 kTrapFuncInvalid,
83 kTrapFuncSigMismatch,
84 kTrapCount
85};
86
87
88static const char* kTrapMessages[] = {
89 "unreachable", "memory access out of bounds",
90 "divide by zero", "divide result unrepresentable",
91 "remainder by zero", "integer result unrepresentable",
92 "invalid function", "function signature mismatch"};
93} // namespace
94
95
96// A helper that handles building graph fragments for trapping.
97// To avoid generating a ton of redundant code that just calls the runtime
98// to trap, we generate a per-trap-reason block of code that all trap sites
99// in this function will branch to.
100class WasmTrapHelper : public ZoneObject {
101 public:
102 explicit WasmTrapHelper(WasmGraphBuilder* builder)
103 : builder_(builder),
104 jsgraph_(builder->jsgraph()),
105 graph_(builder->jsgraph() ? builder->jsgraph()->graph() : nullptr) {
106 for (int i = 0; i < kTrapCount; i++) traps_[i] = nullptr;
107 }
108
109 // Make the current control path trap to unreachable.
110 void Unreachable() { ConnectTrap(kTrapUnreachable); }
111
Ben Murdoch097c5b22016-05-18 11:27:45 +0100112 // Always trap with the given reason.
113 void TrapAlways(TrapReason reason) { ConnectTrap(reason); }
114
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 // Add a check that traps if {node} is equal to {val}.
116 Node* TrapIfEq32(TrapReason reason, Node* node, int32_t val) {
117 Int32Matcher m(node);
118 if (m.HasValue() && !m.Is(val)) return graph()->start();
119 if (val == 0) {
120 AddTrapIfFalse(reason, node);
121 } else {
122 AddTrapIfTrue(reason,
123 graph()->NewNode(jsgraph()->machine()->Word32Equal(), node,
124 jsgraph()->Int32Constant(val)));
125 }
126 return builder_->Control();
127 }
128
129 // Add a check that traps if {node} is zero.
130 Node* ZeroCheck32(TrapReason reason, Node* node) {
131 return TrapIfEq32(reason, node, 0);
132 }
133
134 // Add a check that traps if {node} is equal to {val}.
135 Node* TrapIfEq64(TrapReason reason, Node* node, int64_t val) {
136 Int64Matcher m(node);
137 if (m.HasValue() && !m.Is(val)) return graph()->start();
138 AddTrapIfTrue(reason,
139 graph()->NewNode(jsgraph()->machine()->Word64Equal(), node,
140 jsgraph()->Int64Constant(val)));
141 return builder_->Control();
142 }
143
144 // Add a check that traps if {node} is zero.
145 Node* ZeroCheck64(TrapReason reason, Node* node) {
146 return TrapIfEq64(reason, node, 0);
147 }
148
149 // Add a trap if {cond} is true.
150 void AddTrapIfTrue(TrapReason reason, Node* cond) {
151 AddTrapIf(reason, cond, true);
152 }
153
154 // Add a trap if {cond} is false.
155 void AddTrapIfFalse(TrapReason reason, Node* cond) {
156 AddTrapIf(reason, cond, false);
157 }
158
159 // Add a trap if {cond} is true or false according to {iftrue}.
160 void AddTrapIf(TrapReason reason, Node* cond, bool iftrue) {
161 Node** effect_ptr = builder_->effect_;
162 Node** control_ptr = builder_->control_;
163 Node* before = *effect_ptr;
164 BranchHint hint = iftrue ? BranchHint::kFalse : BranchHint::kTrue;
165 Node* branch = graph()->NewNode(common()->Branch(hint), cond, *control_ptr);
166 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
167 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
168
169 *control_ptr = iftrue ? if_true : if_false;
170 ConnectTrap(reason);
171 *control_ptr = iftrue ? if_false : if_true;
172 *effect_ptr = before;
173 }
174
Ben Murdoch097c5b22016-05-18 11:27:45 +0100175 Node* GetTrapValue(wasm::FunctionSig* sig) {
176 if (sig->return_count() > 0) {
177 switch (sig->GetReturn()) {
178 case wasm::kAstI32:
179 return jsgraph()->Int32Constant(0xdeadbeef);
180 case wasm::kAstI64:
181 return jsgraph()->Int64Constant(0xdeadbeefdeadbeef);
182 case wasm::kAstF32:
183 return jsgraph()->Float32Constant(bit_cast<float>(0xdeadbeef));
184 case wasm::kAstF64:
185 return jsgraph()->Float64Constant(
186 bit_cast<double>(0xdeadbeefdeadbeef));
187 break;
188 default:
189 UNREACHABLE();
190 return nullptr;
191 }
192 } else {
193 return jsgraph()->Int32Constant(0xdeadbeef);
194 }
195 }
196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 private:
198 WasmGraphBuilder* builder_;
199 JSGraph* jsgraph_;
200 Graph* graph_;
201 Node* traps_[kTrapCount];
202 Node* effects_[kTrapCount];
203
204 JSGraph* jsgraph() { return jsgraph_; }
205 Graph* graph() { return jsgraph_->graph(); }
206 CommonOperatorBuilder* common() { return jsgraph()->common(); }
207
208 void ConnectTrap(TrapReason reason) {
209 if (traps_[reason] == nullptr) {
210 // Create trap code for the first time this trap is used.
211 return BuildTrapCode(reason);
212 }
213 // Connect the current control and effect to the existing trap code.
214 builder_->AppendToMerge(traps_[reason], builder_->Control());
215 builder_->AppendToPhi(traps_[reason], effects_[reason], builder_->Effect());
216 }
217
218 void BuildTrapCode(TrapReason reason) {
219 Node* exception = builder_->String(kTrapMessages[reason]);
220 Node* end;
221 Node** control_ptr = builder_->control_;
222 Node** effect_ptr = builder_->effect_;
223 wasm::ModuleEnv* module = builder_->module_;
224 *control_ptr = traps_[reason] =
225 graph()->NewNode(common()->Merge(1), *control_ptr);
226 *effect_ptr = effects_[reason] =
227 graph()->NewNode(common()->EffectPhi(1), *effect_ptr, *control_ptr);
228
Ben Murdoch097c5b22016-05-18 11:27:45 +0100229 if (module && !module->instance->context.is_null()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 // Use the module context to call the runtime to throw an exception.
231 Runtime::FunctionId f = Runtime::kThrow;
232 const Runtime::Function* fun = Runtime::FunctionForId(f);
233 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
234 jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
235 CallDescriptor::kNoFlags);
236 Node* inputs[] = {
237 jsgraph()->CEntryStubConstant(fun->result_size), // C entry
238 exception, // exception
239 jsgraph()->ExternalConstant(
240 ExternalReference(f, jsgraph()->isolate())), // ref
241 jsgraph()->Int32Constant(fun->nargs), // arity
Ben Murdoch097c5b22016-05-18 11:27:45 +0100242 jsgraph()->Constant(module->instance->context), // context
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 *effect_ptr,
244 *control_ptr};
245
246 Node* node = graph()->NewNode(
247 common()->Call(desc), static_cast<int>(arraysize(inputs)), inputs);
248 *control_ptr = node;
249 *effect_ptr = node;
250 }
251 if (false) {
252 // End the control flow with a throw
253 Node* thrw =
254 graph()->NewNode(common()->Throw(), jsgraph()->ZeroConstant(),
255 *effect_ptr, *control_ptr);
256 end = thrw;
257 } else {
258 // End the control flow with returning 0xdeadbeef
Ben Murdoch097c5b22016-05-18 11:27:45 +0100259 Node* ret_value = GetTrapValue(builder_->GetFunctionSignature());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 end = graph()->NewNode(jsgraph()->common()->Return(), ret_value,
261 *effect_ptr, *control_ptr);
262 }
263
264 MergeControlToEnd(jsgraph(), end);
265 }
266};
267
268
269WasmGraphBuilder::WasmGraphBuilder(Zone* zone, JSGraph* jsgraph,
270 wasm::FunctionSig* function_signature)
271 : zone_(zone),
272 jsgraph_(jsgraph),
273 module_(nullptr),
274 mem_buffer_(nullptr),
275 mem_size_(nullptr),
276 function_table_(nullptr),
277 control_(nullptr),
278 effect_(nullptr),
279 cur_buffer_(def_buffer_),
280 cur_bufsize_(kDefaultBufferSize),
281 trap_(new (zone) WasmTrapHelper(this)),
282 function_signature_(function_signature) {
283 DCHECK_NOT_NULL(jsgraph_);
284}
285
286
287Node* WasmGraphBuilder::Error() { return jsgraph()->Dead(); }
288
289
290Node* WasmGraphBuilder::Start(unsigned params) {
291 Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
292 graph()->SetStart(start);
293 return start;
294}
295
296
297Node* WasmGraphBuilder::Param(unsigned index, wasm::LocalType type) {
298 return graph()->NewNode(jsgraph()->common()->Parameter(index),
299 graph()->start());
300}
301
302
303Node* WasmGraphBuilder::Loop(Node* entry) {
304 return graph()->NewNode(jsgraph()->common()->Loop(1), entry);
305}
306
307
308Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
309 Node* terminate =
310 graph()->NewNode(jsgraph()->common()->Terminate(), effect, control);
311 MergeControlToEnd(jsgraph(), terminate);
312 return terminate;
313}
314
315
316unsigned WasmGraphBuilder::InputCount(Node* node) {
317 return static_cast<unsigned>(node->InputCount());
318}
319
320
321bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
322 return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
323 NodeProperties::GetControlInput(phi) == merge;
324}
325
326
327void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) {
328 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
329 merge->AppendInput(jsgraph()->zone(), from);
330 int new_size = merge->InputCount();
331 NodeProperties::ChangeOp(
332 merge, jsgraph()->common()->ResizeMergeOrPhi(merge->op(), new_size));
333}
334
335
336void WasmGraphBuilder::AppendToPhi(Node* merge, Node* phi, Node* from) {
337 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
338 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
339 int new_size = phi->InputCount();
340 phi->InsertInput(jsgraph()->zone(), phi->InputCount() - 1, from);
341 NodeProperties::ChangeOp(
342 phi, jsgraph()->common()->ResizeMergeOrPhi(phi->op(), new_size));
343}
344
345
346Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
347 return graph()->NewNode(jsgraph()->common()->Merge(count), count, controls);
348}
349
350
351Node* WasmGraphBuilder::Phi(wasm::LocalType type, unsigned count, Node** vals,
352 Node* control) {
353 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
354 Node** buf = Realloc(vals, count);
355 buf = Realloc(buf, count + 1);
356 buf[count] = control;
357 return graph()->NewNode(jsgraph()->common()->Phi(type, count), count + 1,
358 buf);
359}
360
361
362Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
363 Node* control) {
364 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
365 Node** buf = Realloc(effects, count);
366 buf = Realloc(buf, count + 1);
367 buf[count] = control;
368 return graph()->NewNode(jsgraph()->common()->EffectPhi(count), count + 1,
369 buf);
370}
371
372
373Node* WasmGraphBuilder::Int32Constant(int32_t value) {
374 return jsgraph()->Int32Constant(value);
375}
376
377
378Node* WasmGraphBuilder::Int64Constant(int64_t value) {
379 return jsgraph()->Int64Constant(value);
380}
381
382
383Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
384 Node* right) {
385 const Operator* op;
386 MachineOperatorBuilder* m = jsgraph()->machine();
387 switch (opcode) {
388 case wasm::kExprI32Add:
389 op = m->Int32Add();
390 break;
391 case wasm::kExprI32Sub:
392 op = m->Int32Sub();
393 break;
394 case wasm::kExprI32Mul:
395 op = m->Int32Mul();
396 break;
397 case wasm::kExprI32DivS: {
398 trap_->ZeroCheck32(kTrapDivByZero, right);
399 Node* before = *control_;
400 Node* denom_is_m1;
401 Node* denom_is_not_m1;
402 Branch(graph()->NewNode(jsgraph()->machine()->Word32Equal(), right,
403 jsgraph()->Int32Constant(-1)),
404 &denom_is_m1, &denom_is_not_m1);
405 *control_ = denom_is_m1;
406 trap_->TrapIfEq32(kTrapDivUnrepresentable, left, kMinInt);
407 if (*control_ != denom_is_m1) {
408 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2),
409 denom_is_not_m1, *control_);
410 } else {
411 *control_ = before;
412 }
413 return graph()->NewNode(m->Int32Div(), left, right, *control_);
414 }
415 case wasm::kExprI32DivU:
416 op = m->Uint32Div();
417 return graph()->NewNode(op, left, right,
418 trap_->ZeroCheck32(kTrapDivByZero, right));
419 case wasm::kExprI32RemS: {
420 trap_->ZeroCheck32(kTrapRemByZero, right);
421 Diamond d(graph(), jsgraph()->common(),
422 graph()->NewNode(jsgraph()->machine()->Word32Equal(), right,
423 jsgraph()->Int32Constant(-1)));
424
425 Node* rem = graph()->NewNode(m->Int32Mod(), left, right, d.if_false);
426
427 return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
428 rem);
429 }
430 case wasm::kExprI32RemU:
431 op = m->Uint32Mod();
432 return graph()->NewNode(op, left, right,
433 trap_->ZeroCheck32(kTrapRemByZero, right));
434 case wasm::kExprI32And:
435 op = m->Word32And();
436 break;
437 case wasm::kExprI32Ior:
438 op = m->Word32Or();
439 break;
440 case wasm::kExprI32Xor:
441 op = m->Word32Xor();
442 break;
443 case wasm::kExprI32Shl:
444 op = m->Word32Shl();
445 break;
446 case wasm::kExprI32ShrU:
447 op = m->Word32Shr();
448 break;
449 case wasm::kExprI32ShrS:
450 op = m->Word32Sar();
451 break;
452 case wasm::kExprI32Eq:
453 op = m->Word32Equal();
454 break;
455 case wasm::kExprI32Ne:
456 return Invert(Binop(wasm::kExprI32Eq, left, right));
457 case wasm::kExprI32LtS:
458 op = m->Int32LessThan();
459 break;
460 case wasm::kExprI32LeS:
461 op = m->Int32LessThanOrEqual();
462 break;
463 case wasm::kExprI32LtU:
464 op = m->Uint32LessThan();
465 break;
466 case wasm::kExprI32LeU:
467 op = m->Uint32LessThanOrEqual();
468 break;
469 case wasm::kExprI32GtS:
470 op = m->Int32LessThan();
471 std::swap(left, right);
472 break;
473 case wasm::kExprI32GeS:
474 op = m->Int32LessThanOrEqual();
475 std::swap(left, right);
476 break;
477 case wasm::kExprI32GtU:
478 op = m->Uint32LessThan();
479 std::swap(left, right);
480 break;
481 case wasm::kExprI32GeU:
482 op = m->Uint32LessThanOrEqual();
483 std::swap(left, right);
484 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100485 case wasm::kExprI64And:
486 op = m->Word64And();
487 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488#if WASM_64
489 // Opcodes only supported on 64-bit platforms.
490 // TODO(titzer): query the machine operator builder here instead of #ifdef.
491 case wasm::kExprI64Add:
492 op = m->Int64Add();
493 break;
494 case wasm::kExprI64Sub:
495 op = m->Int64Sub();
496 break;
497 case wasm::kExprI64Mul:
498 op = m->Int64Mul();
499 break;
500 case wasm::kExprI64DivS: {
501 trap_->ZeroCheck64(kTrapDivByZero, right);
502 Node* before = *control_;
503 Node* denom_is_m1;
504 Node* denom_is_not_m1;
505 Branch(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
506 jsgraph()->Int64Constant(-1)),
507 &denom_is_m1, &denom_is_not_m1);
508 *control_ = denom_is_m1;
509 trap_->TrapIfEq64(kTrapDivUnrepresentable, left,
510 std::numeric_limits<int64_t>::min());
511 if (*control_ != denom_is_m1) {
512 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2),
513 denom_is_not_m1, *control_);
514 } else {
515 *control_ = before;
516 }
517 return graph()->NewNode(m->Int64Div(), left, right, *control_);
518 }
519 case wasm::kExprI64DivU:
520 op = m->Uint64Div();
521 return graph()->NewNode(op, left, right,
522 trap_->ZeroCheck64(kTrapDivByZero, right));
523 case wasm::kExprI64RemS: {
524 trap_->ZeroCheck64(kTrapRemByZero, right);
525 Diamond d(jsgraph()->graph(), jsgraph()->common(),
526 graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
527 jsgraph()->Int64Constant(-1)));
528
529 Node* rem = graph()->NewNode(m->Int64Mod(), left, right, d.if_false);
530
531 return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
532 rem);
533 }
534 case wasm::kExprI64RemU:
535 op = m->Uint64Mod();
536 return graph()->NewNode(op, left, right,
537 trap_->ZeroCheck64(kTrapRemByZero, right));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 case wasm::kExprI64Ior:
539 op = m->Word64Or();
540 break;
541 case wasm::kExprI64Xor:
542 op = m->Word64Xor();
543 break;
544 case wasm::kExprI64Shl:
545 op = m->Word64Shl();
546 break;
547 case wasm::kExprI64ShrU:
548 op = m->Word64Shr();
549 break;
550 case wasm::kExprI64ShrS:
551 op = m->Word64Sar();
552 break;
553 case wasm::kExprI64Eq:
554 op = m->Word64Equal();
555 break;
556 case wasm::kExprI64Ne:
557 return Invert(Binop(wasm::kExprI64Eq, left, right));
558 case wasm::kExprI64LtS:
559 op = m->Int64LessThan();
560 break;
561 case wasm::kExprI64LeS:
562 op = m->Int64LessThanOrEqual();
563 break;
564 case wasm::kExprI64LtU:
565 op = m->Uint64LessThan();
566 break;
567 case wasm::kExprI64LeU:
568 op = m->Uint64LessThanOrEqual();
569 break;
570 case wasm::kExprI64GtS:
571 op = m->Int64LessThan();
572 std::swap(left, right);
573 break;
574 case wasm::kExprI64GeS:
575 op = m->Int64LessThanOrEqual();
576 std::swap(left, right);
577 break;
578 case wasm::kExprI64GtU:
579 op = m->Uint64LessThan();
580 std::swap(left, right);
581 break;
582 case wasm::kExprI64GeU:
583 op = m->Uint64LessThanOrEqual();
584 std::swap(left, right);
585 break;
586#endif
587
588 case wasm::kExprF32CopySign:
589 return BuildF32CopySign(left, right);
590 case wasm::kExprF64CopySign:
591 return BuildF64CopySign(left, right);
592 case wasm::kExprF32Add:
593 op = m->Float32Add();
594 break;
595 case wasm::kExprF32Sub:
596 op = m->Float32Sub();
597 break;
598 case wasm::kExprF32Mul:
599 op = m->Float32Mul();
600 break;
601 case wasm::kExprF32Div:
602 op = m->Float32Div();
603 break;
604 case wasm::kExprF32Eq:
605 op = m->Float32Equal();
606 break;
607 case wasm::kExprF32Ne:
608 return Invert(Binop(wasm::kExprF32Eq, left, right));
609 case wasm::kExprF32Lt:
610 op = m->Float32LessThan();
611 break;
612 case wasm::kExprF32Ge:
613 op = m->Float32LessThanOrEqual();
614 std::swap(left, right);
615 break;
616 case wasm::kExprF32Gt:
617 op = m->Float32LessThan();
618 std::swap(left, right);
619 break;
620 case wasm::kExprF32Le:
621 op = m->Float32LessThanOrEqual();
622 break;
623 case wasm::kExprF64Add:
624 op = m->Float64Add();
625 break;
626 case wasm::kExprF64Sub:
627 op = m->Float64Sub();
628 break;
629 case wasm::kExprF64Mul:
630 op = m->Float64Mul();
631 break;
632 case wasm::kExprF64Div:
633 op = m->Float64Div();
634 break;
635 case wasm::kExprF64Eq:
636 op = m->Float64Equal();
637 break;
638 case wasm::kExprF64Ne:
639 return Invert(Binop(wasm::kExprF64Eq, left, right));
640 case wasm::kExprF64Lt:
641 op = m->Float64LessThan();
642 break;
643 case wasm::kExprF64Le:
644 op = m->Float64LessThanOrEqual();
645 break;
646 case wasm::kExprF64Gt:
647 op = m->Float64LessThan();
648 std::swap(left, right);
649 break;
650 case wasm::kExprF64Ge:
651 op = m->Float64LessThanOrEqual();
652 std::swap(left, right);
653 break;
654 case wasm::kExprF32Min:
655 return BuildF32Min(left, right);
656 case wasm::kExprF64Min:
657 return BuildF64Min(left, right);
658 case wasm::kExprF32Max:
659 return BuildF32Max(left, right);
660 case wasm::kExprF64Max:
661 return BuildF64Max(left, right);
662 default:
663 op = UnsupportedOpcode(opcode);
664 }
665 return graph()->NewNode(op, left, right);
666}
667
668
669Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input) {
670 const Operator* op;
671 MachineOperatorBuilder* m = jsgraph()->machine();
672 switch (opcode) {
673 case wasm::kExprBoolNot:
674 op = m->Word32Equal();
675 return graph()->NewNode(op, input, jsgraph()->Int32Constant(0));
676 case wasm::kExprF32Abs:
677 op = m->Float32Abs();
678 break;
679 case wasm::kExprF32Neg:
680 return BuildF32Neg(input);
681 case wasm::kExprF32Sqrt:
682 op = m->Float32Sqrt();
683 break;
684 case wasm::kExprF64Abs:
685 op = m->Float64Abs();
686 break;
687 case wasm::kExprF64Neg:
688 return BuildF64Neg(input);
689 case wasm::kExprF64Sqrt:
690 op = m->Float64Sqrt();
691 break;
692 case wasm::kExprI32SConvertF64:
693 return BuildI32SConvertF64(input);
694 case wasm::kExprI32UConvertF64:
695 return BuildI32UConvertF64(input);
696 case wasm::kExprF32ConvertF64:
697 op = m->TruncateFloat64ToFloat32();
698 break;
699 case wasm::kExprF64SConvertI32:
700 op = m->ChangeInt32ToFloat64();
701 break;
702 case wasm::kExprF64UConvertI32:
703 op = m->ChangeUint32ToFloat64();
704 break;
705 case wasm::kExprF32SConvertI32:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100706 op = m->RoundInt32ToFloat32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000707 break;
708 case wasm::kExprF32UConvertI32:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100709 op = m->RoundUint32ToFloat32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000710 break;
711 case wasm::kExprI32SConvertF32:
712 return BuildI32SConvertF32(input);
713 case wasm::kExprI32UConvertF32:
714 return BuildI32UConvertF32(input);
715 case wasm::kExprF64ConvertF32:
716 op = m->ChangeFloat32ToFloat64();
717 break;
718 case wasm::kExprF32ReinterpretI32:
719 op = m->BitcastInt32ToFloat32();
720 break;
721 case wasm::kExprI32ReinterpretF32:
722 op = m->BitcastFloat32ToInt32();
723 break;
724 case wasm::kExprI32Clz:
725 op = m->Word32Clz();
726 break;
727 case wasm::kExprI32Ctz: {
728 if (m->Word32Ctz().IsSupported()) {
729 op = m->Word32Ctz().op();
730 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100731 } else if (m->Word32ReverseBits().IsSupported()) {
732 Node* reversed = graph()->NewNode(m->Word32ReverseBits().op(), input);
733 Node* result = graph()->NewNode(m->Word32Clz(), reversed);
734 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735 } else {
736 return BuildI32Ctz(input);
737 }
738 }
739 case wasm::kExprI32Popcnt: {
740 if (m->Word32Popcnt().IsSupported()) {
741 op = m->Word32Popcnt().op();
742 break;
743 } else {
744 return BuildI32Popcnt(input);
745 }
746 }
747 case wasm::kExprF32Floor: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100748 if (!m->Float32RoundDown().IsSupported()) return BuildF32Floor(input);
749 op = m->Float32RoundDown().op();
750 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000751 }
752 case wasm::kExprF32Ceil: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100753 if (!m->Float32RoundUp().IsSupported()) return BuildF32Ceil(input);
754 op = m->Float32RoundUp().op();
755 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756 }
757 case wasm::kExprF32Trunc: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100758 if (!m->Float32RoundTruncate().IsSupported()) return BuildF32Trunc(input);
759 op = m->Float32RoundTruncate().op();
760 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 }
762 case wasm::kExprF32NearestInt: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100763 if (!m->Float32RoundTiesEven().IsSupported())
764 return BuildF32NearestInt(input);
765 op = m->Float32RoundTiesEven().op();
766 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000767 }
768 case wasm::kExprF64Floor: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100769 if (!m->Float64RoundDown().IsSupported()) return BuildF64Floor(input);
770 op = m->Float64RoundDown().op();
771 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000772 }
773 case wasm::kExprF64Ceil: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100774 if (!m->Float64RoundUp().IsSupported()) return BuildF64Ceil(input);
775 op = m->Float64RoundUp().op();
776 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000777 }
778 case wasm::kExprF64Trunc: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100779 if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input);
780 op = m->Float64RoundTruncate().op();
781 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782 }
783 case wasm::kExprF64NearestInt: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100784 if (!m->Float64RoundTiesEven().IsSupported())
785 return BuildF64NearestInt(input);
786 op = m->Float64RoundTiesEven().op();
787 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789 case wasm::kExprI32ConvertI64:
790 op = m->TruncateInt64ToInt32();
791 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100792#if WASM_64
793 // Opcodes only supported on 64-bit platforms.
794 // TODO(titzer): query the machine operator builder here instead of #ifdef.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000795 case wasm::kExprI64SConvertI32:
796 op = m->ChangeInt32ToInt64();
797 break;
798 case wasm::kExprI64UConvertI32:
799 op = m->ChangeUint32ToUint64();
800 break;
801 case wasm::kExprF32SConvertI64:
802 op = m->RoundInt64ToFloat32();
803 break;
804 case wasm::kExprF32UConvertI64:
805 op = m->RoundUint64ToFloat32();
806 break;
807 case wasm::kExprF64SConvertI64:
808 op = m->RoundInt64ToFloat64();
809 break;
810 case wasm::kExprF64UConvertI64:
811 op = m->RoundUint64ToFloat64();
812 break;
813 case wasm::kExprI64SConvertF32: {
814 Node* trunc = graph()->NewNode(m->TryTruncateFloat32ToInt64(), input);
815 Node* result =
816 graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
817 Node* overflow =
818 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
819 trap_->ZeroCheck64(kTrapFloatUnrepresentable, overflow);
820 return result;
821 }
822 case wasm::kExprI64SConvertF64: {
823 Node* trunc = graph()->NewNode(m->TryTruncateFloat64ToInt64(), input);
824 Node* result =
825 graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
826 Node* overflow =
827 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
828 trap_->ZeroCheck64(kTrapFloatUnrepresentable, overflow);
829 return result;
830 }
831 case wasm::kExprI64UConvertF32: {
832 Node* trunc = graph()->NewNode(m->TryTruncateFloat32ToUint64(), input);
833 Node* result =
834 graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
835 Node* overflow =
836 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
837 trap_->ZeroCheck64(kTrapFloatUnrepresentable, overflow);
838 return result;
839 }
840 case wasm::kExprI64UConvertF64: {
841 Node* trunc = graph()->NewNode(m->TryTruncateFloat64ToUint64(), input);
842 Node* result =
843 graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
844 Node* overflow =
845 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
846 trap_->ZeroCheck64(kTrapFloatUnrepresentable, overflow);
847 return result;
848 }
849 case wasm::kExprF64ReinterpretI64:
850 op = m->BitcastInt64ToFloat64();
851 break;
852 case wasm::kExprI64ReinterpretF64:
853 op = m->BitcastFloat64ToInt64();
854 break;
855 case wasm::kExprI64Clz:
856 op = m->Word64Clz();
857 break;
858 case wasm::kExprI64Ctz: {
859 if (m->Word64Ctz().IsSupported()) {
860 op = m->Word64Ctz().op();
861 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100862 } else if (m->Word64ReverseBits().IsSupported()) {
863 Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input);
864 Node* result = graph()->NewNode(m->Word64Clz(), reversed);
865 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000866 } else {
867 return BuildI64Ctz(input);
868 }
869 }
870 case wasm::kExprI64Popcnt: {
871 if (m->Word64Popcnt().IsSupported()) {
872 op = m->Word64Popcnt().op();
873 break;
874 } else {
875 return BuildI64Popcnt(input);
876 }
877 }
878#endif
879 default:
880 op = UnsupportedOpcode(opcode);
881 }
882 return graph()->NewNode(op, input);
883}
884
885
886Node* WasmGraphBuilder::Float32Constant(float value) {
887 return jsgraph()->Float32Constant(value);
888}
889
890
891Node* WasmGraphBuilder::Float64Constant(double value) {
892 return jsgraph()->Float64Constant(value);
893}
894
895
896Node* WasmGraphBuilder::Constant(Handle<Object> value) {
897 return jsgraph()->Constant(value);
898}
899
900
901Node* WasmGraphBuilder::Branch(Node* cond, Node** true_node,
902 Node** false_node) {
903 DCHECK_NOT_NULL(cond);
904 DCHECK_NOT_NULL(*control_);
905 Node* branch =
906 graph()->NewNode(jsgraph()->common()->Branch(), cond, *control_);
907 *true_node = graph()->NewNode(jsgraph()->common()->IfTrue(), branch);
908 *false_node = graph()->NewNode(jsgraph()->common()->IfFalse(), branch);
909 return branch;
910}
911
912
913Node* WasmGraphBuilder::Switch(unsigned count, Node* key) {
914 return graph()->NewNode(jsgraph()->common()->Switch(count), key, *control_);
915}
916
917
918Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) {
919 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
920 return graph()->NewNode(jsgraph()->common()->IfValue(value), sw);
921}
922
923
924Node* WasmGraphBuilder::IfDefault(Node* sw) {
925 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
926 return graph()->NewNode(jsgraph()->common()->IfDefault(), sw);
927}
928
929
930Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
931 DCHECK_NOT_NULL(*control_);
932 DCHECK_NOT_NULL(*effect_);
933
934 if (count == 0) {
935 // Handle a return of void.
936 vals[0] = jsgraph()->Int32Constant(0);
937 count = 1;
938 }
939
940 Node** buf = Realloc(vals, count);
941 buf = Realloc(buf, count + 2);
942 buf[count] = *effect_;
943 buf[count + 1] = *control_;
944 Node* ret = graph()->NewNode(jsgraph()->common()->Return(), count + 2, vals);
945
946 MergeControlToEnd(jsgraph(), ret);
947 return ret;
948}
949
950
951Node* WasmGraphBuilder::ReturnVoid() { return Return(0, Buffer(0)); }
952
953
954Node* WasmGraphBuilder::Unreachable() {
955 trap_->Unreachable();
956 return nullptr;
957}
958
959
960Node* WasmGraphBuilder::BuildF32Neg(Node* input) {
961 Node* result =
962 Unop(wasm::kExprF32ReinterpretI32,
963 Binop(wasm::kExprI32Xor, Unop(wasm::kExprI32ReinterpretF32, input),
964 jsgraph()->Int32Constant(0x80000000)));
965
966 return result;
967}
968
969
970Node* WasmGraphBuilder::BuildF64Neg(Node* input) {
971#if WASM_64
972 Node* result =
973 Unop(wasm::kExprF64ReinterpretI64,
974 Binop(wasm::kExprI64Xor, Unop(wasm::kExprI64ReinterpretF64, input),
975 jsgraph()->Int64Constant(0x8000000000000000)));
976
977 return result;
978#else
979 MachineOperatorBuilder* m = jsgraph()->machine();
980
981 Node* old_high_word = graph()->NewNode(m->Float64ExtractHighWord32(), input);
982 Node* new_high_word = Binop(wasm::kExprI32Xor, old_high_word,
983 jsgraph()->Int32Constant(0x80000000));
984
985 return graph()->NewNode(m->Float64InsertHighWord32(), input, new_high_word);
986#endif
987}
988
989
990Node* WasmGraphBuilder::BuildF32CopySign(Node* left, Node* right) {
991 Node* result = Unop(
992 wasm::kExprF32ReinterpretI32,
993 Binop(wasm::kExprI32Ior,
994 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, left),
995 jsgraph()->Int32Constant(0x7fffffff)),
996 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, right),
997 jsgraph()->Int32Constant(0x80000000))));
998
999 return result;
1000}
1001
1002
1003Node* WasmGraphBuilder::BuildF64CopySign(Node* left, Node* right) {
1004#if WASM_64
1005 Node* result = Unop(
1006 wasm::kExprF64ReinterpretI64,
1007 Binop(wasm::kExprI64Ior,
1008 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, left),
1009 jsgraph()->Int64Constant(0x7fffffffffffffff)),
1010 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, right),
1011 jsgraph()->Int64Constant(0x8000000000000000))));
1012
1013 return result;
1014#else
1015 MachineOperatorBuilder* m = jsgraph()->machine();
1016
1017 Node* high_word_left = graph()->NewNode(m->Float64ExtractHighWord32(), left);
1018 Node* high_word_right =
1019 graph()->NewNode(m->Float64ExtractHighWord32(), right);
1020
1021 Node* new_high_word =
1022 Binop(wasm::kExprI32Ior, Binop(wasm::kExprI32And, high_word_left,
1023 jsgraph()->Int32Constant(0x7fffffff)),
1024 Binop(wasm::kExprI32And, high_word_right,
1025 jsgraph()->Int32Constant(0x80000000)));
1026
1027 return graph()->NewNode(m->Float64InsertHighWord32(), left, new_high_word);
1028#endif
1029}
1030
1031
1032Node* WasmGraphBuilder::BuildF32Min(Node* left, Node* right) {
1033 Diamond left_le_right(graph(), jsgraph()->common(),
1034 Binop(wasm::kExprF32Le, left, right));
1035
1036 Diamond right_lt_left(graph(), jsgraph()->common(),
1037 Binop(wasm::kExprF32Lt, right, left));
1038
1039 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1040 Binop(wasm::kExprF32Eq, left, left));
1041
1042 return left_le_right.Phi(
1043 wasm::kAstF32, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001044 right_lt_left.Phi(
1045 wasm::kAstF32, right,
1046 left_is_not_nan.Phi(
1047 wasm::kAstF32,
1048 Binop(wasm::kExprF32Mul, right, Float32Constant(1.0)),
1049 Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001050}
1051
1052
1053Node* WasmGraphBuilder::BuildF32Max(Node* left, Node* right) {
1054 Diamond left_ge_right(graph(), jsgraph()->common(),
1055 Binop(wasm::kExprF32Ge, left, right));
1056
1057 Diamond right_gt_left(graph(), jsgraph()->common(),
1058 Binop(wasm::kExprF32Gt, right, left));
1059
1060 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1061 Binop(wasm::kExprF32Eq, left, left));
1062
1063 return left_ge_right.Phi(
1064 wasm::kAstF32, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001065 right_gt_left.Phi(
1066 wasm::kAstF32, right,
1067 left_is_not_nan.Phi(
1068 wasm::kAstF32,
1069 Binop(wasm::kExprF32Mul, right, Float32Constant(1.0)),
1070 Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001071}
1072
1073
1074Node* WasmGraphBuilder::BuildF64Min(Node* left, Node* right) {
1075 Diamond left_le_right(graph(), jsgraph()->common(),
1076 Binop(wasm::kExprF64Le, left, right));
1077
1078 Diamond right_lt_left(graph(), jsgraph()->common(),
1079 Binop(wasm::kExprF64Lt, right, left));
1080
1081 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1082 Binop(wasm::kExprF64Eq, left, left));
1083
1084 return left_le_right.Phi(
1085 wasm::kAstF64, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001086 right_lt_left.Phi(
1087 wasm::kAstF64, right,
1088 left_is_not_nan.Phi(
1089 wasm::kAstF64,
1090 Binop(wasm::kExprF64Mul, right, Float64Constant(1.0)),
1091 Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001092}
1093
1094
1095Node* WasmGraphBuilder::BuildF64Max(Node* left, Node* right) {
1096 Diamond left_ge_right(graph(), jsgraph()->common(),
1097 Binop(wasm::kExprF64Ge, left, right));
1098
1099 Diamond right_gt_left(graph(), jsgraph()->common(),
1100 Binop(wasm::kExprF64Lt, right, left));
1101
1102 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1103 Binop(wasm::kExprF64Eq, left, left));
1104
1105 return left_ge_right.Phi(
1106 wasm::kAstF64, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001107 right_gt_left.Phi(
1108 wasm::kAstF64, right,
1109 left_is_not_nan.Phi(
1110 wasm::kAstF64,
1111 Binop(wasm::kExprF64Mul, right, Float64Constant(1.0)),
1112 Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001113}
1114
1115
1116Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input) {
1117 MachineOperatorBuilder* m = jsgraph()->machine();
1118 // Truncation of the input value is needed for the overflow check later.
1119 Node* trunc = Unop(wasm::kExprF32Trunc, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001120 Node* result = graph()->NewNode(m->TruncateFloat32ToInt32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001121
1122 // Convert the result back to f64. If we end up at a different value than the
1123 // truncated input value, then there has been an overflow and we trap.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001124 Node* check = Unop(wasm::kExprF32SConvertI32, result);
1125 Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001126 trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
1127
1128 return result;
1129}
1130
1131
1132Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input) {
1133 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001134 if (module_ && module_->asm_js) {
1135 return graph()->NewNode(
1136 m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
1137 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001138 // Truncation of the input value is needed for the overflow check later.
1139 Node* trunc = Unop(wasm::kExprF64Trunc, input);
1140 Node* result = graph()->NewNode(m->ChangeFloat64ToInt32(), trunc);
1141
1142 // Convert the result back to f64. If we end up at a different value than the
1143 // truncated input value, then there has been an overflow and we trap.
1144 Node* check = Unop(wasm::kExprF64SConvertI32, result);
1145 Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
1146 trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
1147
1148 return result;
1149}
1150
1151
1152Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input) {
1153 MachineOperatorBuilder* m = jsgraph()->machine();
1154 // Truncation of the input value is needed for the overflow check later.
1155 Node* trunc = Unop(wasm::kExprF32Trunc, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001156 Node* result = graph()->NewNode(m->TruncateFloat32ToUint32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157
Ben Murdoch097c5b22016-05-18 11:27:45 +01001158 // Convert the result back to f32. If we end up at a different value than the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159 // truncated input value, then there has been an overflow and we trap.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001160 Node* check = Unop(wasm::kExprF32UConvertI32, result);
1161 Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001162 trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
1163
1164 return result;
1165}
1166
1167
1168Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input) {
1169 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001170 if (module_ && module_->asm_js) {
1171 return graph()->NewNode(
1172 m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
1173 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 // Truncation of the input value is needed for the overflow check later.
1175 Node* trunc = Unop(wasm::kExprF64Trunc, input);
1176 Node* result = graph()->NewNode(m->ChangeFloat64ToUint32(), trunc);
1177
1178 // Convert the result back to f64. If we end up at a different value than the
1179 // truncated input value, then there has been an overflow and we trap.
1180 Node* check = Unop(wasm::kExprF64UConvertI32, result);
1181 Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
1182 trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
1183
1184 return result;
1185}
1186
1187
1188Node* WasmGraphBuilder::BuildI32Ctz(Node* input) {
1189 //// Implement the following code as TF graph.
1190 // value = value | (value << 1);
1191 // value = value | (value << 2);
1192 // value = value | (value << 4);
1193 // value = value | (value << 8);
1194 // value = value | (value << 16);
1195 // return CountPopulation32(0xffffffff XOR value);
1196
1197 Node* result =
1198 Binop(wasm::kExprI32Ior, input,
1199 Binop(wasm::kExprI32Shl, input, jsgraph()->Int32Constant(1)));
1200
1201 result = Binop(wasm::kExprI32Ior, result,
1202 Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(2)));
1203
1204 result = Binop(wasm::kExprI32Ior, result,
1205 Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(4)));
1206
1207 result = Binop(wasm::kExprI32Ior, result,
1208 Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(8)));
1209
1210 result =
1211 Binop(wasm::kExprI32Ior, result,
1212 Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(16)));
1213
1214 result = BuildI32Popcnt(
1215 Binop(wasm::kExprI32Xor, jsgraph()->Int32Constant(0xffffffff), result));
1216
1217 return result;
1218}
1219
1220
1221Node* WasmGraphBuilder::BuildI64Ctz(Node* input) {
1222 //// Implement the following code as TF graph.
1223 // value = value | (value << 1);
1224 // value = value | (value << 2);
1225 // value = value | (value << 4);
1226 // value = value | (value << 8);
1227 // value = value | (value << 16);
1228 // value = value | (value << 32);
1229 // return CountPopulation64(0xffffffffffffffff XOR value);
1230
1231 Node* result =
1232 Binop(wasm::kExprI64Ior, input,
1233 Binop(wasm::kExprI64Shl, input, jsgraph()->Int64Constant(1)));
1234
1235 result = Binop(wasm::kExprI64Ior, result,
1236 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(2)));
1237
1238 result = Binop(wasm::kExprI64Ior, result,
1239 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(4)));
1240
1241 result = Binop(wasm::kExprI64Ior, result,
1242 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(8)));
1243
1244 result =
1245 Binop(wasm::kExprI64Ior, result,
1246 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(16)));
1247
1248 result =
1249 Binop(wasm::kExprI64Ior, result,
1250 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(32)));
1251
1252 result = BuildI64Popcnt(Binop(
1253 wasm::kExprI64Xor, jsgraph()->Int64Constant(0xffffffffffffffff), result));
1254
1255 return result;
1256}
1257
1258
1259Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) {
1260 //// Implement the following code as a TF graph.
1261 // value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
1262 // value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
1263 // value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
1264 // value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
1265 // value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
1266
1267 Node* result = Binop(
1268 wasm::kExprI32Add,
1269 Binop(wasm::kExprI32And,
1270 Binop(wasm::kExprI32ShrU, input, jsgraph()->Int32Constant(1)),
1271 jsgraph()->Int32Constant(0x55555555)),
1272 Binop(wasm::kExprI32And, input, jsgraph()->Int32Constant(0x55555555)));
1273
1274 result = Binop(
1275 wasm::kExprI32Add,
1276 Binop(wasm::kExprI32And,
1277 Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(2)),
1278 jsgraph()->Int32Constant(0x33333333)),
1279 Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x33333333)));
1280
1281 result = Binop(
1282 wasm::kExprI32Add,
1283 Binop(wasm::kExprI32And,
1284 Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(4)),
1285 jsgraph()->Int32Constant(0x0f0f0f0f)),
1286 Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x0f0f0f0f)));
1287
1288 result = Binop(
1289 wasm::kExprI32Add,
1290 Binop(wasm::kExprI32And,
1291 Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(8)),
1292 jsgraph()->Int32Constant(0x00ff00ff)),
1293 Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x00ff00ff)));
1294
1295 result = Binop(
1296 wasm::kExprI32Add,
1297 Binop(wasm::kExprI32And,
1298 Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(16)),
1299 jsgraph()->Int32Constant(0x0000ffff)),
1300 Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x0000ffff)));
1301
1302 return result;
1303}
1304
1305
1306Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) {
1307 //// Implement the following code as a TF graph.
1308 // value = ((value >> 1) & 0x5555555555555555) + (value & 0x5555555555555555);
1309 // value = ((value >> 2) & 0x3333333333333333) + (value & 0x3333333333333333);
1310 // value = ((value >> 4) & 0x0f0f0f0f0f0f0f0f) + (value & 0x0f0f0f0f0f0f0f0f);
1311 // value = ((value >> 8) & 0x00ff00ff00ff00ff) + (value & 0x00ff00ff00ff00ff);
1312 // value = ((value >> 16) & 0x0000ffff0000ffff) + (value &
1313 // 0x0000ffff0000ffff);
1314 // value = ((value >> 32) & 0x00000000ffffffff) + (value &
1315 // 0x00000000ffffffff);
1316
1317 Node* result =
1318 Binop(wasm::kExprI64Add,
1319 Binop(wasm::kExprI64And,
1320 Binop(wasm::kExprI64ShrU, input, jsgraph()->Int64Constant(1)),
1321 jsgraph()->Int64Constant(0x5555555555555555)),
1322 Binop(wasm::kExprI64And, input,
1323 jsgraph()->Int64Constant(0x5555555555555555)));
1324
1325 result = Binop(wasm::kExprI64Add,
1326 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1327 jsgraph()->Int64Constant(2)),
1328 jsgraph()->Int64Constant(0x3333333333333333)),
1329 Binop(wasm::kExprI64And, result,
1330 jsgraph()->Int64Constant(0x3333333333333333)));
1331
1332 result = Binop(wasm::kExprI64Add,
1333 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1334 jsgraph()->Int64Constant(4)),
1335 jsgraph()->Int64Constant(0x0f0f0f0f0f0f0f0f)),
1336 Binop(wasm::kExprI64And, result,
1337 jsgraph()->Int64Constant(0x0f0f0f0f0f0f0f0f)));
1338
1339 result = Binop(wasm::kExprI64Add,
1340 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1341 jsgraph()->Int64Constant(8)),
1342 jsgraph()->Int64Constant(0x00ff00ff00ff00ff)),
1343 Binop(wasm::kExprI64And, result,
1344 jsgraph()->Int64Constant(0x00ff00ff00ff00ff)));
1345
1346 result = Binop(wasm::kExprI64Add,
1347 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1348 jsgraph()->Int64Constant(16)),
1349 jsgraph()->Int64Constant(0x0000ffff0000ffff)),
1350 Binop(wasm::kExprI64And, result,
1351 jsgraph()->Int64Constant(0x0000ffff0000ffff)));
1352
1353 result = Binop(wasm::kExprI64Add,
1354 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1355 jsgraph()->Int64Constant(32)),
1356 jsgraph()->Int64Constant(0x00000000ffffffff)),
1357 Binop(wasm::kExprI64And, result,
1358 jsgraph()->Int64Constant(0x00000000ffffffff)));
1359
1360 return result;
1361}
1362
Ben Murdoch097c5b22016-05-18 11:27:45 +01001363Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
1364 MachineType type = MachineType::Float32();
1365 ExternalReference ref =
1366 ExternalReference::f32_trunc_wrapper_function(jsgraph()->isolate());
1367 return BuildRoundingInstruction(input, ref, type);
1368}
1369
1370Node* WasmGraphBuilder::BuildF32Floor(Node* input) {
1371 MachineType type = MachineType::Float32();
1372 ExternalReference ref =
1373 ExternalReference::f32_floor_wrapper_function(jsgraph()->isolate());
1374 return BuildRoundingInstruction(input, ref, type);
1375}
1376
1377Node* WasmGraphBuilder::BuildF32Ceil(Node* input) {
1378 MachineType type = MachineType::Float32();
1379 ExternalReference ref =
1380 ExternalReference::f32_ceil_wrapper_function(jsgraph()->isolate());
1381 return BuildRoundingInstruction(input, ref, type);
1382}
1383
1384Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) {
1385 MachineType type = MachineType::Float32();
1386 ExternalReference ref =
1387 ExternalReference::f32_nearest_int_wrapper_function(jsgraph()->isolate());
1388 return BuildRoundingInstruction(input, ref, type);
1389}
1390
1391Node* WasmGraphBuilder::BuildF64Trunc(Node* input) {
1392 MachineType type = MachineType::Float64();
1393 ExternalReference ref =
1394 ExternalReference::f64_trunc_wrapper_function(jsgraph()->isolate());
1395 return BuildRoundingInstruction(input, ref, type);
1396}
1397
1398Node* WasmGraphBuilder::BuildF64Floor(Node* input) {
1399 MachineType type = MachineType::Float64();
1400 ExternalReference ref =
1401 ExternalReference::f64_floor_wrapper_function(jsgraph()->isolate());
1402 return BuildRoundingInstruction(input, ref, type);
1403}
1404
1405Node* WasmGraphBuilder::BuildF64Ceil(Node* input) {
1406 MachineType type = MachineType::Float64();
1407 ExternalReference ref =
1408 ExternalReference::f64_ceil_wrapper_function(jsgraph()->isolate());
1409 return BuildRoundingInstruction(input, ref, type);
1410}
1411
1412Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) {
1413 MachineType type = MachineType::Float64();
1414 ExternalReference ref =
1415 ExternalReference::f64_nearest_int_wrapper_function(jsgraph()->isolate());
1416 return BuildRoundingInstruction(input, ref, type);
1417}
1418
1419Node* WasmGraphBuilder::BuildRoundingInstruction(Node* input,
1420 ExternalReference ref,
1421 MachineType type) {
1422 // We do truncation by calling a C function which calculates the truncation
1423 // for us. The input is passed to the C function as a double* to avoid double
1424 // parameters. For this we reserve a slot on the stack, store the parameter in
1425 // that slot, pass a pointer to the slot to the C function, and after calling
1426 // the C function we collect the return value from the stack slot.
1427
1428 Node* stack_slot_param =
1429 graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation()));
1430
1431 const Operator* store_op = jsgraph()->machine()->Store(
1432 StoreRepresentation(type.representation(), kNoWriteBarrier));
1433 *effect_ =
1434 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1435 input, *effect_, *control_);
1436
1437 Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0, 1);
1438 sig_builder.AddParam(MachineType::Pointer());
1439 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1440
1441 Node* args[] = {function, stack_slot_param};
1442
1443 BuildCCall(sig_builder.Build(), args);
1444
1445 const Operator* load_op = jsgraph()->machine()->Load(type);
1446
1447 Node* load =
1448 graph()->NewNode(load_op, stack_slot_param, jsgraph()->Int32Constant(0),
1449 *effect_, *control_);
1450 *effect_ = load;
1451 return load;
1452}
1453
1454Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
1455 const size_t params = sig->parameter_count();
1456 const size_t extra = 2; // effect and control inputs.
1457 const size_t count = 1 + params + extra;
1458
1459 // Reallocate the buffer to make space for extra inputs.
1460 args = Realloc(args, count);
1461
1462 // Add effect and control inputs.
1463 args[params + 1] = *effect_;
1464 args[params + 2] = *control_;
1465
1466 CallDescriptor* desc =
1467 Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig);
1468
1469 const Operator* op = jsgraph()->common()->Call(desc);
1470 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
1471 *effect_ = call;
1472 return call;
1473}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001474
1475Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args) {
1476 const size_t params = sig->parameter_count();
1477 const size_t extra = 2; // effect and control inputs.
1478 const size_t count = 1 + params + extra;
1479
1480 // Reallocate the buffer to make space for extra inputs.
1481 args = Realloc(args, count);
1482
1483 // Add effect and control inputs.
1484 args[params + 1] = *effect_;
1485 args[params + 2] = *control_;
1486
Ben Murdoch097c5b22016-05-18 11:27:45 +01001487 CallDescriptor* descriptor =
1488 wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
1489 const Operator* op = jsgraph()->common()->Call(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001490 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
1491
1492 *effect_ = call;
1493 return call;
1494}
1495
1496
1497Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args) {
1498 DCHECK_NULL(args[0]);
1499
1500 // Add code object as constant.
1501 args[0] = Constant(module_->GetFunctionCode(index));
1502 wasm::FunctionSig* sig = module_->GetFunctionSignature(index);
1503
1504 return BuildWasmCall(sig, args);
1505}
1506
Ben Murdoch097c5b22016-05-18 11:27:45 +01001507Node* WasmGraphBuilder::CallImport(uint32_t index, Node** args) {
1508 DCHECK_NULL(args[0]);
1509
1510 // Add code object as constant.
1511 args[0] = Constant(module_->GetImportCode(index));
1512 wasm::FunctionSig* sig = module_->GetImportSignature(index);
1513
1514 return BuildWasmCall(sig, args);
1515}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001516
1517Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args) {
1518 DCHECK_NOT_NULL(args[0]);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001519 DCHECK(module_ && module_->instance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001520
1521 MachineOperatorBuilder* machine = jsgraph()->machine();
1522
1523 // Compute the code object by loading it from the function table.
1524 Node* key = args[0];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001525
1526 // Bounds check the index.
1527 int table_size = static_cast<int>(module_->FunctionTableSize());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001528 if (table_size > 0) {
1529 // Bounds check against the table size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001530 Node* size = Int32Constant(static_cast<int>(table_size));
1531 Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
1532 trap_->AddTrapIfFalse(kTrapFuncInvalid, in_bounds);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001533 } else {
1534 // No function table. Generate a trap and return a constant.
1535 trap_->AddTrapIfFalse(kTrapFuncInvalid, Int32Constant(0));
1536 return trap_->GetTrapValue(module_->GetSignature(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001537 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001538 Node* table = FunctionTable();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001539
1540 // Load signature from the table and check.
1541 // The table is a FixedArray; signatures are encoded as SMIs.
1542 // [sig1, sig2, sig3, ...., code1, code2, code3 ...]
1543 ElementAccess access = AccessBuilder::ForFixedArrayElement();
1544 const int fixed_offset = access.header_size - access.tag();
1545 {
1546 Node* load_sig = graph()->NewNode(
1547 machine->Load(MachineType::AnyTagged()), table,
1548 graph()->NewNode(machine->Int32Add(),
1549 graph()->NewNode(machine->Word32Shl(), key,
1550 Int32Constant(kPointerSizeLog2)),
1551 Int32Constant(fixed_offset)),
1552 *effect_, *control_);
1553 Node* sig_match = graph()->NewNode(machine->WordEqual(), load_sig,
1554 jsgraph()->SmiConstant(index));
1555 trap_->AddTrapIfFalse(kTrapFuncSigMismatch, sig_match);
1556 }
1557
1558 // Load code object from the table.
1559 int offset = fixed_offset + kPointerSize * table_size;
1560 Node* load_code = graph()->NewNode(
1561 machine->Load(MachineType::AnyTagged()), table,
1562 graph()->NewNode(machine->Int32Add(),
1563 graph()->NewNode(machine->Word32Shl(), key,
1564 Int32Constant(kPointerSizeLog2)),
1565 Int32Constant(offset)),
1566 *effect_, *control_);
1567
1568 args[0] = load_code;
1569 wasm::FunctionSig* sig = module_->GetSignature(index);
1570 return BuildWasmCall(sig, args);
1571}
1572
1573
1574Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
1575 SimplifiedOperatorBuilder simplified(jsgraph()->zone());
1576 switch (type) {
1577 case wasm::kAstI32:
1578 return graph()->NewNode(simplified.ChangeInt32ToTagged(), node);
1579 case wasm::kAstI64:
1580 // TODO(titzer): i64->JS has no good solution right now. Using lower 32
1581 // bits.
1582 node =
1583 graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), node);
1584 return graph()->NewNode(simplified.ChangeInt32ToTagged(), node);
1585 case wasm::kAstF32:
1586 node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
1587 node);
1588 return graph()->NewNode(simplified.ChangeFloat64ToTagged(), node);
1589 case wasm::kAstF64:
1590 return graph()->NewNode(simplified.ChangeFloat64ToTagged(), node);
1591 case wasm::kAstStmt:
1592 return jsgraph()->UndefinedConstant();
1593 default:
1594 UNREACHABLE();
1595 return nullptr;
1596 }
1597}
1598
1599
1600Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
1601 wasm::LocalType type) {
1602 // Do a JavaScript ToNumber.
1603 Node* num =
1604 graph()->NewNode(jsgraph()->javascript()->ToNumber(), node, context,
1605 jsgraph()->EmptyFrameState(), *effect_, *control_);
1606 *control_ = num;
1607 *effect_ = num;
1608
1609 // Change representation.
1610 SimplifiedOperatorBuilder simplified(jsgraph()->zone());
1611 num = graph()->NewNode(simplified.ChangeTaggedToFloat64(), num);
1612
1613 switch (type) {
1614 case wasm::kAstI32: {
1615 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToInt32(
1616 TruncationMode::kJavaScript),
1617 num);
1618 break;
1619 }
1620 case wasm::kAstI64:
1621 // TODO(titzer): JS->i64 has no good solution right now. Using 32 bits.
1622 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToInt32(
1623 TruncationMode::kJavaScript),
1624 num);
1625 num = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), num);
1626 break;
1627 case wasm::kAstF32:
1628 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToFloat32(),
1629 num);
1630 break;
1631 case wasm::kAstF64:
1632 break;
1633 case wasm::kAstStmt:
1634 num = jsgraph()->Int32Constant(0);
1635 break;
1636 default:
1637 UNREACHABLE();
1638 return nullptr;
1639 }
1640 return num;
1641}
1642
1643
1644Node* WasmGraphBuilder::Invert(Node* node) {
1645 return Unop(wasm::kExprBoolNot, node);
1646}
1647
1648
1649void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
1650 wasm::FunctionSig* sig) {
1651 int params = static_cast<int>(sig->parameter_count());
1652 int count = params + 3;
1653 Node** args = Buffer(count);
1654
1655 // Build the start and the JS parameter nodes.
1656 Node* start = Start(params + 3);
1657 *control_ = start;
1658 *effect_ = start;
1659 // JS context is the last parameter.
1660 Node* context = graph()->NewNode(
1661 jsgraph()->common()->Parameter(params + 1, "context"), start);
1662
1663 int pos = 0;
1664 args[pos++] = Constant(wasm_code);
1665
1666 // Convert JS parameters to WASM numbers.
1667 for (int i = 0; i < params; i++) {
1668 Node* param = graph()->NewNode(jsgraph()->common()->Parameter(i), start);
1669 args[pos++] = FromJS(param, context, sig->GetParam(i));
1670 }
1671
1672 args[pos++] = *effect_;
1673 args[pos++] = *control_;
1674
1675 // Call the WASM code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001676 CallDescriptor* desc =
1677 wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001678 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args);
1679 Node* jsval =
1680 ToJS(call, context,
1681 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
1682 Node* ret =
1683 graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start);
1684
1685 MergeControlToEnd(jsgraph(), ret);
1686}
1687
1688
1689void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function,
1690 wasm::FunctionSig* sig) {
1691 int js_count = function->shared()->internal_formal_parameter_count();
1692 int wasm_count = static_cast<int>(sig->parameter_count());
1693
1694 // Build the start and the parameter nodes.
1695 Isolate* isolate = jsgraph()->isolate();
1696 CallDescriptor* desc;
1697 Node* start = Start(wasm_count + 3);
1698 *effect_ = start;
1699 *control_ = start;
1700 // JS context is the last parameter.
1701 Node* context = Constant(Handle<Context>(function->context(), isolate));
1702 Node** args = Buffer(wasm_count + 7);
1703
1704 bool arg_count_before_args = false;
1705 bool add_new_target_undefined = false;
1706
1707 int pos = 0;
1708 if (js_count == wasm_count) {
1709 // exact arity match, just call the function directly.
1710 desc = Linkage::GetJSCallDescriptor(graph()->zone(), false, wasm_count + 1,
1711 CallDescriptor::kNoFlags);
1712 arg_count_before_args = false;
1713 add_new_target_undefined = true;
1714 } else {
1715 // Use the Call builtin.
1716 Callable callable = CodeFactory::Call(isolate);
1717 args[pos++] = jsgraph()->HeapConstant(callable.code());
1718 desc = Linkage::GetStubCallDescriptor(isolate, graph()->zone(),
1719 callable.descriptor(), wasm_count + 1,
1720 CallDescriptor::kNoFlags);
1721 arg_count_before_args = true;
1722 }
1723
1724 args[pos++] = jsgraph()->Constant(function); // JS function.
1725 if (arg_count_before_args) {
1726 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
1727 }
1728 // JS receiver.
1729 Handle<Object> global(function->context()->global_object(), isolate);
1730 args[pos++] = jsgraph()->Constant(global);
1731
1732 // Convert WASM numbers to JS values.
1733 for (int i = 0; i < wasm_count; i++) {
1734 Node* param = graph()->NewNode(jsgraph()->common()->Parameter(i), start);
1735 args[pos++] = ToJS(param, context, sig->GetParam(i));
1736 }
1737
1738 if (add_new_target_undefined) {
1739 args[pos++] = jsgraph()->UndefinedConstant(); // new target
1740 }
1741
1742 if (!arg_count_before_args) {
1743 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
1744 }
1745 args[pos++] = context;
1746 args[pos++] = *effect_;
1747 args[pos++] = *control_;
1748
1749 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
1750
1751 // Convert the return value back.
1752 Node* val =
1753 FromJS(call, context,
1754 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
1755 Node* ret = graph()->NewNode(jsgraph()->common()->Return(), val, call, start);
1756
1757 MergeControlToEnd(jsgraph(), ret);
1758}
1759
1760
1761Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001762 DCHECK(module_ && module_->instance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001763 if (offset == 0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001764 if (!mem_buffer_) {
1765 mem_buffer_ = jsgraph()->IntPtrConstant(
1766 reinterpret_cast<uintptr_t>(module_->instance->mem_start));
1767 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001768 return mem_buffer_;
1769 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001770 return jsgraph()->IntPtrConstant(
1771 reinterpret_cast<uintptr_t>(module_->instance->mem_start + offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001772 }
1773}
1774
1775
1776Node* WasmGraphBuilder::MemSize(uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001777 DCHECK(module_ && module_->instance);
1778 uint32_t size = static_cast<uint32_t>(module_->instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001779 if (offset == 0) {
1780 if (!mem_size_) mem_size_ = jsgraph()->Int32Constant(size);
1781 return mem_size_;
1782 } else {
1783 return jsgraph()->Int32Constant(size + offset);
1784 }
1785}
1786
1787
1788Node* WasmGraphBuilder::FunctionTable() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001789 DCHECK(module_ && module_->instance &&
1790 !module_->instance->function_table.is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001791 if (!function_table_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001792 function_table_ = jsgraph()->Constant(module_->instance->function_table);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001793 }
1794 return function_table_;
1795}
1796
1797
1798Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001799 DCHECK(module_ && module_->instance && module_->instance->globals_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001800 MachineType mem_type = module_->GetGlobalType(index);
1801 Node* addr = jsgraph()->IntPtrConstant(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001802 reinterpret_cast<uintptr_t>(module_->instance->globals_start +
1803 module_->module->globals->at(index).offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001804 const Operator* op = jsgraph()->machine()->Load(mem_type);
1805 Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), *effect_,
1806 *control_);
1807 *effect_ = node;
1808 return node;
1809}
1810
1811
1812Node* WasmGraphBuilder::StoreGlobal(uint32_t index, Node* val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001813 DCHECK(module_ && module_->instance && module_->instance->globals_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001814 MachineType mem_type = module_->GetGlobalType(index);
1815 Node* addr = jsgraph()->IntPtrConstant(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001816 reinterpret_cast<uintptr_t>(module_->instance->globals_start +
1817 module_->module->globals->at(index).offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001818 const Operator* op = jsgraph()->machine()->Store(
1819 StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
1820 Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), val,
1821 *effect_, *control_);
1822 *effect_ = node;
1823 return node;
1824}
1825
1826
1827void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
1828 uint32_t offset) {
1829 // TODO(turbofan): fold bounds checks for constant indexes.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001830 DCHECK(module_ && module_->instance);
1831 size_t size = module_->instance->mem_size;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001832 byte memsize = wasm::WasmOpcodes::MemSize(memtype);
1833 Node* cond;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001834 if (offset >= size || (static_cast<uint64_t>(offset) + memsize) > size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001835 // The access will always throw.
1836 cond = jsgraph()->Int32Constant(0);
1837 } else {
1838 // Check against the limit.
1839 size_t limit = size - offset - memsize;
1840 CHECK(limit <= kMaxUInt32);
1841 cond = graph()->NewNode(
1842 jsgraph()->machine()->Uint32LessThanOrEqual(), index,
1843 jsgraph()->Int32Constant(static_cast<uint32_t>(limit)));
1844 }
1845
1846 trap_->AddTrapIfFalse(kTrapMemOutOfBounds, cond);
1847}
1848
1849
1850Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
1851 Node* index, uint32_t offset) {
1852 Node* load;
1853
1854 if (module_ && module_->asm_js) {
1855 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
1856 DCHECK_EQ(0, offset);
1857 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype);
1858 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_,
1859 *control_);
1860 } else {
1861 // WASM semantics throw on OOB. Introduce explicit bounds check.
1862 BoundsCheckMem(memtype, index, offset);
1863 load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
1864 MemBuffer(offset), index, *effect_, *control_);
1865 }
1866
1867 *effect_ = load;
1868
1869 if (type == wasm::kAstI64 &&
1870 ElementSizeLog2Of(memtype.representation()) < 3) {
1871 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes.
1872 if (memtype.IsSigned()) {
1873 // sign extend
1874 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
1875 } else {
1876 // zero extend
1877 load =
1878 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load);
1879 }
1880 }
1881
1882 return load;
1883}
1884
1885
1886Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
1887 uint32_t offset, Node* val) {
1888 Node* store;
1889 if (module_ && module_->asm_js) {
1890 // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
1891 DCHECK_EQ(0, offset);
1892 const Operator* op =
1893 jsgraph()->machine()->CheckedStore(memtype.representation());
1894 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_,
1895 *control_);
1896 } else {
1897 // WASM semantics throw on OOB. Introduce explicit bounds check.
1898 BoundsCheckMem(memtype, index, offset);
1899 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
1900 store =
1901 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
1902 index, val, *effect_, *control_);
1903 }
1904 *effect_ = store;
1905 return store;
1906}
1907
1908
1909void WasmGraphBuilder::PrintDebugName(Node* node) {
1910 PrintF("#%d:%s", node->id(), node->op()->mnemonic());
1911}
1912
1913
1914Node* WasmGraphBuilder::String(const char* string) {
1915 return jsgraph()->Constant(
1916 jsgraph()->isolate()->factory()->NewStringFromAsciiChecked(string));
1917}
1918
1919
1920Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
1921
Ben Murdoch097c5b22016-05-18 11:27:45 +01001922void WasmGraphBuilder::Int64LoweringForTesting() {
1923 if (kPointerSize == 4) {
1924 Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(),
1925 jsgraph()->common(), jsgraph()->zone(),
1926 function_signature_);
1927 r.LowerGraph();
1928 }
1929}
1930
1931static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
1932 CompilationInfo* info,
1933 const char* message, uint32_t index,
1934 const char* func_name) {
1935 Isolate* isolate = info->isolate();
1936 if (isolate->logger()->is_logging_code_events() ||
1937 isolate->cpu_profiler()->is_profiling()) {
1938 ScopedVector<char> buffer(128);
1939 SNPrintF(buffer, "%s#%d:%s", message, index, func_name);
1940 Handle<String> name_str =
1941 isolate->factory()->NewStringFromAsciiChecked(buffer.start());
1942 Handle<String> script_str =
1943 isolate->factory()->NewStringFromAsciiChecked("(WASM)");
1944 Handle<Code> code = info->code();
1945 Handle<SharedFunctionInfo> shared =
1946 isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
1947 PROFILE(isolate,
1948 CodeCreateEvent(tag, *code, *shared, info, *script_str, 0, 0));
1949 }
1950}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001951
1952Handle<JSFunction> CompileJSToWasmWrapper(
1953 Isolate* isolate, wasm::ModuleEnv* module, Handle<String> name,
1954 Handle<Code> wasm_code, Handle<JSObject> module_object, uint32_t index) {
1955 wasm::WasmFunction* func = &module->module->functions->at(index);
1956
1957 //----------------------------------------------------------------------------
1958 // Create the JSFunction object.
1959 //----------------------------------------------------------------------------
1960 Handle<SharedFunctionInfo> shared =
1961 isolate->factory()->NewSharedFunctionInfo(name, wasm_code, false);
1962 int params = static_cast<int>(func->sig->parameter_count());
1963 shared->set_length(params);
1964 shared->set_internal_formal_parameter_count(1 + params);
1965 Handle<JSFunction> function = isolate->factory()->NewFunction(
1966 isolate->wasm_function_map(), name, MaybeHandle<Code>());
1967 function->SetInternalField(0, *module_object);
1968 function->set_shared(*shared);
1969
1970 //----------------------------------------------------------------------------
1971 // Create the Graph
1972 //----------------------------------------------------------------------------
1973 Zone zone;
1974 Graph graph(&zone);
1975 CommonOperatorBuilder common(&zone);
1976 JSOperatorBuilder javascript(&zone);
1977 MachineOperatorBuilder machine(&zone);
1978 JSGraph jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine);
1979
1980 Node* control = nullptr;
1981 Node* effect = nullptr;
1982
1983 WasmGraphBuilder builder(&zone, &jsgraph, func->sig);
1984 builder.set_control_ptr(&control);
1985 builder.set_effect_ptr(&effect);
1986 builder.set_module(module);
1987 builder.BuildJSToWasmWrapper(wasm_code, func->sig);
1988
1989 //----------------------------------------------------------------------------
1990 // Run the compilation pipeline.
1991 //----------------------------------------------------------------------------
1992 {
1993 // Changes lowering requires types.
1994 Typer typer(isolate, &graph);
1995 NodeVector roots(&zone);
1996 jsgraph.GetCachedNodes(&roots);
1997 typer.Run(roots);
1998
1999 // Run generic and change lowering.
2000 JSGenericLowering generic(true, &jsgraph);
2001 ChangeLowering changes(&jsgraph);
2002 GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
2003 graph_reducer.AddReducer(&changes);
2004 graph_reducer.AddReducer(&generic);
2005 graph_reducer.ReduceGraph();
2006
2007 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
2008 OFStream os(stdout);
2009 os << "-- Graph after change lowering -- " << std::endl;
2010 os << AsRPO(graph);
2011 }
2012
2013 // Schedule and compile to machine code.
2014 int params = static_cast<int>(
2015 module->GetFunctionSignature(index)->parameter_count());
2016 CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
2017 &zone, false, params + 1, CallDescriptor::kNoFlags);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002018 // TODO(titzer): this is technically a WASM wrapper, not a wasm function.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002019 Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
2020 bool debugging =
2021#if DEBUG
2022 true;
2023#else
2024 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
2025#endif
2026 const char* func_name = "js-to-wasm";
2027
2028 static unsigned id = 0;
2029 Vector<char> buffer;
2030 if (debugging) {
2031 buffer = Vector<char>::New(128);
2032 SNPrintF(buffer, "js-to-wasm#%d", id);
2033 func_name = buffer.start();
2034 }
2035
2036 CompilationInfo info(func_name, isolate, &zone, flags);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002037 Handle<Code> code =
2038 Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002039 if (debugging) {
2040 buffer.Dispose();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002041 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002042
2043 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "js-to-wasm", index,
2044 module->module->GetName(func->name_offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002045 // Set the JSFunction's machine code.
2046 function->set_code(*code);
2047 }
2048 return function;
2049}
2050
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002051Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
2052 Handle<JSFunction> function,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002053 wasm::FunctionSig* sig, const char* name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002054 //----------------------------------------------------------------------------
2055 // Create the Graph
2056 //----------------------------------------------------------------------------
2057 Zone zone;
2058 Graph graph(&zone);
2059 CommonOperatorBuilder common(&zone);
2060 JSOperatorBuilder javascript(&zone);
2061 MachineOperatorBuilder machine(&zone);
2062 JSGraph jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine);
2063
2064 Node* control = nullptr;
2065 Node* effect = nullptr;
2066
Ben Murdoch097c5b22016-05-18 11:27:45 +01002067 WasmGraphBuilder builder(&zone, &jsgraph, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002068 builder.set_control_ptr(&control);
2069 builder.set_effect_ptr(&effect);
2070 builder.set_module(module);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002071 builder.BuildWasmToJSWrapper(function, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002072
2073 Handle<Code> code = Handle<Code>::null();
2074 {
2075 // Changes lowering requires types.
2076 Typer typer(isolate, &graph);
2077 NodeVector roots(&zone);
2078 jsgraph.GetCachedNodes(&roots);
2079 typer.Run(roots);
2080
2081 // Run generic and change lowering.
2082 JSGenericLowering generic(true, &jsgraph);
2083 ChangeLowering changes(&jsgraph);
2084 GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
2085 graph_reducer.AddReducer(&changes);
2086 graph_reducer.AddReducer(&generic);
2087 graph_reducer.ReduceGraph();
2088
2089 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
2090 OFStream os(stdout);
2091 os << "-- Graph after change lowering -- " << std::endl;
2092 os << AsRPO(graph);
2093 }
2094
2095 // Schedule and compile to machine code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002096 CallDescriptor* incoming =
2097 wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002098 // TODO(titzer): this is technically a WASM wrapper, not a wasm function.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002099 Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
2100 bool debugging =
2101#if DEBUG
2102 true;
2103#else
2104 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002105#endif
Ben Murdoch097c5b22016-05-18 11:27:45 +01002106 const char* func_name = "wasm-to-js";
2107 static unsigned id = 0;
2108 Vector<char> buffer;
2109 if (debugging) {
2110 buffer = Vector<char>::New(128);
2111 SNPrintF(buffer, "wasm-to-js#%d", id);
2112 func_name = buffer.start();
2113 }
2114
2115 CompilationInfo info(func_name, isolate, &zone, flags);
2116 code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
2117 if (debugging) {
2118 buffer.Dispose();
2119 }
2120
2121 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "wasm-to-js", 0,
2122 name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002123 }
2124 return code;
2125}
2126
2127
2128// Helper function to compile a single function.
2129Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
2130 wasm::ModuleEnv* module_env,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002131 const wasm::WasmFunction& function) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002132 if (FLAG_trace_wasm_compiler || FLAG_trace_wasm_decode_time) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002133 OFStream os(stdout);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002134 os << "Compiling WASM function "
2135 << wasm::WasmFunctionName(&function, module_env) << std::endl;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002136 os << std::endl;
2137 }
2138 // Initialize the function environment for decoding.
2139 wasm::FunctionEnv env;
2140 env.module = module_env;
2141 env.sig = function.sig;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002142 env.local_i32_count = function.local_i32_count;
2143 env.local_i64_count = function.local_i64_count;
2144 env.local_f32_count = function.local_f32_count;
2145 env.local_f64_count = function.local_f64_count;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002146 env.SumLocals();
2147
2148 // Create a TF graph during decoding.
2149 Zone zone;
2150 Graph graph(&zone);
2151 CommonOperatorBuilder common(&zone);
2152 MachineOperatorBuilder machine(
2153 &zone, MachineType::PointerRepresentation(),
2154 InstructionSelector::SupportedMachineOperatorFlags());
2155 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
2156 WasmGraphBuilder builder(&zone, &jsgraph, function.sig);
2157 wasm::TreeResult result = wasm::BuildTFGraph(
2158 &builder, &env, // --
2159 module_env->module->module_start, // --
2160 module_env->module->module_start + function.code_start_offset, // --
2161 module_env->module->module_start + function.code_end_offset); // --
2162
2163 if (result.failed()) {
2164 if (FLAG_trace_wasm_compiler) {
2165 OFStream os(stdout);
2166 os << "Compilation failed: " << result << std::endl;
2167 }
2168 // Add the function as another context for the exception
Ben Murdoch097c5b22016-05-18 11:27:45 +01002169 ScopedVector<char> buffer(128);
2170 SNPrintF(buffer, "Compiling WASM function #%d:%s failed:",
2171 function.func_index,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002172 module_env->module->GetName(function.name_offset));
2173 thrower.Failed(buffer.start(), result);
2174 return Handle<Code>::null();
2175 }
2176
2177 // Run the compiler pipeline to generate machine code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002178 CallDescriptor* descriptor =
2179 wasm::ModuleEnv::GetWasmCallDescriptor(&zone, function.sig);
2180 if (kPointerSize == 4) {
2181 descriptor = module_env->GetI32WasmCallDescriptor(&zone, descriptor);
2182 }
2183 Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
2184 // add flags here if a meaningful name is helpful for debugging.
2185 bool debugging =
2186#if DEBUG
2187 true;
2188#else
2189 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
2190#endif
2191 const char* func_name = "wasm";
2192 Vector<char> buffer;
2193 if (debugging) {
2194 buffer = Vector<char>::New(128);
2195 SNPrintF(buffer, "WASM_function_#%d:%s", function.func_index,
2196 module_env->module->GetName(function.name_offset));
2197 func_name = buffer.start();
2198 }
2199 CompilationInfo info(func_name, isolate, &zone, flags);
2200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002201 Handle<Code> code =
2202 Pipeline::GenerateCodeForTesting(&info, descriptor, &graph);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002203 if (debugging) {
2204 buffer.Dispose();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002205 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002206 if (!code.is_null()) {
2207 RecordFunctionCompilation(
2208 Logger::FUNCTION_TAG, &info, "WASM_function", function.func_index,
2209 module_env->module->GetName(function.name_offset));
2210 }
2211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002212 return code;
2213}
2214
2215
2216} // namespace compiler
2217} // namespace internal
2218} // namespace v8