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