Line data Source code
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/optional.h"
11 : #include "src/base/platform/elapsed-timer.h"
12 : #include "src/base/platform/platform.h"
13 : #include "src/builtins/builtins.h"
14 : #include "src/code-factory.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-inl.h"
38 : #include "src/wasm/wasm-opcodes.h"
39 : #include "src/wasm/wasm-text.h"
40 :
41 : namespace v8 {
42 : namespace internal {
43 : namespace compiler {
44 :
45 : // TODO(titzer): pull WASM_64 up to a common header.
46 : #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
47 : #define WASM_64 1
48 : #else
49 : #define WASM_64 0
50 : #endif
51 :
52 : #define FATAL_UNSUPPORTED_OPCODE(opcode) \
53 : V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", (opcode), \
54 : wasm::WasmOpcodes::OpcodeName(opcode));
55 :
56 : namespace {
57 :
58 : constexpr uint32_t kBytesPerExceptionValuesArrayElement = 2;
59 :
60 1481654 : void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
61 740827 : Graph* g = jsgraph->graph();
62 740827 : if (g->end()) {
63 200525 : NodeProperties::MergeControlToEnd(g, jsgraph->common(), node);
64 : } else {
65 540302 : g->SetEnd(g->NewNode(jsgraph->common()->End(1), node));
66 : }
67 740908 : }
68 :
69 : } // namespace
70 :
71 545199 : WasmGraphBuilder::WasmGraphBuilder(
72 : ModuleEnv* env, Zone* zone, JSGraph* jsgraph, Handle<Code> centry_stub,
73 1913251 : wasm::FunctionSig* sig,
74 : compiler::SourcePositionTable* source_position_table,
75 : RuntimeExceptionSupport exception_support)
76 : : zone_(zone),
77 : jsgraph_(jsgraph),
78 1090368 : centry_stub_node_(jsgraph_->HeapConstant(centry_stub)),
79 : env_(env),
80 : signature_tables_(zone),
81 : function_tables_(zone),
82 : function_table_sizes_(zone),
83 : cur_buffer_(def_buffer_),
84 : cur_bufsize_(kDefaultBufferSize),
85 : runtime_exception_support_(exception_support),
86 : sig_(sig),
87 2725875 : source_position_table_(source_position_table) {
88 1662560 : for (size_t i = sig->parameter_count(); i > 0 && !has_simd_; --i) {
89 1144444 : if (sig->GetParam(i - 1) == wasm::kWasmS128) has_simd_ = true;
90 : }
91 1341029 : for (size_t i = sig->return_count(); i > 0 && !has_simd_; --i) {
92 501382 : if (sig->GetReturn(i - 1) == wasm::kWasmS128) has_simd_ = true;
93 : }
94 : DCHECK_NOT_NULL(jsgraph_);
95 545169 : }
96 :
97 0 : Node* WasmGraphBuilder::Error() { return jsgraph()->Dead(); }
98 :
99 1090418 : Node* WasmGraphBuilder::Start(unsigned params) {
100 1090418 : Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
101 : graph()->SetStart(start);
102 545223 : return start;
103 : }
104 :
105 805567 : Node* WasmGraphBuilder::Param(unsigned index) {
106 : return graph()->NewNode(jsgraph()->common()->Parameter(index),
107 1611120 : graph()->start());
108 : }
109 :
110 11622 : Node* WasmGraphBuilder::Loop(Node* entry) {
111 23243 : return graph()->NewNode(jsgraph()->common()->Loop(1), entry);
112 : }
113 :
114 23248 : Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
115 : Node* terminate =
116 11624 : graph()->NewNode(jsgraph()->common()->Terminate(), effect, control);
117 11624 : MergeControlToEnd(jsgraph(), terminate);
118 11624 : return terminate;
119 : }
120 :
121 16797 : unsigned WasmGraphBuilder::InputCount(Node* node) {
122 16797 : return static_cast<unsigned>(node->InputCount());
123 : }
124 :
125 3094031 : bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
126 3380892 : return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
127 1833875 : NodeProperties::GetControlInput(phi) == merge;
128 : }
129 :
130 190 : bool WasmGraphBuilder::ThrowsException(Node* node, Node** if_success,
131 180 : Node** if_exception) {
132 190 : if (node->op()->HasProperty(compiler::Operator::kNoThrow)) {
133 : return false;
134 : }
135 :
136 180 : *if_success = graph()->NewNode(jsgraph()->common()->IfSuccess(), node);
137 : *if_exception =
138 180 : graph()->NewNode(jsgraph()->common()->IfException(), node, node);
139 :
140 90 : return true;
141 : }
142 :
143 539119 : void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) {
144 : DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
145 269558 : merge->AppendInput(jsgraph()->zone(), from);
146 : int new_size = merge->InputCount();
147 : NodeProperties::ChangeOp(
148 269561 : merge, jsgraph()->common()->ResizeMergeOrPhi(merge->op(), new_size));
149 269558 : }
150 :
151 433069 : void WasmGraphBuilder::AppendToPhi(Node* phi, Node* from) {
152 : DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
153 : int new_size = phi->InputCount();
154 288712 : phi->InsertInput(jsgraph()->zone(), phi->InputCount() - 1, from);
155 : NodeProperties::ChangeOp(
156 144357 : phi, jsgraph()->common()->ResizeMergeOrPhi(phi->op(), new_size));
157 144357 : }
158 :
159 103194 : Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
160 154796 : return graph()->NewNode(jsgraph()->common()->Merge(count), count, controls);
161 : }
162 :
163 191508 : Node* WasmGraphBuilder::Phi(wasm::ValueType type, unsigned count, Node** vals,
164 191507 : Node* control) {
165 : DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
166 191508 : Node** buf = Realloc(vals, count, count + 1);
167 191507 : buf[count] = control;
168 : return graph()->NewNode(jsgraph()->common()->Phi(type, count), count + 1,
169 574521 : buf);
170 : }
171 :
172 39885 : Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
173 39888 : Node* control) {
174 : DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
175 39885 : Node** buf = Realloc(effects, count, count + 1);
176 39888 : buf[count] = control;
177 : return graph()->NewNode(jsgraph()->common()->EffectPhi(count), count + 1,
178 119660 : buf);
179 : }
180 :
181 0 : Node* WasmGraphBuilder::NumberConstant(int32_t value) {
182 0 : return jsgraph()->Constant(value);
183 : }
184 :
185 3760 : Node* WasmGraphBuilder::Uint32Constant(uint32_t value) {
186 0 : return jsgraph()->Uint32Constant(value);
187 : }
188 :
189 1116270 : Node* WasmGraphBuilder::Int32Constant(int32_t value) {
190 1116410 : return jsgraph()->Int32Constant(value);
191 : }
192 :
193 46831 : Node* WasmGraphBuilder::Int64Constant(int64_t value) {
194 46831 : return jsgraph()->Int64Constant(value);
195 : }
196 :
197 0 : Node* WasmGraphBuilder::IntPtrConstant(intptr_t value) {
198 0 : return jsgraph()->IntPtrConstant(value);
199 : }
200 :
201 162469 : void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
202 2029011 : Node** effect, Node** control) {
203 : // TODO(mtrofin): "!env_" happens when we generate a wrapper.
204 : // We should factor wrappers separately from wasm codegen.
205 162469 : if (FLAG_wasm_no_stack_checks || !env_ || !runtime_exception_support_) {
206 6396 : return;
207 : }
208 156073 : if (effect == nullptr) effect = effect_;
209 156073 : if (control == nullptr) control = control_;
210 :
211 : Node* limit = graph()->NewNode(
212 : jsgraph()->machine()->Load(MachineType::Pointer()),
213 : jsgraph()->ExternalConstant(
214 : ExternalReference::address_of_stack_limit(jsgraph()->isolate())),
215 780357 : jsgraph()->IntPtrConstant(0), *effect, *control);
216 156091 : *effect = limit;
217 156091 : Node* pointer = graph()->NewNode(jsgraph()->machine()->LoadStackPointer());
218 :
219 : Node* check =
220 156088 : graph()->NewNode(jsgraph()->machine()->UintLessThan(), limit, pointer);
221 :
222 312160 : Diamond stack_check(graph(), jsgraph()->common(), check, BranchHint::kTrue);
223 156079 : stack_check.Chain(*control);
224 :
225 156075 : Handle<Code> code = BUILTIN_CODE(jsgraph()->isolate(), WasmStackGuard);
226 : CallInterfaceDescriptor idesc =
227 312148 : WasmRuntimeCallDescriptor(jsgraph()->isolate());
228 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
229 : jsgraph()->isolate(), jsgraph()->zone(), idesc, 0,
230 : CallDescriptor::kNoFlags, Operator::kNoProperties,
231 156086 : MachineType::AnyTagged(), 1, Linkage::kNoContext);
232 156065 : Node* stub_code = jsgraph()->HeapConstant(code);
233 :
234 : Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
235 312174 : *effect, stack_check.if_false);
236 :
237 156087 : SetSourcePosition(call, position);
238 :
239 : Node* ephi = graph()->NewNode(jsgraph()->common()->EffectPhi(2), *effect,
240 312186 : call, stack_check.merge);
241 :
242 156089 : *control = stack_check.merge;
243 156089 : *effect = ephi;
244 : }
245 :
246 228445 : void WasmGraphBuilder::PatchInStackCheckIfNeeded() {
247 312063 : if (!needs_stack_check_) return;
248 :
249 150796 : Node* start = graph()->start();
250 : // Place a stack check which uses a dummy node as control and effect.
251 150796 : Node* dummy = graph()->NewNode(jsgraph()->common()->Dead());
252 150857 : Node* control = dummy;
253 150857 : Node* effect = dummy;
254 : // The function-prologue stack check is associated with position 0, which
255 : // is never a position of any instruction in the function.
256 150857 : StackCheck(0, &effect, &control);
257 :
258 : // In testing, no steck checks were emitted. Nothing to rewire then.
259 150861 : if (effect == dummy) return;
260 :
261 : // Now patch all control uses of {start} to use {control} and all effect uses
262 : // to use {effect} instead. Then rewire the dummy node to use start instead.
263 144892 : NodeProperties::ReplaceUses(start, start, effect, control);
264 144891 : NodeProperties::ReplaceUses(dummy, nullptr, start, start);
265 : }
266 :
267 992565 : Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
268 992565 : wasm::WasmCodePosition position) {
269 : const Operator* op;
270 992565 : MachineOperatorBuilder* m = jsgraph()->machine();
271 992565 : switch (opcode) {
272 : case wasm::kExprI32Add:
273 446462 : op = m->Int32Add();
274 446462 : break;
275 : case wasm::kExprI32Sub:
276 17054 : op = m->Int32Sub();
277 17051 : break;
278 : case wasm::kExprI32Mul:
279 5372 : op = m->Int32Mul();
280 5372 : break;
281 : case wasm::kExprI32DivS:
282 338 : return BuildI32DivS(left, right, position);
283 : case wasm::kExprI32DivU:
284 222 : return BuildI32DivU(left, right, position);
285 : case wasm::kExprI32RemS:
286 156 : return BuildI32RemS(left, right, position);
287 : case wasm::kExprI32RemU:
288 142 : return BuildI32RemU(left, right, position);
289 : case wasm::kExprI32And:
290 141523 : op = m->Word32And();
291 141523 : break;
292 : case wasm::kExprI32Ior:
293 7537 : op = m->Word32Or();
294 7537 : break;
295 : case wasm::kExprI32Xor:
296 1284 : op = m->Word32Xor();
297 1284 : break;
298 : case wasm::kExprI32Shl:
299 16006 : op = m->Word32Shl();
300 16006 : right = MaskShiftCount32(right);
301 16006 : break;
302 : case wasm::kExprI32ShrU:
303 21294 : op = m->Word32Shr();
304 21294 : right = MaskShiftCount32(right);
305 21294 : break;
306 : case wasm::kExprI32ShrS:
307 2177 : op = m->Word32Sar();
308 2177 : right = MaskShiftCount32(right);
309 2177 : break;
310 : case wasm::kExprI32Ror:
311 128 : op = m->Word32Ror();
312 128 : right = MaskShiftCount32(right);
313 128 : break;
314 : case wasm::kExprI32Rol:
315 64 : right = MaskShiftCount32(right);
316 64 : return BuildI32Rol(left, right);
317 : case wasm::kExprI32Eq:
318 155622 : op = m->Word32Equal();
319 155622 : break;
320 : case wasm::kExprI32Ne:
321 21559 : return Invert(Binop(wasm::kExprI32Eq, left, right));
322 : case wasm::kExprI32LtS:
323 2698 : op = m->Int32LessThan();
324 2698 : break;
325 : case wasm::kExprI32LeS:
326 1179 : op = m->Int32LessThanOrEqual();
327 1179 : break;
328 : case wasm::kExprI32LtU:
329 6051 : op = m->Uint32LessThan();
330 6051 : break;
331 : case wasm::kExprI32LeU:
332 176 : op = m->Uint32LessThanOrEqual();
333 176 : break;
334 : case wasm::kExprI32GtS:
335 3036 : op = m->Int32LessThan();
336 : std::swap(left, right);
337 : break;
338 : case wasm::kExprI32GeS:
339 830 : op = m->Int32LessThanOrEqual();
340 : std::swap(left, right);
341 : break;
342 : case wasm::kExprI32GtU:
343 2384 : op = m->Uint32LessThan();
344 : std::swap(left, right);
345 : break;
346 : case wasm::kExprI32GeU:
347 212 : op = m->Uint32LessThanOrEqual();
348 : std::swap(left, right);
349 : break;
350 : case wasm::kExprI64And:
351 9730 : op = m->Word64And();
352 9730 : break;
353 : case wasm::kExprI64Add:
354 208 : op = m->Int64Add();
355 208 : break;
356 : case wasm::kExprI64Sub:
357 389 : op = m->Int64Sub();
358 389 : break;
359 : case wasm::kExprI64Mul:
360 359 : op = m->Int64Mul();
361 359 : break;
362 : case wasm::kExprI64DivS:
363 306 : return BuildI64DivS(left, right, position);
364 : case wasm::kExprI64DivU:
365 154 : return BuildI64DivU(left, right, position);
366 : case wasm::kExprI64RemS:
367 134 : return BuildI64RemS(left, right, position);
368 : case wasm::kExprI64RemU:
369 134 : return BuildI64RemU(left, right, position);
370 : case wasm::kExprI64Ior:
371 178 : op = m->Word64Or();
372 178 : break;
373 : case wasm::kExprI64Xor:
374 134 : op = m->Word64Xor();
375 134 : break;
376 : case wasm::kExprI64Shl:
377 314 : op = m->Word64Shl();
378 313 : right = MaskShiftCount64(right);
379 314 : break;
380 : case wasm::kExprI64ShrU:
381 332 : op = m->Word64Shr();
382 332 : right = MaskShiftCount64(right);
383 332 : break;
384 : case wasm::kExprI64ShrS:
385 142 : op = m->Word64Sar();
386 142 : right = MaskShiftCount64(right);
387 142 : break;
388 : case wasm::kExprI64Eq:
389 41411 : op = m->Word64Equal();
390 41411 : break;
391 : case wasm::kExprI64Ne:
392 62 : return Invert(Binop(wasm::kExprI64Eq, left, right));
393 : case wasm::kExprI64LtS:
394 92 : op = m->Int64LessThan();
395 92 : break;
396 : case wasm::kExprI64LeS:
397 62 : op = m->Int64LessThanOrEqual();
398 62 : break;
399 : case wasm::kExprI64LtU:
400 72 : op = m->Uint64LessThan();
401 72 : break;
402 : case wasm::kExprI64LeU:
403 82 : op = m->Uint64LessThanOrEqual();
404 82 : break;
405 : case wasm::kExprI64GtS:
406 72 : op = m->Int64LessThan();
407 : std::swap(left, right);
408 : break;
409 : case wasm::kExprI64GeS:
410 62 : op = m->Int64LessThanOrEqual();
411 : std::swap(left, right);
412 : break;
413 : case wasm::kExprI64GtU:
414 72 : op = m->Uint64LessThan();
415 : std::swap(left, right);
416 : break;
417 : case wasm::kExprI64GeU:
418 62 : op = m->Uint64LessThanOrEqual();
419 : std::swap(left, right);
420 : break;
421 : case wasm::kExprI64Ror:
422 152 : op = m->Word64Ror();
423 152 : right = MaskShiftCount64(right);
424 152 : break;
425 : case wasm::kExprI64Rol:
426 76 : return BuildI64Rol(left, right);
427 : case wasm::kExprF32CopySign:
428 54 : return BuildF32CopySign(left, right);
429 : case wasm::kExprF64CopySign:
430 54 : return BuildF64CopySign(left, right);
431 : case wasm::kExprF32Add:
432 625 : op = m->Float32Add();
433 625 : break;
434 : case wasm::kExprF32Sub:
435 461 : op = m->Float32Sub();
436 461 : break;
437 : case wasm::kExprF32Mul:
438 577 : op = m->Float32Mul();
439 577 : break;
440 : case wasm::kExprF32Div:
441 508 : op = m->Float32Div();
442 509 : break;
443 : case wasm::kExprF32Eq:
444 580 : op = m->Float32Equal();
445 577 : break;
446 : case wasm::kExprF32Ne:
447 450 : return Invert(Binop(wasm::kExprF32Eq, left, right));
448 : case wasm::kExprF32Lt:
449 167 : op = m->Float32LessThan();
450 167 : break;
451 : case wasm::kExprF32Ge:
452 147 : op = m->Float32LessThanOrEqual();
453 : std::swap(left, right);
454 : break;
455 : case wasm::kExprF32Gt:
456 177 : op = m->Float32LessThan();
457 : std::swap(left, right);
458 : break;
459 : case wasm::kExprF32Le:
460 157 : op = m->Float32LessThanOrEqual();
461 157 : break;
462 : case wasm::kExprF64Add:
463 5801 : op = m->Float64Add();
464 5800 : break;
465 : case wasm::kExprF64Sub:
466 4095 : op = m->Float64Sub();
467 4095 : break;
468 : case wasm::kExprF64Mul:
469 9022 : op = m->Float64Mul();
470 9022 : break;
471 : case wasm::kExprF64Div:
472 984 : op = m->Float64Div();
473 984 : break;
474 : case wasm::kExprF64Eq:
475 1067 : op = m->Float64Equal();
476 1067 : break;
477 : case wasm::kExprF64Ne:
478 621 : return Invert(Binop(wasm::kExprF64Eq, left, right));
479 : case wasm::kExprF64Lt:
480 1007 : op = m->Float64LessThan();
481 1007 : break;
482 : case wasm::kExprF64Le:
483 400 : op = m->Float64LessThanOrEqual();
484 400 : break;
485 : case wasm::kExprF64Gt:
486 973 : op = m->Float64LessThan();
487 : std::swap(left, right);
488 : break;
489 : case wasm::kExprF64Ge:
490 428 : op = m->Float64LessThanOrEqual();
491 : std::swap(left, right);
492 : break;
493 : case wasm::kExprF32Min:
494 72 : op = m->Float32Min();
495 72 : break;
496 : case wasm::kExprF64Min:
497 66 : op = m->Float64Min();
498 66 : break;
499 : case wasm::kExprF32Max:
500 72 : op = m->Float32Max();
501 72 : break;
502 : case wasm::kExprF64Max:
503 66 : op = m->Float64Max();
504 66 : break;
505 : case wasm::kExprF64Pow:
506 13 : return BuildF64Pow(left, right);
507 : case wasm::kExprF64Atan2:
508 13 : op = m->Float64Atan2();
509 13 : break;
510 : case wasm::kExprF64Mod:
511 30 : return BuildF64Mod(left, right);
512 : case wasm::kExprI32AsmjsDivS:
513 524 : return BuildI32AsmjsDivS(left, right);
514 : case wasm::kExprI32AsmjsDivU:
515 191 : return BuildI32AsmjsDivU(left, right);
516 : case wasm::kExprI32AsmjsRemS:
517 608 : return BuildI32AsmjsRemS(left, right);
518 : case wasm::kExprI32AsmjsRemU:
519 260 : return BuildI32AsmjsRemU(left, right);
520 : case wasm::kExprI32AsmjsStoreMem8:
521 4069 : return BuildAsmjsStoreMem(MachineType::Int8(), left, right);
522 : case wasm::kExprI32AsmjsStoreMem16:
523 1891 : return BuildAsmjsStoreMem(MachineType::Int16(), left, right);
524 : case wasm::kExprI32AsmjsStoreMem:
525 42528 : return BuildAsmjsStoreMem(MachineType::Int32(), left, right);
526 : case wasm::kExprF32AsmjsStoreMem:
527 4615 : return BuildAsmjsStoreMem(MachineType::Float32(), left, right);
528 : case wasm::kExprF64AsmjsStoreMem:
529 895 : return BuildAsmjsStoreMem(MachineType::Float64(), left, right);
530 : default:
531 0 : FATAL_UNSUPPORTED_OPCODE(opcode);
532 : }
533 912386 : return graph()->NewNode(op, left, right);
534 : }
535 :
536 391578 : Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input,
537 556245 : wasm::WasmCodePosition position) {
538 : const Operator* op;
539 391578 : MachineOperatorBuilder* m = jsgraph()->machine();
540 391578 : switch (opcode) {
541 : case wasm::kExprI32Eqz:
542 164455 : op = m->Word32Equal();
543 328918 : return graph()->NewNode(op, input, jsgraph()->Int32Constant(0));
544 : case wasm::kExprF32Abs:
545 86 : op = m->Float32Abs();
546 86 : break;
547 : case wasm::kExprF32Neg: {
548 288 : op = m->Float32Neg();
549 288 : break;
550 : }
551 : case wasm::kExprF32Sqrt:
552 202 : op = m->Float32Sqrt();
553 202 : break;
554 : case wasm::kExprF64Abs:
555 120 : op = m->Float64Abs();
556 120 : break;
557 : case wasm::kExprF64Neg: {
558 1455 : op = m->Float64Neg();
559 1455 : break;
560 : }
561 : case wasm::kExprF64Sqrt:
562 320 : op = m->Float64Sqrt();
563 320 : break;
564 : case wasm::kExprI32SConvertF64:
565 262 : return BuildI32SConvertF64(input, position);
566 : case wasm::kExprI32UConvertF64:
567 58 : return BuildI32UConvertF64(input, position);
568 : case wasm::kExprI32AsmjsSConvertF64:
569 130 : return BuildI32AsmjsSConvertF64(input);
570 : case wasm::kExprI32AsmjsUConvertF64:
571 12 : return BuildI32AsmjsUConvertF64(input);
572 : case wasm::kExprF32ConvertF64:
573 4839 : op = m->TruncateFloat64ToFloat32();
574 4838 : break;
575 : case wasm::kExprF64SConvertI32:
576 875 : op = m->ChangeInt32ToFloat64();
577 875 : break;
578 : case wasm::kExprF64UConvertI32:
579 399 : op = m->ChangeUint32ToFloat64();
580 399 : break;
581 : case wasm::kExprF32SConvertI32:
582 394 : op = m->RoundInt32ToFloat32();
583 394 : break;
584 : case wasm::kExprF32UConvertI32:
585 130 : op = m->RoundUint32ToFloat32();
586 130 : break;
587 : case wasm::kExprI32SConvertF32:
588 272 : return BuildI32SConvertF32(input, position);
589 : case wasm::kExprI32UConvertF32:
590 68 : return BuildI32UConvertF32(input, position);
591 : case wasm::kExprI32AsmjsSConvertF32:
592 12 : return BuildI32AsmjsSConvertF32(input);
593 : case wasm::kExprI32AsmjsUConvertF32:
594 12 : return BuildI32AsmjsUConvertF32(input);
595 : case wasm::kExprF64ConvertF32:
596 7789 : op = m->ChangeFloat32ToFloat64();
597 7789 : break;
598 : case wasm::kExprF32ReinterpretI32:
599 236 : op = m->BitcastInt32ToFloat32();
600 236 : break;
601 : case wasm::kExprI32ReinterpretF32:
602 62798 : op = m->BitcastFloat32ToInt32();
603 62798 : break;
604 : case wasm::kExprI32Clz:
605 1890 : op = m->Word32Clz();
606 1890 : break;
607 : case wasm::kExprI32Ctz: {
608 858 : if (m->Word32Ctz().IsSupported()) {
609 858 : op = m->Word32Ctz().op();
610 858 : break;
611 0 : } else if (m->Word32ReverseBits().IsSupported()) {
612 0 : Node* reversed = graph()->NewNode(m->Word32ReverseBits().op(), input);
613 0 : Node* result = graph()->NewNode(m->Word32Clz(), reversed);
614 0 : return result;
615 : } else {
616 0 : return BuildI32Ctz(input);
617 : }
618 : }
619 : case wasm::kExprI32Popcnt: {
620 158 : if (m->Word32Popcnt().IsSupported()) {
621 158 : op = m->Word32Popcnt().op();
622 158 : break;
623 : } else {
624 0 : return BuildI32Popcnt(input);
625 : }
626 : }
627 : case wasm::kExprF32Floor: {
628 57 : if (!m->Float32RoundDown().IsSupported()) return BuildF32Floor(input);
629 57 : op = m->Float32RoundDown().op();
630 57 : break;
631 : }
632 : case wasm::kExprF32Ceil: {
633 57 : if (!m->Float32RoundUp().IsSupported()) return BuildF32Ceil(input);
634 57 : op = m->Float32RoundUp().op();
635 57 : break;
636 : }
637 : case wasm::kExprF32Trunc: {
638 376 : if (!m->Float32RoundTruncate().IsSupported()) return BuildF32Trunc(input);
639 375 : op = m->Float32RoundTruncate().op();
640 375 : break;
641 : }
642 : case wasm::kExprF32NearestInt: {
643 38 : if (!m->Float32RoundTiesEven().IsSupported())
644 0 : return BuildF32NearestInt(input);
645 38 : op = m->Float32RoundTiesEven().op();
646 38 : break;
647 : }
648 : case wasm::kExprF64Floor: {
649 107 : if (!m->Float64RoundDown().IsSupported()) return BuildF64Floor(input);
650 107 : op = m->Float64RoundDown().op();
651 107 : break;
652 : }
653 : case wasm::kExprF64Ceil: {
654 69 : if (!m->Float64RoundUp().IsSupported()) return BuildF64Ceil(input);
655 69 : op = m->Float64RoundUp().op();
656 69 : break;
657 : }
658 : case wasm::kExprF64Trunc: {
659 357 : if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input);
660 356 : op = m->Float64RoundTruncate().op();
661 357 : break;
662 : }
663 : case wasm::kExprF64NearestInt: {
664 38 : if (!m->Float64RoundTiesEven().IsSupported())
665 0 : return BuildF64NearestInt(input);
666 38 : op = m->Float64RoundTiesEven().op();
667 38 : break;
668 : }
669 : case wasm::kExprF64Acos: {
670 19 : return BuildF64Acos(input);
671 : }
672 : case wasm::kExprF64Asin: {
673 19 : return BuildF64Asin(input);
674 : }
675 : case wasm::kExprF64Atan:
676 19 : op = m->Float64Atan();
677 19 : break;
678 : case wasm::kExprF64Cos: {
679 194 : op = m->Float64Cos();
680 194 : break;
681 : }
682 : case wasm::kExprF64Sin: {
683 194 : op = m->Float64Sin();
684 194 : break;
685 : }
686 : case wasm::kExprF64Tan: {
687 19 : op = m->Float64Tan();
688 19 : break;
689 : }
690 : case wasm::kExprF64Exp: {
691 19 : op = m->Float64Exp();
692 19 : break;
693 : }
694 : case wasm::kExprF64Log:
695 19 : op = m->Float64Log();
696 19 : break;
697 : case wasm::kExprI32ConvertI64:
698 1770 : op = m->TruncateInt64ToInt32();
699 1770 : break;
700 : case wasm::kExprI64SConvertI32:
701 90 : op = m->ChangeInt32ToInt64();
702 90 : break;
703 : case wasm::kExprI64UConvertI32:
704 172 : op = m->ChangeUint32ToUint64();
705 172 : break;
706 : case wasm::kExprF64ReinterpretI64:
707 292 : op = m->BitcastInt64ToFloat64();
708 292 : break;
709 : case wasm::kExprI64ReinterpretF64:
710 62404 : op = m->BitcastFloat64ToInt64();
711 62404 : break;
712 : case wasm::kExprI64Clz:
713 38 : op = m->Word64Clz();
714 38 : break;
715 : case wasm::kExprI64Ctz: {
716 188 : OptionalOperator ctz64 = m->Word64Ctz();
717 188 : if (ctz64.IsSupported()) {
718 : op = ctz64.op();
719 188 : break;
720 0 : } else if (m->Is32() && m->Word32Ctz().IsSupported()) {
721 : op = ctz64.placeholder();
722 : break;
723 0 : } else if (m->Word64ReverseBits().IsSupported()) {
724 0 : Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input);
725 0 : Node* result = graph()->NewNode(m->Word64Clz(), reversed);
726 0 : return result;
727 : } else {
728 0 : return BuildI64Ctz(input);
729 : }
730 : }
731 : case wasm::kExprI64Popcnt: {
732 50 : OptionalOperator popcnt64 = m->Word64Popcnt();
733 50 : if (popcnt64.IsSupported()) {
734 : op = popcnt64.op();
735 0 : } else if (m->Is32() && m->Word32Popcnt().IsSupported()) {
736 : op = popcnt64.placeholder();
737 : } else {
738 0 : return BuildI64Popcnt(input);
739 : }
740 50 : break;
741 : }
742 : case wasm::kExprI64Eqz:
743 212 : op = m->Word64Equal();
744 424 : return graph()->NewNode(op, input, jsgraph()->Int64Constant(0));
745 : case wasm::kExprF32SConvertI64:
746 88 : if (m->Is32()) {
747 0 : return BuildF32SConvertI64(input);
748 : }
749 88 : op = m->RoundInt64ToFloat32();
750 88 : break;
751 : case wasm::kExprF32UConvertI64:
752 47 : if (m->Is32()) {
753 0 : return BuildF32UConvertI64(input);
754 : }
755 47 : op = m->RoundUint64ToFloat32();
756 47 : break;
757 : case wasm::kExprF64SConvertI64:
758 114 : if (m->Is32()) {
759 0 : return BuildF64SConvertI64(input);
760 : }
761 114 : op = m->RoundInt64ToFloat64();
762 114 : break;
763 : case wasm::kExprF64UConvertI64:
764 177 : if (m->Is32()) {
765 0 : return BuildF64UConvertI64(input);
766 : }
767 177 : op = m->RoundUint64ToFloat64();
768 175 : break;
769 : case wasm::kExprI64SConvertF32:
770 70 : return BuildI64SConvertF32(input, position);
771 : case wasm::kExprI64SConvertF64:
772 122 : return BuildI64SConvertF64(input, position);
773 : case wasm::kExprI64UConvertF32:
774 70 : return BuildI64UConvertF32(input, position);
775 : case wasm::kExprI64UConvertF64:
776 80 : return BuildI64UConvertF64(input, position);
777 : case wasm::kExprI32AsmjsLoadMem8S:
778 3770 : return BuildAsmjsLoadMem(MachineType::Int8(), input);
779 : case wasm::kExprI32AsmjsLoadMem8U:
780 2836 : return BuildAsmjsLoadMem(MachineType::Uint8(), input);
781 : case wasm::kExprI32AsmjsLoadMem16S:
782 1270 : return BuildAsmjsLoadMem(MachineType::Int16(), input);
783 : case wasm::kExprI32AsmjsLoadMem16U:
784 717 : return BuildAsmjsLoadMem(MachineType::Uint16(), input);
785 : case wasm::kExprI32AsmjsLoadMem:
786 58745 : return BuildAsmjsLoadMem(MachineType::Int32(), input);
787 : case wasm::kExprF32AsmjsLoadMem:
788 7558 : return BuildAsmjsLoadMem(MachineType::Float32(), input);
789 : case wasm::kExprF64AsmjsLoadMem:
790 979 : return BuildAsmjsLoadMem(MachineType::Float64(), input);
791 : default:
792 0 : FATAL_UNSUPPORTED_OPCODE(opcode);
793 : }
794 149820 : return graph()->NewNode(op, input);
795 : }
796 :
797 147351 : Node* WasmGraphBuilder::Float32Constant(float value) {
798 147351 : return jsgraph()->Float32Constant(value);
799 : }
800 :
801 159314 : Node* WasmGraphBuilder::Float64Constant(double value) {
802 159314 : return jsgraph()->Float64Constant(value);
803 : }
804 :
805 332693 : Node* WasmGraphBuilder::HeapConstant(Handle<HeapObject> value) {
806 332693 : return jsgraph()->HeapConstant(value);
807 : }
808 :
809 : namespace {
810 1359971 : Node* Branch(JSGraph* jsgraph, Node* cond, Node** true_node, Node** false_node,
811 : Node* control, BranchHint hint) {
812 : DCHECK_NOT_NULL(cond);
813 : DCHECK_NOT_NULL(control);
814 : Node* branch =
815 226659 : jsgraph->graph()->NewNode(jsgraph->common()->Branch(hint), cond, control);
816 453324 : *true_node = jsgraph->graph()->NewNode(jsgraph->common()->IfTrue(), branch);
817 453327 : *false_node = jsgraph->graph()->NewNode(jsgraph->common()->IfFalse(), branch);
818 226664 : return branch;
819 : }
820 : } // namespace
821 :
822 226012 : Node* WasmGraphBuilder::BranchNoHint(Node* cond, Node** true_node,
823 226012 : Node** false_node) {
824 : return Branch(jsgraph(), cond, true_node, false_node, *control_,
825 452024 : BranchHint::kNone);
826 : }
827 :
828 0 : Node* WasmGraphBuilder::BranchExpectTrue(Node* cond, Node** true_node,
829 0 : Node** false_node) {
830 : return Branch(jsgraph(), cond, true_node, false_node, *control_,
831 0 : BranchHint::kTrue);
832 : }
833 :
834 0 : Node* WasmGraphBuilder::BranchExpectFalse(Node* cond, Node** true_node,
835 644 : Node** false_node) {
836 : return Branch(jsgraph(), cond, true_node, false_node, *control_,
837 1288 : BranchHint::kFalse);
838 : }
839 :
840 198441 : Builtins::Name WasmGraphBuilder::GetBuiltinIdForTrap(wasm::TrapReason reason) {
841 198441 : if (runtime_exception_support_ == kNoRuntimeExceptionSupport) {
842 : // We use Builtins::builtin_count as a marker to tell the code generator
843 : // to generate a call to a testing c-function instead of a runtime
844 : // function. This code should only be called from a cctest.
845 : return Builtins::builtin_count;
846 : }
847 :
848 163413 : switch (reason) {
849 : #define TRAPREASON_TO_MESSAGE(name) \
850 : case wasm::k##name: \
851 : return Builtins::kThrowWasm##name;
852 27847 : FOREACH_WASM_TRAPREASON(TRAPREASON_TO_MESSAGE)
853 : #undef TRAPREASON_TO_MESSAGE
854 : default:
855 0 : UNREACHABLE();
856 : }
857 : }
858 :
859 1977 : Node* WasmGraphBuilder::TrapIfTrue(wasm::TrapReason reason, Node* cond,
860 5934 : wasm::WasmCodePosition position) {
861 1977 : Builtins::Name trap_id = GetBuiltinIdForTrap(reason);
862 : Node* node = graph()->NewNode(jsgraph()->common()->TrapIf(trap_id), cond,
863 1978 : Effect(), Control());
864 1982 : *control_ = node;
865 1982 : SetSourcePosition(node, position);
866 1983 : return node;
867 : }
868 :
869 196464 : Node* WasmGraphBuilder::TrapIfFalse(wasm::TrapReason reason, Node* cond,
870 589443 : wasm::WasmCodePosition position) {
871 196464 : Builtins::Name trap_id = GetBuiltinIdForTrap(reason);
872 :
873 : Node* node = graph()->NewNode(jsgraph()->common()->TrapUnless(trap_id), cond,
874 196481 : Effect(), Control());
875 196486 : *control_ = node;
876 196486 : SetSourcePosition(node, position);
877 196494 : return node;
878 : }
879 :
880 : // Add a check that traps if {node} is equal to {val}.
881 1243 : Node* WasmGraphBuilder::TrapIfEq32(wasm::TrapReason reason, Node* node,
882 : int32_t val,
883 632 : wasm::WasmCodePosition position) {
884 : Int32Matcher m(node);
885 2108 : if (m.HasValue() && !m.Is(val)) return graph()->start();
886 865 : if (val == 0) {
887 549 : return TrapIfFalse(reason, node, position);
888 : } else {
889 : return TrapIfTrue(reason,
890 : graph()->NewNode(jsgraph()->machine()->Word32Equal(),
891 : node, jsgraph()->Int32Constant(val)),
892 948 : position);
893 : }
894 : }
895 :
896 : // Add a check that traps if {node} is zero.
897 0 : Node* WasmGraphBuilder::ZeroCheck32(wasm::TrapReason reason, Node* node,
898 : wasm::WasmCodePosition position) {
899 858 : return TrapIfEq32(reason, node, 0, position);
900 : }
901 :
902 : // Add a check that traps if {node} is equal to {val}.
903 1374 : Node* WasmGraphBuilder::TrapIfEq64(wasm::TrapReason reason, Node* node,
904 : int64_t val,
905 2013 : wasm::WasmCodePosition position) {
906 : Int64Matcher m(node);
907 2142 : if (m.HasValue() && !m.Is(val)) return graph()->start();
908 : return TrapIfTrue(reason,
909 : graph()->NewNode(jsgraph()->machine()->Word64Equal(), node,
910 : jsgraph()->Int64Constant(val)),
911 3021 : position);
912 : }
913 :
914 : // Add a check that traps if {node} is zero.
915 0 : Node* WasmGraphBuilder::ZeroCheck64(wasm::TrapReason reason, Node* node,
916 : wasm::WasmCodePosition position) {
917 1070 : return TrapIfEq64(reason, node, 0, position);
918 : }
919 :
920 26148 : Node* WasmGraphBuilder::Switch(unsigned count, Node* key) {
921 39222 : return graph()->NewNode(jsgraph()->common()->Switch(count), key, *control_);
922 : }
923 :
924 284696 : Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) {
925 : DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
926 569391 : return graph()->NewNode(jsgraph()->common()->IfValue(value), sw);
927 : }
928 :
929 13074 : Node* WasmGraphBuilder::IfDefault(Node* sw) {
930 : DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
931 26148 : return graph()->NewNode(jsgraph()->common()->IfDefault(), sw);
932 : }
933 :
934 2373306 : Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
935 : DCHECK_NOT_NULL(*control_);
936 : DCHECK_NOT_NULL(*effect_);
937 :
938 : static const int kStackAllocatedNodeBufferSize = 8;
939 : Node* stack_buffer[kStackAllocatedNodeBufferSize];
940 : std::vector<Node*> heap_buffer;
941 :
942 : Node** buf = stack_buffer;
943 593274 : if (count + 3 > kStackAllocatedNodeBufferSize) {
944 0 : heap_buffer.resize(count + 3);
945 : buf = heap_buffer.data();
946 : }
947 :
948 593274 : buf[0] = jsgraph()->Int32Constant(0);
949 593348 : memcpy(buf + 1, vals, sizeof(void*) * count);
950 593348 : buf[count + 1] = *effect_;
951 593348 : buf[count + 2] = *control_;
952 : Node* ret =
953 1779903 : graph()->NewNode(jsgraph()->common()->Return(count), count + 3, buf);
954 :
955 593410 : MergeControlToEnd(jsgraph(), ret);
956 593364 : return ret;
957 : }
958 :
959 130051 : Node* WasmGraphBuilder::ReturnVoid() { return Return(0, nullptr); }
960 :
961 129999 : Node* WasmGraphBuilder::Unreachable(wasm::WasmCodePosition position) {
962 130001 : TrapIfFalse(wasm::TrapReason::kTrapUnreachable, Int32Constant(0), position);
963 : ReturnVoid();
964 130001 : return nullptr;
965 : }
966 :
967 39704 : Node* WasmGraphBuilder::MaskShiftCount32(Node* node) {
968 : static const int32_t kMask32 = 0x1f;
969 79336 : if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
970 : // Shifts by constants are so common we pattern-match them here.
971 : Int32Matcher match(node);
972 36 : if (match.HasValue()) {
973 0 : int32_t masked = (match.Value() & kMask32);
974 0 : if (match.Value() != masked) node = jsgraph()->Int32Constant(masked);
975 : } else {
976 : node = graph()->NewNode(jsgraph()->machine()->Word32And(), node,
977 72 : jsgraph()->Int32Constant(kMask32));
978 : }
979 : }
980 39668 : return node;
981 : }
982 :
983 970 : Node* WasmGraphBuilder::MaskShiftCount64(Node* node) {
984 : static const int64_t kMask64 = 0x3f;
985 1880 : if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
986 : // Shifts by constants are so common we pattern-match them here.
987 : Int64Matcher match(node);
988 30 : if (match.HasValue()) {
989 0 : int64_t masked = (match.Value() & kMask64);
990 0 : if (match.Value() != masked) node = jsgraph()->Int64Constant(masked);
991 : } else {
992 : node = graph()->NewNode(jsgraph()->machine()->Word64And(), node,
993 60 : jsgraph()->Int64Constant(kMask64));
994 : }
995 : }
996 940 : return node;
997 : }
998 :
999 0 : static bool ReverseBytesSupported(MachineOperatorBuilder* m,
1000 : size_t size_in_bytes) {
1001 0 : switch (size_in_bytes) {
1002 : case 4:
1003 : case 16:
1004 0 : return m->Word32ReverseBytes().IsSupported();
1005 : case 8:
1006 0 : return m->Word64ReverseBytes().IsSupported();
1007 : default:
1008 : break;
1009 : }
1010 : return false;
1011 : }
1012 :
1013 0 : Node* WasmGraphBuilder::BuildChangeEndiannessStore(Node* node,
1014 : MachineType memtype,
1015 0 : wasm::ValueType wasmtype) {
1016 : Node* result;
1017 : Node* value = node;
1018 0 : MachineOperatorBuilder* m = jsgraph()->machine();
1019 0 : int valueSizeInBytes = 1 << ElementSizeLog2Of(wasmtype);
1020 0 : int valueSizeInBits = 8 * valueSizeInBytes;
1021 : bool isFloat = false;
1022 :
1023 0 : switch (wasmtype) {
1024 : case wasm::kWasmF64:
1025 0 : value = graph()->NewNode(m->BitcastFloat64ToInt64(), node);
1026 : isFloat = true;
1027 : case wasm::kWasmI64:
1028 0 : result = jsgraph()->Int64Constant(0);
1029 0 : break;
1030 : case wasm::kWasmF32:
1031 0 : value = graph()->NewNode(m->BitcastFloat32ToInt32(), node);
1032 : isFloat = true;
1033 : case wasm::kWasmI32:
1034 0 : result = jsgraph()->Int32Constant(0);
1035 0 : break;
1036 : case wasm::kWasmS128:
1037 : DCHECK(ReverseBytesSupported(m, valueSizeInBytes));
1038 : break;
1039 : default:
1040 0 : UNREACHABLE();
1041 : break;
1042 : }
1043 :
1044 0 : if (memtype.representation() == MachineRepresentation::kWord8) {
1045 : // No need to change endianness for byte size, return original node
1046 : return node;
1047 : }
1048 0 : if (wasmtype == wasm::kWasmI64 &&
1049 : memtype.representation() < MachineRepresentation::kWord64) {
1050 : // In case we store lower part of WasmI64 expression, we can truncate
1051 : // upper 32bits
1052 0 : value = graph()->NewNode(m->TruncateInt64ToInt32(), value);
1053 0 : valueSizeInBytes = 1 << ElementSizeLog2Of(wasm::kWasmI32);
1054 0 : valueSizeInBits = 8 * valueSizeInBytes;
1055 0 : if (memtype.representation() == MachineRepresentation::kWord16) {
1056 : value =
1057 0 : graph()->NewNode(m->Word32Shl(), value, jsgraph()->Int32Constant(16));
1058 : }
1059 0 : } else if (wasmtype == wasm::kWasmI32 &&
1060 : memtype.representation() == MachineRepresentation::kWord16) {
1061 : value =
1062 0 : graph()->NewNode(m->Word32Shl(), value, jsgraph()->Int32Constant(16));
1063 : }
1064 :
1065 : int i;
1066 : uint32_t shiftCount;
1067 :
1068 0 : if (ReverseBytesSupported(m, valueSizeInBytes)) {
1069 0 : switch (valueSizeInBytes) {
1070 : case 4:
1071 0 : result = graph()->NewNode(m->Word32ReverseBytes().op(), value);
1072 0 : break;
1073 : case 8:
1074 0 : result = graph()->NewNode(m->Word64ReverseBytes().op(), value);
1075 0 : break;
1076 : case 16: {
1077 : Node* byte_reversed_lanes[4];
1078 0 : for (int lane = 0; lane < 4; lane++) {
1079 : byte_reversed_lanes[lane] = graph()->NewNode(
1080 : m->Word32ReverseBytes().op(),
1081 : graph()->NewNode(jsgraph()->machine()->I32x4ExtractLane(lane),
1082 0 : value));
1083 : }
1084 :
1085 : // This is making a copy of the value.
1086 : result =
1087 0 : graph()->NewNode(jsgraph()->machine()->S128And(), value, value);
1088 :
1089 0 : for (int lane = 0; lane < 4; lane++) {
1090 : result =
1091 : graph()->NewNode(jsgraph()->machine()->I32x4ReplaceLane(3 - lane),
1092 0 : result, byte_reversed_lanes[lane]);
1093 : }
1094 :
1095 : break;
1096 : }
1097 : default:
1098 0 : UNREACHABLE();
1099 : break;
1100 : }
1101 : } else {
1102 0 : for (i = 0, shiftCount = valueSizeInBits - 8; i < valueSizeInBits / 2;
1103 : i += 8, shiftCount -= 16) {
1104 : Node* shiftLower;
1105 : Node* shiftHigher;
1106 : Node* lowerByte;
1107 : Node* higherByte;
1108 :
1109 : DCHECK_LT(0, shiftCount);
1110 : DCHECK_EQ(0, (shiftCount + 8) % 16);
1111 :
1112 0 : if (valueSizeInBits > 32) {
1113 : shiftLower = graph()->NewNode(m->Word64Shl(), value,
1114 0 : jsgraph()->Int64Constant(shiftCount));
1115 : shiftHigher = graph()->NewNode(m->Word64Shr(), value,
1116 0 : jsgraph()->Int64Constant(shiftCount));
1117 : lowerByte = graph()->NewNode(
1118 : m->Word64And(), shiftLower,
1119 : jsgraph()->Int64Constant(static_cast<uint64_t>(0xFF)
1120 0 : << (valueSizeInBits - 8 - i)));
1121 : higherByte = graph()->NewNode(
1122 : m->Word64And(), shiftHigher,
1123 0 : jsgraph()->Int64Constant(static_cast<uint64_t>(0xFF) << i));
1124 0 : result = graph()->NewNode(m->Word64Or(), result, lowerByte);
1125 0 : result = graph()->NewNode(m->Word64Or(), result, higherByte);
1126 : } else {
1127 : shiftLower = graph()->NewNode(m->Word32Shl(), value,
1128 0 : jsgraph()->Int32Constant(shiftCount));
1129 : shiftHigher = graph()->NewNode(m->Word32Shr(), value,
1130 0 : jsgraph()->Int32Constant(shiftCount));
1131 : lowerByte = graph()->NewNode(
1132 : m->Word32And(), shiftLower,
1133 : jsgraph()->Int32Constant(static_cast<uint32_t>(0xFF)
1134 0 : << (valueSizeInBits - 8 - i)));
1135 : higherByte = graph()->NewNode(
1136 : m->Word32And(), shiftHigher,
1137 0 : jsgraph()->Int32Constant(static_cast<uint32_t>(0xFF) << i));
1138 0 : result = graph()->NewNode(m->Word32Or(), result, lowerByte);
1139 0 : result = graph()->NewNode(m->Word32Or(), result, higherByte);
1140 : }
1141 : }
1142 : }
1143 :
1144 0 : if (isFloat) {
1145 0 : switch (wasmtype) {
1146 : case wasm::kWasmF64:
1147 0 : result = graph()->NewNode(m->BitcastInt64ToFloat64(), result);
1148 0 : break;
1149 : case wasm::kWasmF32:
1150 0 : result = graph()->NewNode(m->BitcastInt32ToFloat32(), result);
1151 0 : break;
1152 : default:
1153 0 : UNREACHABLE();
1154 : break;
1155 : }
1156 : }
1157 :
1158 0 : return result;
1159 : }
1160 :
1161 0 : Node* WasmGraphBuilder::BuildChangeEndiannessLoad(Node* node,
1162 : MachineType memtype,
1163 0 : wasm::ValueType wasmtype) {
1164 : Node* result;
1165 : Node* value = node;
1166 0 : MachineOperatorBuilder* m = jsgraph()->machine();
1167 0 : int valueSizeInBytes = 1 << ElementSizeLog2Of(memtype.representation());
1168 0 : int valueSizeInBits = 8 * valueSizeInBytes;
1169 : bool isFloat = false;
1170 :
1171 0 : switch (memtype.representation()) {
1172 : case MachineRepresentation::kFloat64:
1173 0 : value = graph()->NewNode(m->BitcastFloat64ToInt64(), node);
1174 : isFloat = true;
1175 : case MachineRepresentation::kWord64:
1176 0 : result = jsgraph()->Int64Constant(0);
1177 0 : break;
1178 : case MachineRepresentation::kFloat32:
1179 0 : value = graph()->NewNode(m->BitcastFloat32ToInt32(), node);
1180 : isFloat = true;
1181 : case MachineRepresentation::kWord32:
1182 : case MachineRepresentation::kWord16:
1183 0 : result = jsgraph()->Int32Constant(0);
1184 0 : break;
1185 : case MachineRepresentation::kWord8:
1186 : // No need to change endianness for byte size, return original node
1187 : return node;
1188 : break;
1189 : case MachineRepresentation::kSimd128:
1190 : DCHECK(ReverseBytesSupported(m, valueSizeInBytes));
1191 : break;
1192 : default:
1193 0 : UNREACHABLE();
1194 : break;
1195 : }
1196 :
1197 : int i;
1198 : uint32_t shiftCount;
1199 :
1200 0 : if (ReverseBytesSupported(m, valueSizeInBytes < 4 ? 4 : valueSizeInBytes)) {
1201 0 : switch (valueSizeInBytes) {
1202 : case 2:
1203 : result =
1204 : graph()->NewNode(m->Word32ReverseBytes().op(),
1205 : graph()->NewNode(m->Word32Shl(), value,
1206 0 : jsgraph()->Int32Constant(16)));
1207 0 : break;
1208 : case 4:
1209 0 : result = graph()->NewNode(m->Word32ReverseBytes().op(), value);
1210 0 : break;
1211 : case 8:
1212 0 : result = graph()->NewNode(m->Word64ReverseBytes().op(), value);
1213 0 : break;
1214 : case 16: {
1215 : Node* byte_reversed_lanes[4];
1216 0 : for (int lane = 0; lane < 4; lane++) {
1217 : byte_reversed_lanes[lane] = graph()->NewNode(
1218 : m->Word32ReverseBytes().op(),
1219 : graph()->NewNode(jsgraph()->machine()->I32x4ExtractLane(lane),
1220 0 : value));
1221 : }
1222 :
1223 : // This is making a copy of the value.
1224 : result =
1225 0 : graph()->NewNode(jsgraph()->machine()->S128And(), value, value);
1226 :
1227 0 : for (int lane = 0; lane < 4; lane++) {
1228 : result =
1229 : graph()->NewNode(jsgraph()->machine()->I32x4ReplaceLane(3 - lane),
1230 0 : result, byte_reversed_lanes[lane]);
1231 : }
1232 :
1233 : break;
1234 : }
1235 : default:
1236 0 : UNREACHABLE();
1237 : }
1238 : } else {
1239 0 : 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_LT(0, shiftCount);
1247 : DCHECK_EQ(0, (shiftCount + 8) % 16);
1248 :
1249 0 : if (valueSizeInBits > 32) {
1250 : shiftLower = graph()->NewNode(m->Word64Shl(), value,
1251 0 : jsgraph()->Int64Constant(shiftCount));
1252 : shiftHigher = graph()->NewNode(m->Word64Shr(), value,
1253 0 : jsgraph()->Int64Constant(shiftCount));
1254 : lowerByte = graph()->NewNode(
1255 : m->Word64And(), shiftLower,
1256 : jsgraph()->Int64Constant(static_cast<uint64_t>(0xFF)
1257 0 : << (valueSizeInBits - 8 - i)));
1258 : higherByte = graph()->NewNode(
1259 : m->Word64And(), shiftHigher,
1260 0 : jsgraph()->Int64Constant(static_cast<uint64_t>(0xFF) << i));
1261 0 : result = graph()->NewNode(m->Word64Or(), result, lowerByte);
1262 0 : result = graph()->NewNode(m->Word64Or(), result, higherByte);
1263 : } else {
1264 : shiftLower = graph()->NewNode(m->Word32Shl(), value,
1265 0 : jsgraph()->Int32Constant(shiftCount));
1266 : shiftHigher = graph()->NewNode(m->Word32Shr(), value,
1267 0 : jsgraph()->Int32Constant(shiftCount));
1268 : lowerByte = graph()->NewNode(
1269 : m->Word32And(), shiftLower,
1270 : jsgraph()->Int32Constant(static_cast<uint32_t>(0xFF)
1271 0 : << (valueSizeInBits - 8 - i)));
1272 : higherByte = graph()->NewNode(
1273 : m->Word32And(), shiftHigher,
1274 0 : jsgraph()->Int32Constant(static_cast<uint32_t>(0xFF) << i));
1275 0 : result = graph()->NewNode(m->Word32Or(), result, lowerByte);
1276 0 : result = graph()->NewNode(m->Word32Or(), result, higherByte);
1277 : }
1278 : }
1279 : }
1280 :
1281 0 : if (isFloat) {
1282 0 : switch (memtype.representation()) {
1283 : case MachineRepresentation::kFloat64:
1284 0 : result = graph()->NewNode(m->BitcastInt64ToFloat64(), result);
1285 0 : break;
1286 : case MachineRepresentation::kFloat32:
1287 0 : result = graph()->NewNode(m->BitcastInt32ToFloat32(), result);
1288 0 : break;
1289 : default:
1290 0 : UNREACHABLE();
1291 : break;
1292 : }
1293 : }
1294 :
1295 : // We need to sign extend the value
1296 0 : if (memtype.IsSigned()) {
1297 : DCHECK(!isFloat);
1298 0 : 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 0 : if (wasmtype == wasm::kWasmI64) {
1304 0 : 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 0 : shiftBitCount);
1311 0 : } else if (wasmtype == wasm::kWasmI32) {
1312 0 : shiftBitCount = jsgraph()->Int32Constant(32 - valueSizeInBits);
1313 : result = graph()->NewNode(
1314 : m->Word32Sar(),
1315 : graph()->NewNode(m->Word32Shl(), result, shiftBitCount),
1316 0 : shiftBitCount);
1317 : }
1318 : }
1319 : }
1320 :
1321 0 : return result;
1322 : }
1323 :
1324 108 : 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 108 : jsgraph()->Int32Constant(0x80000000))));
1332 :
1333 54 : return result;
1334 : }
1335 :
1336 108 : 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 108 : jsgraph()->Int64Constant(0x8000000000000000))));
1345 :
1346 54 : 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 :
1364 272 : Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input,
1365 272 : wasm::WasmCodePosition position) {
1366 272 : MachineOperatorBuilder* m = jsgraph()->machine();
1367 : // Truncation of the input value is needed for the overflow check later.
1368 272 : Node* trunc = Unop(wasm::kExprF32Trunc, input);
1369 272 : 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 272 : Node* check = Unop(wasm::kExprF32SConvertI32, result);
1374 272 : Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
1375 272 : TrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
1376 :
1377 272 : return result;
1378 : }
1379 :
1380 262 : Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input,
1381 262 : wasm::WasmCodePosition position) {
1382 262 : MachineOperatorBuilder* m = jsgraph()->machine();
1383 : // Truncation of the input value is needed for the overflow check later.
1384 262 : Node* trunc = Unop(wasm::kExprF64Trunc, input);
1385 262 : 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 262 : Node* check = Unop(wasm::kExprF64SConvertI32, result);
1390 262 : Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
1391 262 : TrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
1392 :
1393 262 : return result;
1394 : }
1395 :
1396 68 : Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input,
1397 68 : wasm::WasmCodePosition position) {
1398 68 : MachineOperatorBuilder* m = jsgraph()->machine();
1399 : // Truncation of the input value is needed for the overflow check later.
1400 68 : Node* trunc = Unop(wasm::kExprF32Trunc, input);
1401 68 : 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 68 : Node* check = Unop(wasm::kExprF32UConvertI32, result);
1406 68 : Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
1407 68 : TrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
1408 :
1409 68 : return result;
1410 : }
1411 :
1412 58 : Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input,
1413 58 : wasm::WasmCodePosition position) {
1414 58 : MachineOperatorBuilder* m = jsgraph()->machine();
1415 : // Truncation of the input value is needed for the overflow check later.
1416 58 : Node* trunc = Unop(wasm::kExprF64Trunc, input);
1417 58 : 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 58 : Node* check = Unop(wasm::kExprF64UConvertI32, result);
1422 58 : Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
1423 58 : TrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
1424 :
1425 58 : return result;
1426 : }
1427 :
1428 12 : Node* WasmGraphBuilder::BuildI32AsmjsSConvertF32(Node* input) {
1429 12 : MachineOperatorBuilder* m = jsgraph()->machine();
1430 : // asm.js must use the wacky JS semantics.
1431 12 : input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1432 24 : return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1433 : }
1434 :
1435 130 : Node* WasmGraphBuilder::BuildI32AsmjsSConvertF64(Node* input) {
1436 130 : MachineOperatorBuilder* m = jsgraph()->machine();
1437 : // asm.js must use the wacky JS semantics.
1438 260 : return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1439 : }
1440 :
1441 12 : Node* WasmGraphBuilder::BuildI32AsmjsUConvertF32(Node* input) {
1442 12 : MachineOperatorBuilder* m = jsgraph()->machine();
1443 : // asm.js must use the wacky JS semantics.
1444 12 : input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1445 24 : return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1446 : }
1447 :
1448 12 : Node* WasmGraphBuilder::BuildI32AsmjsUConvertF64(Node* input) {
1449 12 : MachineOperatorBuilder* m = jsgraph()->machine();
1450 : // asm.js must use the wacky JS semantics.
1451 24 : return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1452 : }
1453 :
1454 0 : Node* WasmGraphBuilder::BuildBitCountingCall(Node* input, ExternalReference ref,
1455 0 : MachineRepresentation input_type) {
1456 : Node* stack_slot_param =
1457 0 : graph()->NewNode(jsgraph()->machine()->StackSlot(input_type));
1458 :
1459 : const Operator* store_op = jsgraph()->machine()->Store(
1460 0 : StoreRepresentation(input_type, kNoWriteBarrier));
1461 : *effect_ =
1462 : graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1463 0 : 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 0 : Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1470 :
1471 0 : return BuildCCall(sig_builder.Build(), function, stack_slot_param);
1472 : }
1473 :
1474 0 : Node* WasmGraphBuilder::BuildI32Ctz(Node* input) {
1475 : return BuildBitCountingCall(
1476 : input, ExternalReference::wasm_word32_ctz(jsgraph()->isolate()),
1477 0 : MachineRepresentation::kWord32);
1478 : }
1479 :
1480 0 : Node* WasmGraphBuilder::BuildI64Ctz(Node* input) {
1481 : return Unop(wasm::kExprI64UConvertI32,
1482 : BuildBitCountingCall(input, ExternalReference::wasm_word64_ctz(
1483 : jsgraph()->isolate()),
1484 0 : MachineRepresentation::kWord64));
1485 : }
1486 :
1487 0 : Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) {
1488 : return BuildBitCountingCall(
1489 : input, ExternalReference::wasm_word32_popcnt(jsgraph()->isolate()),
1490 0 : MachineRepresentation::kWord32);
1491 : }
1492 :
1493 0 : Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) {
1494 : return Unop(wasm::kExprI64UConvertI32,
1495 : BuildBitCountingCall(input, ExternalReference::wasm_word64_popcnt(
1496 : jsgraph()->isolate()),
1497 0 : MachineRepresentation::kWord64));
1498 : }
1499 :
1500 0 : Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
1501 0 : MachineType type = MachineType::Float32();
1502 : ExternalReference ref =
1503 0 : ExternalReference::wasm_f32_trunc(jsgraph()->isolate());
1504 :
1505 0 : return BuildCFuncInstruction(ref, type, input);
1506 : }
1507 :
1508 0 : Node* WasmGraphBuilder::BuildF32Floor(Node* input) {
1509 0 : MachineType type = MachineType::Float32();
1510 : ExternalReference ref =
1511 0 : ExternalReference::wasm_f32_floor(jsgraph()->isolate());
1512 0 : return BuildCFuncInstruction(ref, type, input);
1513 : }
1514 :
1515 0 : Node* WasmGraphBuilder::BuildF32Ceil(Node* input) {
1516 0 : MachineType type = MachineType::Float32();
1517 : ExternalReference ref =
1518 0 : ExternalReference::wasm_f32_ceil(jsgraph()->isolate());
1519 0 : return BuildCFuncInstruction(ref, type, input);
1520 : }
1521 :
1522 0 : Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) {
1523 0 : MachineType type = MachineType::Float32();
1524 : ExternalReference ref =
1525 0 : ExternalReference::wasm_f32_nearest_int(jsgraph()->isolate());
1526 0 : return BuildCFuncInstruction(ref, type, input);
1527 : }
1528 :
1529 0 : Node* WasmGraphBuilder::BuildF64Trunc(Node* input) {
1530 0 : MachineType type = MachineType::Float64();
1531 : ExternalReference ref =
1532 0 : ExternalReference::wasm_f64_trunc(jsgraph()->isolate());
1533 0 : return BuildCFuncInstruction(ref, type, input);
1534 : }
1535 :
1536 0 : Node* WasmGraphBuilder::BuildF64Floor(Node* input) {
1537 0 : MachineType type = MachineType::Float64();
1538 : ExternalReference ref =
1539 0 : ExternalReference::wasm_f64_floor(jsgraph()->isolate());
1540 0 : return BuildCFuncInstruction(ref, type, input);
1541 : }
1542 :
1543 0 : Node* WasmGraphBuilder::BuildF64Ceil(Node* input) {
1544 0 : MachineType type = MachineType::Float64();
1545 : ExternalReference ref =
1546 0 : ExternalReference::wasm_f64_ceil(jsgraph()->isolate());
1547 0 : return BuildCFuncInstruction(ref, type, input);
1548 : }
1549 :
1550 0 : Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) {
1551 0 : MachineType type = MachineType::Float64();
1552 : ExternalReference ref =
1553 0 : ExternalReference::wasm_f64_nearest_int(jsgraph()->isolate());
1554 0 : return BuildCFuncInstruction(ref, type, input);
1555 : }
1556 :
1557 38 : Node* WasmGraphBuilder::BuildF64Acos(Node* input) {
1558 19 : MachineType type = MachineType::Float64();
1559 : ExternalReference ref =
1560 19 : ExternalReference::f64_acos_wrapper_function(jsgraph()->isolate());
1561 19 : return BuildCFuncInstruction(ref, type, input);
1562 : }
1563 :
1564 38 : Node* WasmGraphBuilder::BuildF64Asin(Node* input) {
1565 19 : MachineType type = MachineType::Float64();
1566 : ExternalReference ref =
1567 19 : ExternalReference::f64_asin_wrapper_function(jsgraph()->isolate());
1568 19 : return BuildCFuncInstruction(ref, type, input);
1569 : }
1570 :
1571 26 : Node* WasmGraphBuilder::BuildF64Pow(Node* left, Node* right) {
1572 13 : MachineType type = MachineType::Float64();
1573 : ExternalReference ref =
1574 13 : ExternalReference::wasm_float64_pow(jsgraph()->isolate());
1575 13 : return BuildCFuncInstruction(ref, type, left, right);
1576 : }
1577 :
1578 60 : Node* WasmGraphBuilder::BuildF64Mod(Node* left, Node* right) {
1579 30 : MachineType type = MachineType::Float64();
1580 : ExternalReference ref =
1581 30 : ExternalReference::f64_mod_wrapper_function(jsgraph()->isolate());
1582 30 : return BuildCFuncInstruction(ref, type, left, right);
1583 : }
1584 :
1585 81 : Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref,
1586 : MachineType type, Node* input0,
1587 696 : Node* input1) {
1588 : // We do truncation by calling a C function which calculates the result.
1589 : // The input is passed to the C function as a double*'s to avoid double
1590 : // parameters. For this we reserve slots on the stack, store the parameters
1591 : // in those slots, pass pointers to the slot to the C function,
1592 : // and after calling the C function we collect the return value from
1593 : // the stack slot.
1594 :
1595 : Node* stack_slot_param0 =
1596 81 : graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation()));
1597 :
1598 : const Operator* store_op0 = jsgraph()->machine()->Store(
1599 81 : StoreRepresentation(type.representation(), kNoWriteBarrier));
1600 : *effect_ = graph()->NewNode(store_op0, stack_slot_param0,
1601 : jsgraph()->Int32Constant(0), input0, *effect_,
1602 243 : *control_);
1603 :
1604 81 : Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1605 :
1606 81 : if (input1 == nullptr) {
1607 : const int input_count = 1;
1608 : Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0,
1609 : input_count);
1610 : sig_builder.AddParam(MachineType::Pointer());
1611 38 : BuildCCall(sig_builder.Build(), function, stack_slot_param0);
1612 : } else {
1613 : Node* stack_slot_param1 = graph()->NewNode(
1614 43 : jsgraph()->machine()->StackSlot(type.representation()));
1615 : const Operator* store_op1 = jsgraph()->machine()->Store(
1616 43 : StoreRepresentation(type.representation(), kNoWriteBarrier));
1617 : *effect_ = graph()->NewNode(store_op1, stack_slot_param1,
1618 : jsgraph()->Int32Constant(0), input1, *effect_,
1619 129 : *control_);
1620 :
1621 : const int input_count = 2;
1622 : Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0,
1623 : input_count);
1624 : sig_builder.AddParam(MachineType::Pointer());
1625 : sig_builder.AddParam(MachineType::Pointer());
1626 : BuildCCall(sig_builder.Build(), function, stack_slot_param0,
1627 43 : stack_slot_param1);
1628 : }
1629 :
1630 81 : const Operator* load_op = jsgraph()->machine()->Load(type);
1631 :
1632 : Node* load =
1633 : graph()->NewNode(load_op, stack_slot_param0, jsgraph()->Int32Constant(0),
1634 162 : *effect_, *control_);
1635 81 : *effect_ = load;
1636 81 : return load;
1637 : }
1638 :
1639 0 : Node* WasmGraphBuilder::BuildF32SConvertI64(Node* input) {
1640 : // TODO(titzer/bradnelson): Check handlng of asm.js case.
1641 : return BuildIntToFloatConversionInstruction(
1642 : input, ExternalReference::wasm_int64_to_float32(jsgraph()->isolate()),
1643 0 : MachineRepresentation::kWord64, MachineType::Float32());
1644 : }
1645 0 : Node* WasmGraphBuilder::BuildF32UConvertI64(Node* input) {
1646 : // TODO(titzer/bradnelson): Check handlng of asm.js case.
1647 : return BuildIntToFloatConversionInstruction(
1648 : input, ExternalReference::wasm_uint64_to_float32(jsgraph()->isolate()),
1649 0 : MachineRepresentation::kWord64, MachineType::Float32());
1650 : }
1651 0 : Node* WasmGraphBuilder::BuildF64SConvertI64(Node* input) {
1652 : return BuildIntToFloatConversionInstruction(
1653 : input, ExternalReference::wasm_int64_to_float64(jsgraph()->isolate()),
1654 0 : MachineRepresentation::kWord64, MachineType::Float64());
1655 : }
1656 0 : Node* WasmGraphBuilder::BuildF64UConvertI64(Node* input) {
1657 : return BuildIntToFloatConversionInstruction(
1658 : input, ExternalReference::wasm_uint64_to_float64(jsgraph()->isolate()),
1659 0 : MachineRepresentation::kWord64, MachineType::Float64());
1660 : }
1661 :
1662 0 : Node* WasmGraphBuilder::BuildIntToFloatConversionInstruction(
1663 : Node* input, ExternalReference ref,
1664 : MachineRepresentation parameter_representation,
1665 0 : const MachineType result_type) {
1666 : Node* stack_slot_param = graph()->NewNode(
1667 0 : jsgraph()->machine()->StackSlot(parameter_representation));
1668 : Node* stack_slot_result = graph()->NewNode(
1669 0 : jsgraph()->machine()->StackSlot(result_type.representation()));
1670 : const Operator* store_op = jsgraph()->machine()->Store(
1671 0 : StoreRepresentation(parameter_representation, kNoWriteBarrier));
1672 : *effect_ =
1673 : graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1674 0 : input, *effect_, *control_);
1675 : MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 2);
1676 : sig_builder.AddParam(MachineType::Pointer());
1677 : sig_builder.AddParam(MachineType::Pointer());
1678 0 : Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1679 : BuildCCall(sig_builder.Build(), function, stack_slot_param,
1680 0 : stack_slot_result);
1681 0 : const Operator* load_op = jsgraph()->machine()->Load(result_type);
1682 : Node* load =
1683 : graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1684 0 : *effect_, *control_);
1685 0 : *effect_ = load;
1686 0 : return load;
1687 : }
1688 :
1689 70 : Node* WasmGraphBuilder::BuildI64SConvertF32(Node* input,
1690 70 : wasm::WasmCodePosition position) {
1691 140 : if (jsgraph()->machine()->Is32()) {
1692 : return BuildFloatToIntConversionInstruction(
1693 : input, ExternalReference::wasm_float32_to_int64(jsgraph()->isolate()),
1694 0 : MachineRepresentation::kFloat32, MachineType::Int64(), position);
1695 : } else {
1696 : Node* trunc = graph()->NewNode(
1697 70 : jsgraph()->machine()->TryTruncateFloat32ToInt64(), input);
1698 : Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1699 70 : graph()->start());
1700 : Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1701 70 : graph()->start());
1702 : ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
1703 70 : return result;
1704 : }
1705 : }
1706 :
1707 70 : Node* WasmGraphBuilder::BuildI64UConvertF32(Node* input,
1708 70 : wasm::WasmCodePosition position) {
1709 140 : if (jsgraph()->machine()->Is32()) {
1710 : return BuildFloatToIntConversionInstruction(
1711 : input, ExternalReference::wasm_float32_to_uint64(jsgraph()->isolate()),
1712 0 : MachineRepresentation::kFloat32, MachineType::Int64(), position);
1713 : } else {
1714 : Node* trunc = graph()->NewNode(
1715 70 : jsgraph()->machine()->TryTruncateFloat32ToUint64(), input);
1716 : Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1717 70 : graph()->start());
1718 : Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1719 70 : graph()->start());
1720 : ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
1721 70 : return result;
1722 : }
1723 : }
1724 :
1725 122 : Node* WasmGraphBuilder::BuildI64SConvertF64(Node* input,
1726 122 : wasm::WasmCodePosition position) {
1727 244 : if (jsgraph()->machine()->Is32()) {
1728 : return BuildFloatToIntConversionInstruction(
1729 : input, ExternalReference::wasm_float64_to_int64(jsgraph()->isolate()),
1730 0 : MachineRepresentation::kFloat64, MachineType::Int64(), position);
1731 : } else {
1732 : Node* trunc = graph()->NewNode(
1733 122 : jsgraph()->machine()->TryTruncateFloat64ToInt64(), input);
1734 : Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1735 122 : graph()->start());
1736 : Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1737 122 : graph()->start());
1738 : ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
1739 122 : return result;
1740 : }
1741 : }
1742 :
1743 80 : Node* WasmGraphBuilder::BuildI64UConvertF64(Node* input,
1744 80 : wasm::WasmCodePosition position) {
1745 160 : if (jsgraph()->machine()->Is32()) {
1746 : return BuildFloatToIntConversionInstruction(
1747 : input, ExternalReference::wasm_float64_to_uint64(jsgraph()->isolate()),
1748 0 : MachineRepresentation::kFloat64, MachineType::Int64(), position);
1749 : } else {
1750 : Node* trunc = graph()->NewNode(
1751 80 : jsgraph()->machine()->TryTruncateFloat64ToUint64(), input);
1752 : Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1753 80 : graph()->start());
1754 : Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1755 80 : graph()->start());
1756 : ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
1757 80 : return result;
1758 : }
1759 : }
1760 :
1761 0 : Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
1762 : Node* input, ExternalReference ref,
1763 : MachineRepresentation parameter_representation,
1764 0 : const MachineType result_type, wasm::WasmCodePosition position) {
1765 : Node* stack_slot_param = graph()->NewNode(
1766 0 : jsgraph()->machine()->StackSlot(parameter_representation));
1767 : Node* stack_slot_result = graph()->NewNode(
1768 0 : jsgraph()->machine()->StackSlot(result_type.representation()));
1769 : const Operator* store_op = jsgraph()->machine()->Store(
1770 0 : StoreRepresentation(parameter_representation, kNoWriteBarrier));
1771 : *effect_ =
1772 : graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1773 0 : input, *effect_, *control_);
1774 : MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
1775 : sig_builder.AddReturn(MachineType::Int32());
1776 : sig_builder.AddParam(MachineType::Pointer());
1777 : sig_builder.AddParam(MachineType::Pointer());
1778 0 : Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1779 : ZeroCheck32(wasm::kTrapFloatUnrepresentable,
1780 : BuildCCall(sig_builder.Build(), function, stack_slot_param,
1781 : stack_slot_result),
1782 0 : position);
1783 0 : const Operator* load_op = jsgraph()->machine()->Load(result_type);
1784 : Node* load =
1785 : graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1786 0 : *effect_, *control_);
1787 0 : *effect_ = load;
1788 0 : return load;
1789 : }
1790 :
1791 6636 : Node* WasmGraphBuilder::GrowMemory(Node* input) {
1792 : SetNeedsStackCheck();
1793 : Diamond check_input_range(
1794 : graph(), jsgraph()->common(),
1795 : graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(), input,
1796 : jsgraph()->Uint32Constant(FLAG_wasm_max_mem_pages)),
1797 4424 : BranchHint::kTrue);
1798 :
1799 1106 : check_input_range.Chain(*control_);
1800 :
1801 1106 : Node* parameters[] = {BuildChangeUint32ToSmi(input)};
1802 1106 : Node* old_effect = *effect_;
1803 1106 : *control_ = check_input_range.if_true;
1804 : Node* call = BuildCallToRuntime(Runtime::kWasmGrowMemory, parameters,
1805 1106 : arraysize(parameters));
1806 :
1807 1106 : Node* result = BuildChangeSmiToInt32(call);
1808 :
1809 : result = check_input_range.Phi(MachineRepresentation::kWord32, result,
1810 1106 : jsgraph()->Int32Constant(-1));
1811 : *effect_ = graph()->NewNode(jsgraph()->common()->EffectPhi(2), *effect_,
1812 3318 : old_effect, check_input_range.merge);
1813 1106 : *control_ = check_input_range.merge;
1814 1106 : return result;
1815 : }
1816 :
1817 210 : uint32_t WasmGraphBuilder::GetExceptionEncodedSize(
1818 : const wasm::WasmException* exception) const {
1819 700 : const wasm::WasmExceptionSig* sig = exception->sig;
1820 : uint32_t encoded_size = 0;
1821 700 : for (size_t i = 0; i < sig->parameter_count(); ++i) {
1822 140 : size_t byte_size = size_t(1) << ElementSizeLog2Of(sig->GetParam(i));
1823 : DCHECK_EQ(byte_size % kBytesPerExceptionValuesArrayElement, 0);
1824 : DCHECK_LE(1, byte_size / kBytesPerExceptionValuesArrayElement);
1825 140 : encoded_size += byte_size / kBytesPerExceptionValuesArrayElement;
1826 : }
1827 210 : return encoded_size;
1828 : }
1829 :
1830 140 : Node* WasmGraphBuilder::Throw(uint32_t tag,
1831 : const wasm::WasmException* exception,
1832 140 : const Vector<Node*> values) {
1833 : SetNeedsStackCheck();
1834 140 : uint32_t encoded_size = GetExceptionEncodedSize(exception);
1835 : Node* create_parameters[] = {
1836 140 : BuildChangeUint32ToSmi(ConvertExceptionTagToRuntimeId(tag)),
1837 280 : BuildChangeUint32ToSmi(Uint32Constant(encoded_size))};
1838 : BuildCallToRuntime(Runtime::kWasmThrowCreate, create_parameters,
1839 140 : arraysize(create_parameters));
1840 140 : uint32_t index = 0;
1841 480 : const wasm::WasmExceptionSig* sig = exception->sig;
1842 140 : MachineOperatorBuilder* m = jsgraph()->machine();
1843 480 : for (size_t i = 0; i < sig->parameter_count(); ++i) {
1844 200 : Node* value = values[i];
1845 100 : switch (sig->GetParam(i)) {
1846 : case wasm::kWasmF32:
1847 20 : value = graph()->NewNode(m->BitcastFloat32ToInt32(), value);
1848 : // Intentionally fall to next case.
1849 : case wasm::kWasmI32:
1850 60 : BuildEncodeException32BitValue(&index, value);
1851 60 : break;
1852 : case wasm::kWasmF64:
1853 20 : value = graph()->NewNode(m->BitcastFloat64ToInt64(), value);
1854 : // Intentionally fall to next case.
1855 : case wasm::kWasmI64: {
1856 : Node* upper32 = graph()->NewNode(
1857 : m->TruncateInt64ToInt32(),
1858 40 : Binop(wasm::kExprI64ShrU, value, Int64Constant(32)));
1859 40 : BuildEncodeException32BitValue(&index, upper32);
1860 40 : Node* lower32 = graph()->NewNode(m->TruncateInt64ToInt32(), value);
1861 40 : BuildEncodeException32BitValue(&index, lower32);
1862 40 : break;
1863 : }
1864 : default:
1865 0 : CHECK(false);
1866 : break;
1867 : }
1868 : }
1869 : DCHECK_EQ(encoded_size, index);
1870 140 : return BuildCallToRuntime(Runtime::kWasmThrow, nullptr, 0);
1871 : }
1872 :
1873 140 : void WasmGraphBuilder::BuildEncodeException32BitValue(uint32_t* index,
1874 140 : Node* value) {
1875 140 : MachineOperatorBuilder* machine = jsgraph()->machine();
1876 : Node* upper_parameters[] = {
1877 280 : BuildChangeUint32ToSmi(Int32Constant(*index)),
1878 : BuildChangeUint32ToSmi(
1879 280 : graph()->NewNode(machine->Word32Shr(), value, Int32Constant(16))),
1880 280 : };
1881 : BuildCallToRuntime(Runtime::kWasmExceptionSetElement, upper_parameters,
1882 140 : arraysize(upper_parameters));
1883 140 : ++(*index);
1884 : Node* lower_parameters[] = {
1885 280 : BuildChangeUint32ToSmi(Int32Constant(*index)),
1886 : BuildChangeUint32ToSmi(graph()->NewNode(machine->Word32And(), value,
1887 280 : Int32Constant(0xFFFFu))),
1888 280 : };
1889 : BuildCallToRuntime(Runtime::kWasmExceptionSetElement, lower_parameters,
1890 140 : arraysize(lower_parameters));
1891 140 : ++(*index);
1892 140 : }
1893 :
1894 60 : Node* WasmGraphBuilder::BuildDecodeException32BitValue(Node* const* values,
1895 60 : uint32_t* index) {
1896 60 : MachineOperatorBuilder* machine = jsgraph()->machine();
1897 60 : Node* upper = BuildChangeSmiToInt32(values[*index]);
1898 60 : (*index)++;
1899 60 : upper = graph()->NewNode(machine->Word32Shl(), upper, Int32Constant(16));
1900 60 : Node* lower = BuildChangeSmiToInt32(values[*index]);
1901 60 : (*index)++;
1902 60 : Node* value = graph()->NewNode(machine->Word32Or(), upper, lower);
1903 60 : return value;
1904 : }
1905 :
1906 70 : Node* WasmGraphBuilder::Rethrow() {
1907 : SetNeedsStackCheck();
1908 70 : Node* result = BuildCallToRuntime(Runtime::kWasmThrow, nullptr, 0);
1909 70 : return result;
1910 : }
1911 :
1912 70 : Node* WasmGraphBuilder::ConvertExceptionTagToRuntimeId(uint32_t tag) {
1913 : // TODO(kschimpf): Handle exceptions from different modules, when they are
1914 : // linked at runtime.
1915 70 : return Uint32Constant(tag);
1916 : }
1917 :
1918 70 : Node* WasmGraphBuilder::GetExceptionRuntimeId() {
1919 : SetNeedsStackCheck();
1920 : return BuildChangeSmiToInt32(
1921 70 : BuildCallToRuntime(Runtime::kWasmGetExceptionRuntimeId, nullptr, 0));
1922 : }
1923 :
1924 70 : Node** WasmGraphBuilder::GetExceptionValues(
1925 : const wasm::WasmException* except_decl) {
1926 : // TODO(kschimpf): We need to move this code to the function-body-decoder.cc
1927 : // in order to build landing-pad (exception) edges in case the runtime
1928 : // call causes an exception.
1929 :
1930 : // Start by getting the encoded values from the exception.
1931 70 : uint32_t encoded_size = GetExceptionEncodedSize(except_decl);
1932 70 : Node** values = Buffer(encoded_size);
1933 190 : for (uint32_t i = 0; i < encoded_size; ++i) {
1934 120 : Node* parameters[] = {BuildChangeUint32ToSmi(Uint32Constant(i))};
1935 120 : values[i] = BuildCallToRuntime(Runtime::kWasmExceptionGetElement,
1936 120 : parameters, arraysize(parameters));
1937 : }
1938 :
1939 : // Now convert the leading entries to the corresponding parameter values.
1940 70 : uint32_t index = 0;
1941 220 : const wasm::WasmExceptionSig* sig = except_decl->sig;
1942 220 : for (size_t i = 0; i < sig->parameter_count(); ++i) {
1943 40 : Node* value = BuildDecodeException32BitValue(values, &index);
1944 40 : switch (wasm::ValueType type = sig->GetParam(i)) {
1945 : case wasm::kWasmF32: {
1946 10 : value = Unop(wasm::kExprF32ReinterpretI32, value);
1947 10 : break;
1948 : }
1949 : case wasm::kWasmI32:
1950 : break;
1951 : case wasm::kWasmF64:
1952 : case wasm::kWasmI64: {
1953 : Node* upper =
1954 : Binop(wasm::kExprI64Shl, Unop(wasm::kExprI64UConvertI32, value),
1955 20 : Int64Constant(32));
1956 : Node* lower = Unop(wasm::kExprI64UConvertI32,
1957 20 : BuildDecodeException32BitValue(values, &index));
1958 20 : value = Binop(wasm::kExprI64Ior, upper, lower);
1959 20 : if (type == wasm::kWasmF64) {
1960 10 : value = Unop(wasm::kExprF64ReinterpretI64, value);
1961 : }
1962 : break;
1963 : }
1964 : default:
1965 0 : CHECK(false);
1966 : break;
1967 : }
1968 40 : values[i] = value;
1969 : }
1970 : DCHECK_EQ(index, encoded_size);
1971 70 : return values;
1972 : }
1973 :
1974 338 : Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
1975 992 : wasm::WasmCodePosition position) {
1976 338 : MachineOperatorBuilder* m = jsgraph()->machine();
1977 : ZeroCheck32(wasm::kTrapDivByZero, right, position);
1978 338 : Node* before = *control_;
1979 : Node* denom_is_m1;
1980 : Node* denom_is_not_m1;
1981 : BranchExpectFalse(
1982 : graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1983 338 : &denom_is_m1, &denom_is_not_m1);
1984 338 : *control_ = denom_is_m1;
1985 338 : TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt, position);
1986 338 : if (*control_ != denom_is_m1) {
1987 : *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1988 948 : *control_);
1989 : } else {
1990 22 : *control_ = before;
1991 : }
1992 676 : return graph()->NewNode(m->Int32Div(), left, right, *control_);
1993 : }
1994 :
1995 156 : Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right,
1996 624 : wasm::WasmCodePosition position) {
1997 156 : MachineOperatorBuilder* m = jsgraph()->machine();
1998 :
1999 : ZeroCheck32(wasm::kTrapRemByZero, right, position);
2000 :
2001 : Diamond d(
2002 : graph(), jsgraph()->common(),
2003 : graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
2004 468 : BranchHint::kFalse);
2005 156 : d.Chain(*control_);
2006 :
2007 : return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
2008 312 : graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
2009 : }
2010 :
2011 222 : Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right,
2012 222 : wasm::WasmCodePosition position) {
2013 222 : MachineOperatorBuilder* m = jsgraph()->machine();
2014 : return graph()->NewNode(m->Uint32Div(), left, right,
2015 444 : ZeroCheck32(wasm::kTrapDivByZero, right, position));
2016 : }
2017 :
2018 142 : Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right,
2019 142 : wasm::WasmCodePosition position) {
2020 142 : MachineOperatorBuilder* m = jsgraph()->machine();
2021 : return graph()->NewNode(m->Uint32Mod(), left, right,
2022 284 : ZeroCheck32(wasm::kTrapRemByZero, right, position));
2023 : }
2024 :
2025 989 : Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) {
2026 524 : MachineOperatorBuilder* m = jsgraph()->machine();
2027 :
2028 : Int32Matcher mr(right);
2029 524 : if (mr.HasValue()) {
2030 431 : if (mr.Value() == 0) {
2031 19 : return jsgraph()->Int32Constant(0);
2032 412 : } else if (mr.Value() == -1) {
2033 : // The result is the negation of the left input.
2034 38 : return graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
2035 : }
2036 786 : return graph()->NewNode(m->Int32Div(), left, right, *control_);
2037 : }
2038 :
2039 : // asm.js semantics return 0 on divide or mod by zero.
2040 93 : if (m->Int32DivIsSafe()) {
2041 : // The hardware instruction does the right thing (e.g. arm).
2042 0 : return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
2043 : }
2044 :
2045 : // Check denominator for zero.
2046 : Diamond z(
2047 : graph(), jsgraph()->common(),
2048 : graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
2049 279 : BranchHint::kFalse);
2050 :
2051 : // Check numerator for -1. (avoid minint / -1 case).
2052 : Diamond n(
2053 : graph(), jsgraph()->common(),
2054 : graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
2055 279 : BranchHint::kFalse);
2056 :
2057 93 : Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
2058 : Node* neg =
2059 93 : graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
2060 :
2061 : return n.Phi(
2062 : MachineRepresentation::kWord32, neg,
2063 93 : z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0), div));
2064 : }
2065 :
2066 700 : Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) {
2067 608 : CommonOperatorBuilder* c = jsgraph()->common();
2068 608 : MachineOperatorBuilder* m = jsgraph()->machine();
2069 608 : Node* const zero = jsgraph()->Int32Constant(0);
2070 :
2071 : Int32Matcher mr(right);
2072 608 : if (mr.HasValue()) {
2073 516 : if (mr.Value() == 0 || mr.Value() == -1) {
2074 : return zero;
2075 : }
2076 956 : return graph()->NewNode(m->Int32Mod(), left, right, *control_);
2077 : }
2078 :
2079 : // General case for signed integer modulus, with optimization for (unknown)
2080 : // power of 2 right hand side.
2081 : //
2082 : // if 0 < right then
2083 : // msk = right - 1
2084 : // if right & msk != 0 then
2085 : // left % right
2086 : // else
2087 : // if left < 0 then
2088 : // -(-left & msk)
2089 : // else
2090 : // left & msk
2091 : // else
2092 : // if right < -1 then
2093 : // left % right
2094 : // else
2095 : // zero
2096 : //
2097 : // Note: We do not use the Diamond helper class here, because it really hurts
2098 : // readability with nested diamonds.
2099 92 : Node* const minus_one = jsgraph()->Int32Constant(-1);
2100 :
2101 92 : const Operator* const merge_op = c->Merge(2);
2102 92 : const Operator* const phi_op = c->Phi(MachineRepresentation::kWord32, 2);
2103 :
2104 92 : Node* check0 = graph()->NewNode(m->Int32LessThan(), zero, right);
2105 : Node* branch0 =
2106 92 : graph()->NewNode(c->Branch(BranchHint::kTrue), check0, graph()->start());
2107 :
2108 92 : Node* if_true0 = graph()->NewNode(c->IfTrue(), branch0);
2109 : Node* true0;
2110 : {
2111 92 : Node* msk = graph()->NewNode(m->Int32Add(), right, minus_one);
2112 :
2113 92 : Node* check1 = graph()->NewNode(m->Word32And(), right, msk);
2114 92 : Node* branch1 = graph()->NewNode(c->Branch(), check1, if_true0);
2115 :
2116 92 : Node* if_true1 = graph()->NewNode(c->IfTrue(), branch1);
2117 92 : Node* true1 = graph()->NewNode(m->Int32Mod(), left, right, if_true1);
2118 :
2119 92 : Node* if_false1 = graph()->NewNode(c->IfFalse(), branch1);
2120 : Node* false1;
2121 : {
2122 92 : Node* check2 = graph()->NewNode(m->Int32LessThan(), left, zero);
2123 : Node* branch2 =
2124 92 : graph()->NewNode(c->Branch(BranchHint::kFalse), check2, if_false1);
2125 :
2126 92 : Node* if_true2 = graph()->NewNode(c->IfTrue(), branch2);
2127 : Node* true2 = graph()->NewNode(
2128 : m->Int32Sub(), zero,
2129 : graph()->NewNode(m->Word32And(),
2130 276 : graph()->NewNode(m->Int32Sub(), zero, left), msk));
2131 :
2132 92 : Node* if_false2 = graph()->NewNode(c->IfFalse(), branch2);
2133 92 : Node* false2 = graph()->NewNode(m->Word32And(), left, msk);
2134 :
2135 : if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
2136 : false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
2137 : }
2138 :
2139 : if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
2140 : true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
2141 : }
2142 :
2143 92 : Node* if_false0 = graph()->NewNode(c->IfFalse(), branch0);
2144 : Node* false0;
2145 : {
2146 92 : Node* check1 = graph()->NewNode(m->Int32LessThan(), right, minus_one);
2147 : Node* branch1 =
2148 92 : graph()->NewNode(c->Branch(BranchHint::kTrue), check1, if_false0);
2149 :
2150 92 : Node* if_true1 = graph()->NewNode(c->IfTrue(), branch1);
2151 92 : Node* true1 = graph()->NewNode(m->Int32Mod(), left, right, if_true1);
2152 :
2153 92 : Node* if_false1 = graph()->NewNode(c->IfFalse(), branch1);
2154 : Node* false1 = zero;
2155 :
2156 : if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
2157 : false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
2158 : }
2159 :
2160 : Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
2161 92 : return graph()->NewNode(phi_op, true0, false0, merge0);
2162 : }
2163 :
2164 764 : Node* WasmGraphBuilder::BuildI32AsmjsDivU(Node* left, Node* right) {
2165 191 : MachineOperatorBuilder* m = jsgraph()->machine();
2166 : // asm.js semantics return 0 on divide or mod by zero.
2167 191 : if (m->Uint32DivIsSafe()) {
2168 : // The hardware instruction does the right thing (e.g. arm).
2169 0 : return graph()->NewNode(m->Uint32Div(), left, right, graph()->start());
2170 : }
2171 :
2172 : // Explicit check for x % 0.
2173 : Diamond z(
2174 : graph(), jsgraph()->common(),
2175 : graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
2176 573 : BranchHint::kFalse);
2177 :
2178 : return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
2179 : graph()->NewNode(jsgraph()->machine()->Uint32Div(), left, right,
2180 573 : z.if_false));
2181 : }
2182 :
2183 1040 : Node* WasmGraphBuilder::BuildI32AsmjsRemU(Node* left, Node* right) {
2184 260 : MachineOperatorBuilder* m = jsgraph()->machine();
2185 : // asm.js semantics return 0 on divide or mod by zero.
2186 : // Explicit check for x % 0.
2187 : Diamond z(
2188 : graph(), jsgraph()->common(),
2189 : graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
2190 780 : BranchHint::kFalse);
2191 :
2192 : Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
2193 520 : z.if_false);
2194 : return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
2195 260 : rem);
2196 : }
2197 :
2198 306 : Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
2199 1518 : wasm::WasmCodePosition position) {
2200 612 : if (jsgraph()->machine()->Is32()) {
2201 : return BuildDiv64Call(
2202 : left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
2203 0 : MachineType::Int64(), wasm::kTrapDivByZero, position);
2204 : }
2205 : ZeroCheck64(wasm::kTrapDivByZero, right, position);
2206 306 : Node* before = *control_;
2207 : Node* denom_is_m1;
2208 : Node* denom_is_not_m1;
2209 : BranchExpectFalse(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
2210 : jsgraph()->Int64Constant(-1)),
2211 612 : &denom_is_m1, &denom_is_not_m1);
2212 306 : *control_ = denom_is_m1;
2213 : TrapIfEq64(wasm::kTrapDivUnrepresentable, left,
2214 306 : std::numeric_limits<int64_t>::min(), position);
2215 306 : if (*control_ != denom_is_m1) {
2216 : *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
2217 882 : *control_);
2218 : } else {
2219 12 : *control_ = before;
2220 : }
2221 : return graph()->NewNode(jsgraph()->machine()->Int64Div(), left, right,
2222 918 : *control_);
2223 : }
2224 :
2225 134 : Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right,
2226 804 : wasm::WasmCodePosition position) {
2227 268 : if (jsgraph()->machine()->Is32()) {
2228 : return BuildDiv64Call(
2229 : left, right, ExternalReference::wasm_int64_mod(jsgraph()->isolate()),
2230 0 : MachineType::Int64(), wasm::kTrapRemByZero, position);
2231 : }
2232 : ZeroCheck64(wasm::kTrapRemByZero, right, position);
2233 : Diamond d(jsgraph()->graph(), jsgraph()->common(),
2234 : graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
2235 402 : jsgraph()->Int64Constant(-1)));
2236 :
2237 134 : d.Chain(*control_);
2238 :
2239 : Node* rem = graph()->NewNode(jsgraph()->machine()->Int64Mod(), left, right,
2240 268 : d.if_false);
2241 :
2242 : return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
2243 134 : rem);
2244 : }
2245 :
2246 154 : Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right,
2247 308 : wasm::WasmCodePosition position) {
2248 308 : if (jsgraph()->machine()->Is32()) {
2249 : return BuildDiv64Call(
2250 : left, right, ExternalReference::wasm_uint64_div(jsgraph()->isolate()),
2251 0 : MachineType::Int64(), wasm::kTrapDivByZero, position);
2252 : }
2253 : return graph()->NewNode(jsgraph()->machine()->Uint64Div(), left, right,
2254 308 : ZeroCheck64(wasm::kTrapDivByZero, right, position));
2255 : }
2256 134 : Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right,
2257 268 : wasm::WasmCodePosition position) {
2258 268 : if (jsgraph()->machine()->Is32()) {
2259 : return BuildDiv64Call(
2260 : left, right, ExternalReference::wasm_uint64_mod(jsgraph()->isolate()),
2261 0 : MachineType::Int64(), wasm::kTrapRemByZero, position);
2262 : }
2263 : return graph()->NewNode(jsgraph()->machine()->Uint64Mod(), left, right,
2264 268 : ZeroCheck64(wasm::kTrapRemByZero, right, position));
2265 : }
2266 :
2267 0 : Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
2268 : ExternalReference ref,
2269 : MachineType result_type, int trap_zero,
2270 0 : wasm::WasmCodePosition position) {
2271 : Node* stack_slot_dst = graph()->NewNode(
2272 0 : jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
2273 : Node* stack_slot_src = graph()->NewNode(
2274 0 : jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
2275 :
2276 : const Operator* store_op = jsgraph()->machine()->Store(
2277 0 : StoreRepresentation(MachineRepresentation::kWord64, kNoWriteBarrier));
2278 : *effect_ =
2279 : graph()->NewNode(store_op, stack_slot_dst, jsgraph()->Int32Constant(0),
2280 0 : left, *effect_, *control_);
2281 : *effect_ =
2282 : graph()->NewNode(store_op, stack_slot_src, jsgraph()->Int32Constant(0),
2283 0 : right, *effect_, *control_);
2284 :
2285 : MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
2286 : sig_builder.AddReturn(MachineType::Int32());
2287 : sig_builder.AddParam(MachineType::Pointer());
2288 : sig_builder.AddParam(MachineType::Pointer());
2289 :
2290 0 : Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
2291 : Node* call =
2292 0 : BuildCCall(sig_builder.Build(), function, stack_slot_dst, stack_slot_src);
2293 :
2294 0 : ZeroCheck32(static_cast<wasm::TrapReason>(trap_zero), call, position);
2295 0 : TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position);
2296 0 : const Operator* load_op = jsgraph()->machine()->Load(result_type);
2297 : Node* load =
2298 : graph()->NewNode(load_op, stack_slot_dst, jsgraph()->Int32Constant(0),
2299 0 : *effect_, *control_);
2300 0 : *effect_ = load;
2301 0 : return load;
2302 : }
2303 :
2304 : template <typename... Args>
2305 35865 : Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node* function,
2306 71568 : Args... args) {
2307 : DCHECK_LE(sig->return_count(), 1);
2308 : DCHECK_EQ(sizeof...(args), sig->parameter_count());
2309 35865 : Node* const call_args[] = {function, args..., *effect_, *control_};
2310 :
2311 : CallDescriptor* desc =
2312 35865 : Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig);
2313 :
2314 35865 : const Operator* op = jsgraph()->common()->Call(desc);
2315 35865 : Node* call = graph()->NewNode(op, arraysize(call_args), call_args);
2316 35865 : *effect_ = call;
2317 35865 : return call;
2318 : }
2319 :
2320 527441 : Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
2321 : Node*** rets,
2322 351628 : wasm::WasmCodePosition position) {
2323 : DCHECK_NOT_NULL(wasm_context_);
2324 : SetNeedsStackCheck();
2325 : const size_t params = sig->parameter_count();
2326 : const size_t extra = 3; // wasm_context, effect, and control.
2327 175813 : const size_t count = 1 + params + extra;
2328 :
2329 : // Reallocate the buffer to make space for extra inputs.
2330 175813 : args = Realloc(args, 1 + params, count);
2331 :
2332 : // Make room for the wasm_context parameter at index 1, just after code.
2333 175825 : memmove(&args[2], &args[1], params * sizeof(Node*));
2334 175825 : args[1] = wasm_context_;
2335 :
2336 : // Add effect and control inputs.
2337 175825 : args[params + 2] = *effect_;
2338 175825 : args[params + 3] = *control_;
2339 :
2340 175825 : CallDescriptor* descriptor = GetWasmCallDescriptor(jsgraph()->zone(), sig);
2341 175803 : const Operator* op = jsgraph()->common()->Call(descriptor);
2342 351636 : Node* call = graph()->NewNode(op, static_cast<int>(count), args);
2343 175815 : SetSourcePosition(call, position);
2344 :
2345 175815 : *effect_ = call;
2346 : size_t ret_count = sig->return_count();
2347 175815 : if (ret_count == 0) return call; // No return value.
2348 :
2349 153485 : *rets = Buffer(ret_count);
2350 153491 : if (ret_count == 1) {
2351 : // Only a single return value.
2352 151943 : (*rets)[0] = call;
2353 : } else {
2354 : // Create projections for all return values.
2355 3096 : for (size_t i = 0; i < ret_count; i++) {
2356 3096 : (*rets)[i] = graph()->NewNode(jsgraph()->common()->Projection(i), call,
2357 6192 : graph()->start());
2358 : }
2359 : }
2360 : return call;
2361 : }
2362 :
2363 172517 : Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args, Node*** rets,
2364 : wasm::WasmCodePosition position) {
2365 : DCHECK_NULL(args[0]);
2366 :
2367 : // Add code object as constant.
2368 172517 : Handle<Code> code = index < env_->function_code.size()
2369 : ? env_->function_code[index]
2370 340054 : : env_->default_function_code;
2371 :
2372 : DCHECK(!code.is_null());
2373 172537 : args[0] = HeapConstant(code);
2374 345074 : wasm::FunctionSig* sig = env_->module->functions[index].sig;
2375 :
2376 172537 : return BuildWasmCall(sig, args, rets, position);
2377 : }
2378 :
2379 3290 : Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
2380 : Node*** rets,
2381 19737 : wasm::WasmCodePosition position) {
2382 : DCHECK_NOT_NULL(args[0]);
2383 : DCHECK_NOT_NULL(env_);
2384 :
2385 : // Assume only one table for now.
2386 : uint32_t table_index = 0;
2387 6580 : wasm::FunctionSig* sig = env_->module->signatures[sig_index];
2388 :
2389 3290 : EnsureFunctionTableNodes();
2390 3290 : MachineOperatorBuilder* machine = jsgraph()->machine();
2391 3290 : Node* key = args[0];
2392 :
2393 : // Bounds check against the table size.
2394 3290 : Node* size = function_table_sizes_[table_index];
2395 3290 : Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
2396 3290 : TrapIfFalse(wasm::kTrapFuncInvalid, in_bounds, position);
2397 3289 : Node* table_address = function_tables_[table_index];
2398 : Node* table = graph()->NewNode(
2399 : jsgraph()->machine()->Load(MachineType::AnyTagged()), table_address,
2400 9868 : jsgraph()->IntPtrConstant(0), *effect_, *control_);
2401 3289 : Node* signatures_address = signature_tables_[table_index];
2402 : Node* signatures = graph()->NewNode(
2403 : jsgraph()->machine()->Load(MachineType::AnyTagged()), signatures_address,
2404 9868 : jsgraph()->IntPtrConstant(0), *effect_, *control_);
2405 : // Load signature from the table and check.
2406 : // The table is a FixedArray; signatures are encoded as SMIs.
2407 : // [sig1, sig2, sig3, ...., code1, code2, code3 ...]
2408 3290 : ElementAccess access = AccessBuilder::ForFixedArrayElement();
2409 6580 : const int fixed_offset = access.header_size - access.tag();
2410 : {
2411 : Node* load_sig = graph()->NewNode(
2412 : machine->Load(MachineType::AnyTagged()), signatures,
2413 : graph()->NewNode(machine->Int32Add(),
2414 : graph()->NewNode(machine->Word32Shl(), key,
2415 : Int32Constant(kPointerSizeLog2)),
2416 : Int32Constant(fixed_offset)),
2417 13159 : *effect_, *control_);
2418 6578 : int32_t canonical_sig_num = env_->module->signature_ids[sig_index];
2419 : CHECK_GE(sig_index, 0);
2420 : Node* sig_match =
2421 : graph()->NewNode(machine->WordEqual(), load_sig,
2422 3290 : jsgraph()->SmiConstant(canonical_sig_num));
2423 3289 : TrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position);
2424 : }
2425 :
2426 : // Load code object from the table.
2427 : Node* load_code = graph()->NewNode(
2428 : machine->Load(MachineType::AnyTagged()), table,
2429 : graph()->NewNode(machine->Int32Add(),
2430 : graph()->NewNode(machine->Word32Shl(), key,
2431 : Int32Constant(kPointerSizeLog2)),
2432 : Uint32Constant(fixed_offset)),
2433 13157 : *effect_, *control_);
2434 :
2435 3290 : args[0] = load_code;
2436 3290 : return BuildWasmCall(sig, args, rets, position);
2437 : }
2438 :
2439 128 : Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
2440 : // Implement Rol by Ror since TurboFan does not have Rol opcode.
2441 : // TODO(weiliang): support Word32Rol opcode in TurboFan.
2442 : Int32Matcher m(right);
2443 64 : if (m.HasValue()) {
2444 : return Binop(wasm::kExprI32Ror, left,
2445 48 : jsgraph()->Int32Constant(32 - m.Value()));
2446 : } else {
2447 : return Binop(wasm::kExprI32Ror, left,
2448 40 : Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(32), right));
2449 : }
2450 : }
2451 :
2452 152 : Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) {
2453 : // Implement Rol by Ror since TurboFan does not have Rol opcode.
2454 : // TODO(weiliang): support Word64Rol opcode in TurboFan.
2455 : Int64Matcher m(right);
2456 76 : if (m.HasValue()) {
2457 : return Binop(wasm::kExprI64Ror, left,
2458 48 : jsgraph()->Int64Constant(64 - m.Value()));
2459 : } else {
2460 : return Binop(wasm::kExprI64Ror, left,
2461 52 : Binop(wasm::kExprI64Sub, jsgraph()->Int64Constant(64), right));
2462 : }
2463 : }
2464 :
2465 22692 : Node* WasmGraphBuilder::Invert(Node* node) {
2466 22692 : return Unop(wasm::kExprI32Eqz, node);
2467 : }
2468 :
2469 28964 : Node* WasmGraphBuilder::BuildChangeInt32ToTagged(Node* value) {
2470 28964 : MachineOperatorBuilder* machine = jsgraph()->machine();
2471 28964 : CommonOperatorBuilder* common = jsgraph()->common();
2472 :
2473 28964 : if (machine->Is64()) {
2474 28964 : return BuildChangeInt32ToSmi(value);
2475 : }
2476 :
2477 : Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value,
2478 0 : graph()->start());
2479 :
2480 0 : Node* ovf = graph()->NewNode(common->Projection(1), add, graph()->start());
2481 : Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf,
2482 0 : graph()->start());
2483 :
2484 0 : Node* if_true = graph()->NewNode(common->IfTrue(), branch);
2485 : Node* vtrue = BuildAllocateHeapNumberWithValue(
2486 0 : graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true);
2487 :
2488 0 : Node* if_false = graph()->NewNode(common->IfFalse(), branch);
2489 0 : Node* vfalse = graph()->NewNode(common->Projection(0), add, if_false);
2490 :
2491 0 : Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false);
2492 : Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
2493 0 : vtrue, vfalse, merge);
2494 0 : return phi;
2495 : }
2496 :
2497 133347 : Node* WasmGraphBuilder::BuildChangeFloat64ToTagged(Node* value) {
2498 44449 : MachineOperatorBuilder* machine = jsgraph()->machine();
2499 44449 : CommonOperatorBuilder* common = jsgraph()->common();
2500 :
2501 44449 : Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value);
2502 : Node* check_same = graph()->NewNode(
2503 : machine->Float64Equal(), value,
2504 88898 : graph()->NewNode(machine->ChangeInt32ToFloat64(), value32));
2505 : Node* branch_same =
2506 44449 : graph()->NewNode(common->Branch(), check_same, graph()->start());
2507 :
2508 44449 : Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same);
2509 : Node* vsmi;
2510 44449 : Node* if_box = graph()->NewNode(common->IfFalse(), branch_same);
2511 : Node* vbox;
2512 :
2513 : // We only need to check for -0 if the {value} can potentially contain -0.
2514 : Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32,
2515 44449 : jsgraph()->Int32Constant(0));
2516 : Node* branch_zero =
2517 44449 : graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi);
2518 :
2519 44449 : Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero);
2520 44449 : Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero);
2521 :
2522 : // In case of 0, we need to check the high bits for the IEEE -0 pattern.
2523 : Node* check_negative = graph()->NewNode(
2524 : machine->Int32LessThan(),
2525 : graph()->NewNode(machine->Float64ExtractHighWord32(), value),
2526 88898 : jsgraph()->Int32Constant(0));
2527 : Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse),
2528 44449 : check_negative, if_zero);
2529 :
2530 44449 : Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative);
2531 44449 : Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative);
2532 :
2533 : // We need to create a box for negative 0.
2534 44449 : if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative);
2535 44449 : if_box = graph()->NewNode(common->Merge(2), if_box, if_negative);
2536 :
2537 : // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
2538 : // machines we need to deal with potential overflow and fallback to boxing.
2539 44449 : if (machine->Is64()) {
2540 44449 : vsmi = BuildChangeInt32ToSmi(value32);
2541 : } else {
2542 : Node* smi_tag = graph()->NewNode(machine->Int32AddWithOverflow(), value32,
2543 0 : value32, if_smi);
2544 :
2545 0 : Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag, if_smi);
2546 : Node* branch_ovf =
2547 0 : graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi);
2548 :
2549 0 : Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf);
2550 0 : if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box);
2551 :
2552 0 : if_smi = graph()->NewNode(common->IfFalse(), branch_ovf);
2553 0 : vsmi = graph()->NewNode(common->Projection(0), smi_tag, if_smi);
2554 : }
2555 :
2556 : // Allocate the box for the {value}.
2557 44449 : vbox = BuildAllocateHeapNumberWithValue(value, if_box);
2558 :
2559 44449 : Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box);
2560 : value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi,
2561 44449 : vbox, control);
2562 44449 : return value;
2563 : }
2564 :
2565 369464 : Node* WasmGraphBuilder::ToJS(Node* node, wasm::ValueType type) {
2566 214658 : switch (type) {
2567 : case wasm::kWasmI32:
2568 28964 : return BuildChangeInt32ToTagged(node);
2569 : case wasm::kWasmS128:
2570 : case wasm::kWasmI64:
2571 0 : UNREACHABLE();
2572 : case wasm::kWasmF32:
2573 : node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
2574 13561 : node);
2575 13561 : return BuildChangeFloat64ToTagged(node);
2576 : case wasm::kWasmF64:
2577 30888 : return BuildChangeFloat64ToTagged(node);
2578 : case wasm::kWasmStmt:
2579 141245 : return jsgraph()->UndefinedConstant();
2580 : default:
2581 0 : UNREACHABLE();
2582 : }
2583 : }
2584 :
2585 347296 : Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* js_context) {
2586 : Callable callable =
2587 86824 : Builtins::CallableFor(jsgraph()->isolate(), Builtins::kToNumber);
2588 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
2589 : jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
2590 173648 : CallDescriptor::kNoFlags, Operator::kNoProperties);
2591 86824 : Node* stub_code = jsgraph()->HeapConstant(callable.code());
2592 :
2593 : Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
2594 173648 : node, js_context, *effect_, *control_);
2595 :
2596 86824 : SetSourcePosition(result, 1);
2597 :
2598 86824 : *effect_ = result;
2599 :
2600 86824 : return result;
2601 : }
2602 :
2603 0 : bool CanCover(Node* value, IrOpcode::Value opcode) {
2604 0 : if (value->opcode() != opcode) return false;
2605 : bool first = true;
2606 0 : for (Edge const edge : value->use_edges()) {
2607 0 : if (NodeProperties::IsControlEdge(edge)) continue;
2608 0 : if (NodeProperties::IsEffectEdge(edge)) continue;
2609 : DCHECK(NodeProperties::IsValueEdge(edge));
2610 0 : if (!first) return false;
2611 : first = false;
2612 : }
2613 0 : return true;
2614 : }
2615 :
2616 260472 : Node* WasmGraphBuilder::BuildChangeTaggedToFloat64(Node* value) {
2617 86824 : MachineOperatorBuilder* machine = jsgraph()->machine();
2618 86824 : CommonOperatorBuilder* common = jsgraph()->common();
2619 :
2620 86824 : Node* check = BuildTestNotSmi(value);
2621 : Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
2622 86824 : graph()->start());
2623 :
2624 86824 : Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
2625 :
2626 : Node* vnot_smi;
2627 : Node* check_undefined = graph()->NewNode(machine->WordEqual(), value,
2628 86824 : jsgraph()->UndefinedConstant());
2629 : Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse),
2630 86824 : check_undefined, if_not_smi);
2631 :
2632 86824 : Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined);
2633 : Node* vundefined =
2634 86824 : jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
2635 :
2636 : Node* if_not_undefined =
2637 86824 : graph()->NewNode(common->IfFalse(), branch_undefined);
2638 86824 : Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined);
2639 :
2640 : if_not_smi =
2641 86824 : graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined);
2642 : vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
2643 86824 : vundefined, vheap_number, if_not_smi);
2644 :
2645 86824 : Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
2646 86824 : Node* vfrom_smi = BuildChangeSmiToFloat64(value);
2647 :
2648 86824 : Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
2649 : Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
2650 86824 : vnot_smi, vfrom_smi, merge);
2651 :
2652 86824 : return phi;
2653 : }
2654 :
2655 86824 : Node* WasmGraphBuilder::FromJS(Node* node, Node* js_context,
2656 130747 : wasm::ValueType type) {
2657 : DCHECK_NE(wasm::kWasmStmt, type);
2658 :
2659 : // Do a JavaScript ToNumber.
2660 86824 : Node* num = BuildJavaScriptToNumber(node, js_context);
2661 :
2662 : // Change representation.
2663 86824 : SimplifiedOperatorBuilder simplified(jsgraph()->zone());
2664 86824 : num = BuildChangeTaggedToFloat64(num);
2665 :
2666 86824 : switch (type) {
2667 : case wasm::kWasmI32: {
2668 : num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
2669 28989 : num);
2670 28989 : break;
2671 : }
2672 : case wasm::kWasmS128:
2673 : case wasm::kWasmI64:
2674 0 : UNREACHABLE();
2675 : case wasm::kWasmF32:
2676 : num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToFloat32(),
2677 14934 : num);
2678 14934 : break;
2679 : case wasm::kWasmF64:
2680 : break;
2681 : default:
2682 0 : UNREACHABLE();
2683 : }
2684 86824 : return num;
2685 : }
2686 :
2687 147065 : Node* WasmGraphBuilder::BuildChangeInt32ToSmi(Node* value) {
2688 147064 : if (jsgraph()->machine()->Is64()) {
2689 73531 : value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value);
2690 : }
2691 : return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
2692 147066 : BuildSmiShiftBitsConstant());
2693 : }
2694 :
2695 264360 : Node* WasmGraphBuilder::BuildChangeSmiToInt32(Node* value) {
2696 : value = graph()->NewNode(jsgraph()->machine()->WordSar(), value,
2697 88120 : BuildSmiShiftBitsConstant());
2698 176240 : if (jsgraph()->machine()->Is64()) {
2699 : value =
2700 88120 : graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value);
2701 : }
2702 88120 : return value;
2703 : }
2704 :
2705 4132 : Node* WasmGraphBuilder::BuildChangeUint32ToSmi(Node* value) {
2706 4132 : if (jsgraph()->machine()->Is64()) {
2707 : value =
2708 2066 : graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), value);
2709 : }
2710 : return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
2711 4132 : BuildSmiShiftBitsConstant());
2712 : }
2713 :
2714 173648 : Node* WasmGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
2715 : return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
2716 260472 : BuildChangeSmiToInt32(value));
2717 : }
2718 :
2719 173648 : Node* WasmGraphBuilder::BuildTestNotSmi(Node* value) {
2720 : STATIC_ASSERT(kSmiTag == 0);
2721 : STATIC_ASSERT(kSmiTagMask == 1);
2722 : return graph()->NewNode(jsgraph()->machine()->WordAnd(), value,
2723 260472 : jsgraph()->IntPtrConstant(kSmiTagMask));
2724 : }
2725 :
2726 163718 : Node* WasmGraphBuilder::BuildSmiShiftBitsConstant() {
2727 163718 : return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
2728 : }
2729 :
2730 44449 : Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
2731 144750 : Node* control) {
2732 44449 : MachineOperatorBuilder* machine = jsgraph()->machine();
2733 44449 : CommonOperatorBuilder* common = jsgraph()->common();
2734 : // The AllocateHeapNumber builtin does not use the js_context, so we can
2735 : // safely pass in Smi zero here.
2736 : Callable callable = Builtins::CallableFor(jsgraph()->isolate(),
2737 44449 : Builtins::kAllocateHeapNumber);
2738 44449 : Node* target = jsgraph()->HeapConstant(callable.code());
2739 : Node* js_context = jsgraph()->NoContextConstant();
2740 : Node* effect =
2741 : graph()->NewNode(common->BeginRegion(RegionObservability::kNotObservable),
2742 44449 : graph()->start());
2743 44449 : if (!allocate_heap_number_operator_.is_set()) {
2744 : CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
2745 : jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
2746 22806 : CallDescriptor::kNoFlags, Operator::kNoThrow);
2747 11403 : allocate_heap_number_operator_.set(common->Call(descriptor));
2748 : }
2749 : Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
2750 : target, js_context, effect, control);
2751 : Node* store =
2752 : graph()->NewNode(machine->Store(StoreRepresentation(
2753 : MachineRepresentation::kFloat64, kNoWriteBarrier)),
2754 : heap_number, BuildHeapNumberValueIndexConstant(), value,
2755 88898 : heap_number, control);
2756 88898 : return graph()->NewNode(common->FinishRegion(), heap_number, store);
2757 : }
2758 :
2759 173648 : Node* WasmGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) {
2760 : return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()),
2761 : value, BuildHeapNumberValueIndexConstant(),
2762 260472 : graph()->start(), control);
2763 : }
2764 :
2765 44449 : Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
2766 131273 : return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
2767 : }
2768 :
2769 160176 : void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
2770 482248 : Address wasm_context_address) {
2771 416729 : const int wasm_count = static_cast<int>(sig_->parameter_count());
2772 : const int count =
2773 160176 : wasm_count + 4; // wasm_code, wasm_context, effect, and control.
2774 160176 : Node** args = Buffer(count);
2775 :
2776 : // Build the start and the JS parameter nodes.
2777 160176 : Node* start = Start(wasm_count + 5);
2778 160176 : *control_ = start;
2779 160176 : *effect_ = start;
2780 :
2781 : // Create the js_context parameter
2782 : Node* js_context = graph()->NewNode(
2783 : jsgraph()->common()->Parameter(
2784 : Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"),
2785 320352 : graph()->start());
2786 :
2787 : // Create the wasm_context node to pass as parameter. This must be a
2788 : // RelocatableIntPtrConstant because JSToWasm wrappers are compiled at module
2789 : // compile time and patched at instance build time.
2790 : DCHECK_NULL(wasm_context_);
2791 : wasm_context_ = jsgraph()->RelocatableIntPtrConstant(
2792 : reinterpret_cast<uintptr_t>(wasm_context_address),
2793 320352 : RelocInfo::WASM_CONTEXT_REFERENCE);
2794 :
2795 160176 : if (!wasm::IsJSCompatibleSignature(sig_)) {
2796 : // Throw a TypeError. Use the js_context of the calling javascript function
2797 : // (passed as a parameter), such that the generated code is js_context
2798 : // independent.
2799 : BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, js_context,
2800 860 : nullptr, 0);
2801 :
2802 : // Add a dummy call to the wasm function so that the generated wrapper
2803 : // contains a reference to the wrapped wasm function. Without this reference
2804 : // the wasm function could not be re-imported into another wasm module.
2805 : int pos = 0;
2806 860 : args[pos++] = HeapConstant(wasm_code);
2807 860 : args[pos++] = wasm_context_;
2808 860 : args[pos++] = *effect_;
2809 860 : args[pos++] = *control_;
2810 :
2811 : // We only need a dummy call descriptor.
2812 : wasm::FunctionSig::Builder dummy_sig_builder(jsgraph()->zone(), 0, 0);
2813 : CallDescriptor* desc =
2814 1720 : GetWasmCallDescriptor(jsgraph()->zone(), dummy_sig_builder.Build());
2815 2580 : *effect_ = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2816 860 : Return(jsgraph()->UndefinedConstant());
2817 160176 : return;
2818 : }
2819 :
2820 : int pos = 0;
2821 159316 : args[pos++] = HeapConstant(wasm_code);
2822 159316 : args[pos++] = wasm_context_;
2823 :
2824 : // Convert JS parameters to wasm numbers.
2825 397798 : for (int i = 0; i < wasm_count; ++i) {
2826 79166 : Node* param = Param(i + 1);
2827 158332 : Node* wasm_param = FromJS(param, js_context, sig_->GetParam(i));
2828 79166 : args[pos++] = wasm_param;
2829 : }
2830 :
2831 : // Set the ThreadInWasm flag before we do the actual call.
2832 159316 : BuildModifyThreadInWasmFlag(true);
2833 :
2834 159316 : args[pos++] = *effect_;
2835 159316 : args[pos++] = *control_;
2836 :
2837 : // Call the wasm code.
2838 318632 : CallDescriptor* desc = GetWasmCallDescriptor(jsgraph()->zone(), sig_);
2839 :
2840 318632 : Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args);
2841 159316 : *effect_ = call;
2842 :
2843 : // Clear the ThreadInWasmFlag
2844 159316 : BuildModifyThreadInWasmFlag(false);
2845 :
2846 : Node* retval = call;
2847 : Node* jsval = ToJS(
2848 477948 : retval, sig_->return_count() == 0 ? wasm::kWasmStmt : sig_->GetReturn());
2849 : Return(jsval);
2850 : }
2851 :
2852 13442 : int WasmGraphBuilder::AddParameterNodes(Node** args, int pos, int param_count,
2853 55342 : wasm::FunctionSig* sig) {
2854 : // Convert wasm numbers to JS values.
2855 82226 : for (int i = 0; i < param_count; ++i) {
2856 55342 : Node* param = Param(i + 1); // Start from index 1 to drop the wasm_context.
2857 110684 : args[pos++] = ToJS(param, sig->GetParam(i));
2858 : }
2859 13442 : return pos;
2860 : }
2861 :
2862 128289 : Node* WasmGraphBuilder::LoadImportDataAtOffset(int offset, Node* table) {
2863 : offset = FixedArray::OffsetOfElementAt(offset) - kHeapObjectTag;
2864 42763 : Node* offset_node = jsgraph()->Int32Constant(offset);
2865 : Node* import_data = graph()->NewNode(
2866 : jsgraph()->machine()->Load(LoadRepresentation::TaggedPointer()), table,
2867 85526 : offset_node, *effect_, *control_);
2868 42763 : *effect_ = import_data;
2869 42763 : return import_data;
2870 : }
2871 :
2872 0 : Node* WasmGraphBuilder::LoadNativeContext(Node* table) {
2873 : // The js_imports_table is set up so that index 0 has isolate->native_context
2874 12391 : return LoadImportDataAtOffset(0, table);
2875 : }
2876 :
2877 0 : int OffsetForImportData(int index, WasmGraphBuilder::ImportDataType type) {
2878 : // The js_imports_table is set up so that index 0 has isolate->native_context
2879 : // and for every index, 3*index+1 has the JSReceiver, 3*index+2 has function's
2880 : // global proxy and 3*index+3 has function's context.
2881 80290 : return 3 * index + type;
2882 : }
2883 :
2884 0 : Node* WasmGraphBuilder::LoadImportData(int index, ImportDataType type,
2885 : Node* table) {
2886 30372 : return LoadImportDataAtOffset(OffsetForImportData(index, type), table);
2887 : }
2888 :
2889 13492 : bool WasmGraphBuilder::BuildWasmToJSWrapper(
2890 : Handle<JSReceiver> target, Handle<FixedArray> global_js_imports_table,
2891 105080 : int index) {
2892 : DCHECK(target->IsCallable());
2893 :
2894 34592 : int wasm_count = static_cast<int>(sig_->parameter_count());
2895 :
2896 : // Build the start and the parameter nodes.
2897 13492 : Isolate* isolate = jsgraph()->isolate();
2898 : CallDescriptor* desc;
2899 13492 : Node* start = Start(wasm_count + 3);
2900 13492 : *effect_ = start;
2901 13492 : *control_ = start;
2902 :
2903 : // We add the target function to a table and look it up during runtime. This
2904 : // ensures that if the GC kicks in, it doesn't need to patch the code for the
2905 : // JS function.
2906 : // js_imports_table is fixed array with global handle scope whose lifetime is
2907 : // tied to the instance.
2908 : // TODO(aseemgarg): explore using per-import global handle instead of a table
2909 : Node* table_ptr = jsgraph()->IntPtrConstant(
2910 26984 : reinterpret_cast<intptr_t>(global_js_imports_table.location()));
2911 : Node* table = graph()->NewNode(
2912 : jsgraph()->machine()->Load(LoadRepresentation::TaggedPointer()),
2913 40476 : table_ptr, jsgraph()->IntPtrConstant(0), *effect_, *control_);
2914 13492 : *effect_ = table;
2915 :
2916 13492 : if (!wasm::IsJSCompatibleSignature(sig_)) {
2917 : // Throw a TypeError.
2918 : Node* native_context = LoadNativeContext(table);
2919 : BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, native_context,
2920 50 : nullptr, 0);
2921 : // We don't need to return a value here, as the runtime call will not return
2922 : // anyway (the c entry stub will trigger stack unwinding).
2923 : ReturnVoid();
2924 50 : return false;
2925 : }
2926 :
2927 13442 : Node** args = Buffer(wasm_count + 7);
2928 :
2929 : Node* call = nullptr;
2930 :
2931 13442 : BuildModifyThreadInWasmFlag(false);
2932 :
2933 13442 : if (target->IsJSFunction()) {
2934 : Handle<JSFunction> function = Handle<JSFunction>::cast(target);
2935 11492 : if (function->shared()->internal_formal_parameter_count() == wasm_count) {
2936 : int pos = 0;
2937 : args[pos++] =
2938 8490 : LoadImportData(index, kFunction, table); // target callable.
2939 : // Receiver.
2940 16930 : if (is_sloppy(function->shared()->language_mode()) &&
2941 : !function->shared()->native()) {
2942 8440 : args[pos++] = LoadImportData(index, kGlobalProxy, table);
2943 : } else {
2944 : args[pos++] = jsgraph()->Constant(
2945 100 : handle(isolate->heap()->undefined_value(), isolate));
2946 : }
2947 :
2948 : desc = Linkage::GetJSCallDescriptor(
2949 16980 : graph()->zone(), false, wasm_count + 1, CallDescriptor::kNoFlags);
2950 :
2951 : // Convert wasm numbers to JS values.
2952 8490 : pos = AddParameterNodes(args, pos, wasm_count, sig_);
2953 :
2954 16980 : args[pos++] = jsgraph()->UndefinedConstant(); // new target
2955 16980 : args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
2956 16980 : args[pos++] = LoadImportData(index, kFunctionContext, table);
2957 8490 : args[pos++] = *effect_;
2958 8490 : args[pos++] = *control_;
2959 :
2960 16980 : call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2961 : }
2962 : }
2963 :
2964 : // We cannot call the target directly, we have to use the Call builtin.
2965 : Node* native_context = nullptr;
2966 13442 : if (!call) {
2967 : int pos = 0;
2968 4952 : Callable callable = CodeFactory::Call(isolate);
2969 4952 : args[pos++] = jsgraph()->HeapConstant(callable.code());
2970 4952 : args[pos++] = LoadImportData(index, kFunction, table); // target callable.
2971 4952 : args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
2972 : args[pos++] = jsgraph()->Constant(
2973 9904 : handle(isolate->heap()->undefined_value(), isolate)); // receiver
2974 :
2975 : desc = Linkage::GetStubCallDescriptor(isolate, graph()->zone(),
2976 : callable.descriptor(), wasm_count + 1,
2977 14856 : CallDescriptor::kNoFlags);
2978 :
2979 : // Convert wasm numbers to JS values.
2980 4952 : pos = AddParameterNodes(args, pos, wasm_count, sig_);
2981 :
2982 : // The native_context is sufficient here, because all kind of callables
2983 : // which depend on the context provide their own context. The context here
2984 : // is only needed if the target is a constructor to throw a TypeError, if
2985 : // the target is a native function, or if the target is a callable JSObject,
2986 : // which can only be constructed by the runtime.
2987 : native_context = LoadNativeContext(table);
2988 4952 : args[pos++] = native_context;
2989 4952 : args[pos++] = *effect_;
2990 4952 : args[pos++] = *control_;
2991 :
2992 9904 : call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2993 : }
2994 :
2995 13442 : *effect_ = call;
2996 13442 : SetSourcePosition(call, 0);
2997 :
2998 13442 : BuildModifyThreadInWasmFlag(true);
2999 :
3000 : // Convert the return value back.
3001 13442 : Node* val = sig_->return_count() == 0
3002 : ? jsgraph()->Int32Constant(0)
3003 : : FromJS(call,
3004 : native_context != nullptr ? native_context
3005 : : LoadNativeContext(table),
3006 34542 : sig_->GetReturn());
3007 : Return(val);
3008 13442 : return true;
3009 : }
3010 :
3011 : namespace {
3012 : bool HasInt64ParamOrReturn(wasm::FunctionSig* sig) {
3013 741918 : for (auto type : sig->all()) {
3014 375623 : if (type == wasm::kWasmI64) return true;
3015 : }
3016 : return false;
3017 : }
3018 : } // namespace
3019 :
3020 135895 : void WasmGraphBuilder::BuildWasmToWasmWrapper(Handle<Code> target,
3021 679475 : Address new_context_address) {
3022 135895 : int wasm_count = static_cast<int>(sig_->parameter_count());
3023 135895 : int count = wasm_count + 4; // wasm_code, wasm_context, effect, and control.
3024 135895 : Node** args = Buffer(count);
3025 :
3026 : // Build the start node.
3027 135895 : Node* start = Start(count + 1);
3028 135895 : *control_ = start;
3029 135895 : *effect_ = start;
3030 :
3031 : int pos = 0;
3032 : // Add the wasm code target.
3033 135895 : args[pos++] = jsgraph()->HeapConstant(target);
3034 : // Add the wasm_context of the other instance.
3035 : args[pos++] = jsgraph()->IntPtrConstant(
3036 271790 : reinterpret_cast<uintptr_t>(new_context_address));
3037 : // Add the parameters starting from index 1 since the parameter with index 0
3038 : // is the old wasm_context.
3039 521190 : for (int i = 0; i < wasm_count; ++i) {
3040 249400 : args[pos++] = Param(i + 1);
3041 : }
3042 135895 : args[pos++] = *effect_;
3043 135895 : args[pos++] = *control_;
3044 :
3045 : // Tail-call the wasm code.
3046 271790 : CallDescriptor* desc = GetWasmCallDescriptor(jsgraph()->zone(), sig_, true);
3047 : Node* tail_call =
3048 271790 : graph()->NewNode(jsgraph()->common()->TailCall(desc), count, args);
3049 135895 : MergeControlToEnd(jsgraph(), tail_call);
3050 135895 : }
3051 :
3052 1125 : void WasmGraphBuilder::BuildWasmInterpreterEntry(
3053 4293 : uint32_t func_index, Handle<WasmInstanceObject> instance) {
3054 4191 : int param_count = static_cast<int>(sig_->parameter_count());
3055 :
3056 : // Build the start and the parameter nodes.
3057 1125 : Node* start = Start(param_count + 3);
3058 1125 : *effect_ = start;
3059 1125 : *control_ = start;
3060 :
3061 : // Compute size for the argument buffer.
3062 1125 : int args_size_bytes = 0;
3063 3273 : for (wasm::ValueType type : sig_->parameters()) {
3064 1023 : args_size_bytes += 1 << ElementSizeLog2Of(type);
3065 : }
3066 :
3067 : // The return value is also passed via this buffer:
3068 : DCHECK_GE(wasm::kV8MaxWasmFunctionReturns, sig_->return_count());
3069 : // TODO(wasm): Handle multi-value returns.
3070 : DCHECK_EQ(1, wasm::kV8MaxWasmFunctionReturns);
3071 : int return_size_bytes =
3072 2043 : sig_->return_count() == 0 ? 0 : 1 << ElementSizeLog2Of(sig_->GetReturn());
3073 :
3074 : // Get a stack slot for the arguments.
3075 : Node* arg_buffer =
3076 1125 : args_size_bytes == 0 && return_size_bytes == 0
3077 : ? jsgraph()->IntPtrConstant(0)
3078 : : graph()->NewNode(jsgraph()->machine()->StackSlot(
3079 3279 : std::max(args_size_bytes, return_size_bytes), 8));
3080 :
3081 : // Now store all our arguments to the buffer.
3082 : int offset = 0;
3083 :
3084 3273 : for (int i = 0; i < param_count; ++i) {
3085 1023 : wasm::ValueType type = sig_->GetParam(i);
3086 : // Start from the parameter with index 1 to drop the wasm_context.
3087 : *effect_ = graph()->NewNode(GetSafeStoreOperator(offset, type), arg_buffer,
3088 1023 : Int32Constant(offset), Param(i + 1), *effect_,
3089 4092 : *control_);
3090 1023 : offset += 1 << ElementSizeLog2Of(type);
3091 : }
3092 : DCHECK_EQ(args_size_bytes, offset);
3093 :
3094 : // We are passing the raw arg_buffer here. To the GC and other parts, it looks
3095 : // like a Smi (lowest bit not set). In the runtime function however, don't
3096 : // call Smi::value on it, but just cast it to a byte pointer.
3097 : Node* parameters[] = {
3098 2250 : jsgraph()->HeapConstant(instance), // wasm instance
3099 1125 : jsgraph()->SmiConstant(func_index), // function index
3100 : arg_buffer, // argument buffer
3101 2250 : };
3102 : BuildCallToRuntime(Runtime::kWasmRunInterpreter, parameters,
3103 1125 : arraysize(parameters));
3104 :
3105 : // Read back the return value.
3106 2250 : if (sig_->return_count() == 0) {
3107 : Return(Int32Constant(0));
3108 : } else {
3109 : // TODO(wasm): Implement multi-return.
3110 : DCHECK_EQ(1, sig_->return_count());
3111 918 : MachineType load_rep = wasm::WasmOpcodes::MachineTypeFor(sig_->GetReturn());
3112 : Node* val =
3113 : graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer,
3114 1836 : Int32Constant(0), *effect_, *control_);
3115 : Return(val);
3116 : }
3117 :
3118 2250 : if (HasInt64ParamOrReturn(sig_)) LowerInt64();
3119 1125 : }
3120 :
3121 672 : void WasmGraphBuilder::BuildCWasmEntry(Address wasm_context_address) {
3122 : // Build the start and the JS parameter nodes.
3123 96 : Node* start = Start(CWasmEntryParameters::kNumParameters + 5);
3124 96 : *control_ = start;
3125 96 : *effect_ = start;
3126 :
3127 : // Create the wasm_context node to pass as parameter.
3128 : DCHECK_NULL(wasm_context_);
3129 : wasm_context_ = jsgraph()->IntPtrConstant(
3130 192 : reinterpret_cast<uintptr_t>(wasm_context_address));
3131 :
3132 : // Create parameter nodes (offset by 1 for the receiver parameter).
3133 96 : Node* code_obj = Param(CWasmEntryParameters::kCodeObject + 1);
3134 96 : Node* arg_buffer = Param(CWasmEntryParameters::kArgumentsBuffer + 1);
3135 :
3136 288 : int wasm_arg_count = static_cast<int>(sig_->parameter_count());
3137 96 : int arg_count = wasm_arg_count + 4; // code, wasm_context, control, effect
3138 96 : Node** args = Buffer(arg_count);
3139 :
3140 : int pos = 0;
3141 96 : args[pos++] = code_obj;
3142 96 : args[pos++] = wasm_context_;
3143 :
3144 : int offset = 0;
3145 312 : for (wasm::ValueType type : sig_->parameters()) {
3146 : Node* arg_load =
3147 : graph()->NewNode(GetSafeLoadOperator(offset, type), arg_buffer,
3148 240 : Int32Constant(offset), *effect_, *control_);
3149 120 : *effect_ = arg_load;
3150 120 : args[pos++] = arg_load;
3151 120 : offset += 1 << ElementSizeLog2Of(type);
3152 : }
3153 :
3154 96 : args[pos++] = *effect_;
3155 96 : args[pos++] = *control_;
3156 : DCHECK_EQ(arg_count, pos);
3157 :
3158 : // Call the wasm code.
3159 192 : CallDescriptor* desc = GetWasmCallDescriptor(jsgraph()->zone(), sig_);
3160 :
3161 : Node* call =
3162 192 : graph()->NewNode(jsgraph()->common()->Call(desc), arg_count, args);
3163 96 : *effect_ = call;
3164 :
3165 : // Store the return value.
3166 : DCHECK_GE(1, sig_->return_count());
3167 192 : if (sig_->return_count() == 1) {
3168 : StoreRepresentation store_rep(sig_->GetReturn(), kNoWriteBarrier);
3169 : Node* store =
3170 : graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer,
3171 192 : Int32Constant(0), call, *effect_, *control_);
3172 96 : *effect_ = store;
3173 : }
3174 : Return(jsgraph()->SmiConstant(0));
3175 :
3176 192 : if (jsgraph()->machine()->Is32() && HasInt64ParamOrReturn(sig_)) {
3177 : MachineRepresentation sig_reps[] = {
3178 : MachineRepresentation::kWord32, // return value
3179 : MachineRepresentation::kTagged, // receiver
3180 : MachineRepresentation::kTagged, // arg0 (code)
3181 : MachineRepresentation::kTagged // arg1 (buffer)
3182 0 : };
3183 : wasm::FunctionSig c_entry_sig(1, 2, sig_reps);
3184 : Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(),
3185 0 : jsgraph()->common(), jsgraph()->zone(), &c_entry_sig);
3186 0 : r.LowerGraph();
3187 : }
3188 96 : }
3189 :
3190 : // This function is used by WasmFullDecoder to create a node that loads the
3191 : // {mem_start} variable from the WasmContext. It should not be used directly by
3192 : // the WasmGraphBuilder. The WasmGraphBuilder should directly use {mem_start_},
3193 : // which will always contain the correct node (stored in the SsaEnv).
3194 1233891 : Node* WasmGraphBuilder::LoadMemStart() {
3195 : DCHECK_NOT_NULL(wasm_context_);
3196 : Node* mem_buffer = graph()->NewNode(
3197 : jsgraph()->machine()->Load(MachineType::UintPtr()), wasm_context_,
3198 : jsgraph()->Int32Constant(
3199 : static_cast<int32_t>(offsetof(WasmContext, mem_start))),
3200 1233891 : *effect_, *control_);
3201 411370 : *effect_ = mem_buffer;
3202 411370 : return mem_buffer;
3203 : }
3204 :
3205 : // This function is used by WasmFullDecoder to create a node that loads the
3206 : // {mem_size} variable from the WasmContext. It should not be used directly by
3207 : // the WasmGraphBuilder. The WasmGraphBuilder should directly use {mem_size_},
3208 : // which will always contain the correct node (stored in the SsaEnv).
3209 1645286 : Node* WasmGraphBuilder::LoadMemSize() {
3210 : // Load mem_size from the WasmContext at runtime.
3211 : DCHECK_NOT_NULL(wasm_context_);
3212 : Node* mem_size = graph()->NewNode(
3213 : jsgraph()->machine()->Load(MachineType::Uint32()), wasm_context_,
3214 : jsgraph()->Int32Constant(
3215 : static_cast<int32_t>(offsetof(WasmContext, mem_size))),
3216 1233929 : *effect_, *control_);
3217 411357 : *effect_ = mem_size;
3218 822714 : if (jsgraph()->machine()->Is64()) {
3219 : mem_size = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(),
3220 411308 : mem_size);
3221 : }
3222 411367 : return mem_size;
3223 : }
3224 :
3225 31608 : void WasmGraphBuilder::GetGlobalBaseAndOffset(MachineType mem_type,
3226 : uint32_t offset, Node** base_node,
3227 36651 : Node** offset_node) {
3228 : DCHECK_NOT_NULL(wasm_context_);
3229 31608 : if (globals_start_ == nullptr) {
3230 : // Load globals_start from the WasmContext at runtime.
3231 : // TODO(wasm): we currently generate only one load of the {globals_start}
3232 : // start per graph, which means it can be placed anywhere by the scheduler.
3233 : // This is legal because the globals_start should never change.
3234 : // However, in some cases (e.g. if the WasmContext is already in a
3235 : // register), it is slightly more efficient to reload this value from the
3236 : // WasmContext. Since this depends on register allocation, it is not
3237 : // possible to express in the graph, and would essentially constitute a
3238 : // "mem2reg" optimization in TurboFan.
3239 : globals_start_ = graph()->NewNode(
3240 : jsgraph()->machine()->Load(MachineType::UintPtr()), wasm_context_,
3241 : jsgraph()->Int32Constant(
3242 : static_cast<int32_t>(offsetof(WasmContext, globals_start))),
3243 14261 : graph()->start(), graph()->start());
3244 : }
3245 31609 : *base_node = globals_start_;
3246 63218 : *offset_node = jsgraph()->Int32Constant(offset);
3247 :
3248 31607 : if (mem_type == MachineType::Simd128() && offset != 0) {
3249 : // TODO(titzer,bbudge): code generation for SIMD memory offsets is broken.
3250 : *base_node =
3251 : graph()->NewNode(kPointerSize == 4 ? jsgraph()->machine()->Int32Add()
3252 : : jsgraph()->machine()->Int64Add(),
3253 432 : *base_node, *offset_node);
3254 144 : *offset_node = jsgraph()->Int32Constant(0);
3255 : }
3256 31607 : }
3257 :
3258 98396 : Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
3259 : DCHECK_NOT_NULL(*mem_start_);
3260 48144 : if (offset == 0) return *mem_start_;
3261 : return graph()->NewNode(jsgraph()->machine()->IntAdd(), *mem_start_,
3262 100504 : jsgraph()->IntPtrConstant(offset));
3263 : }
3264 :
3265 2272 : Node* WasmGraphBuilder::CurrentMemoryPages() {
3266 : // CurrentMemoryPages can not be called from asm.js.
3267 : DCHECK_EQ(wasm::kWasmOrigin, env_->module->origin());
3268 : DCHECK_NOT_NULL(*mem_size_);
3269 568 : Node* mem_size = *mem_size_;
3270 1136 : if (jsgraph()->machine()->Is64()) {
3271 : mem_size = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
3272 568 : mem_size);
3273 : }
3274 : return graph()->NewNode(
3275 : jsgraph()->machine()->Word32Shr(), mem_size,
3276 2272 : jsgraph()->Int32Constant(WhichPowerOf2(wasm::WasmModule::kPageSize)));
3277 : }
3278 :
3279 10259 : void WasmGraphBuilder::EnsureFunctionTableNodes() {
3280 9870 : if (function_tables_.size() > 0) return;
3281 4646 : size_t tables_size = env_->function_tables.size();
3282 4646 : for (size_t i = 0; i < tables_size; ++i) {
3283 : wasm::GlobalHandleAddress function_handle_address =
3284 4646 : env_->function_tables[i];
3285 : wasm::GlobalHandleAddress signature_handle_address =
3286 4646 : env_->signature_tables[i];
3287 : function_tables_.push_back(jsgraph()->RelocatableIntPtrConstant(
3288 : reinterpret_cast<intptr_t>(function_handle_address),
3289 6969 : RelocInfo::WASM_GLOBAL_HANDLE));
3290 : signature_tables_.push_back(jsgraph()->RelocatableIntPtrConstant(
3291 : reinterpret_cast<intptr_t>(signature_handle_address),
3292 6969 : RelocInfo::WASM_GLOBAL_HANDLE));
3293 4646 : uint32_t table_size = env_->module->function_tables[i].initial_size;
3294 : function_table_sizes_.push_back(jsgraph()->RelocatableInt32Constant(
3295 : static_cast<uint32_t>(table_size),
3296 6969 : RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE));
3297 : }
3298 : }
3299 :
3300 452868 : Node* WasmGraphBuilder::BuildModifyThreadInWasmFlag(bool new_value) {
3301 : // TODO(eholk): generate code to modify the thread-local storage directly,
3302 : // rather than calling the runtime.
3303 345516 : if (!trap_handler::UseTrapHandler()) {
3304 309732 : return *control_;
3305 : }
3306 :
3307 : // Using two functions instead of taking the new value as a parameter saves
3308 : // one instruction on each call to set up the parameter.
3309 : ExternalReference ref =
3310 : new_value ? ExternalReference::wasm_set_thread_in_wasm_flag(
3311 17892 : jsgraph()->isolate())
3312 : : ExternalReference::wasm_clear_thread_in_wasm_flag(
3313 71568 : jsgraph()->isolate());
3314 : MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 0);
3315 : return BuildCCall(
3316 : sig_builder.Build(),
3317 71568 : graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)));
3318 : }
3319 :
3320 : // Only call this function for code which is not reused across instantiations,
3321 : // as we do not patch the embedded js_context.
3322 4018 : Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f,
3323 : Node* js_context,
3324 : Node** parameters,
3325 24120 : int parameter_count) {
3326 4018 : const Runtime::Function* fun = Runtime::FunctionForId(f);
3327 : CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
3328 : jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
3329 8038 : CallDescriptor::kNoFlags);
3330 : // CEntryStubConstant nodes have to be created and cached in the main
3331 : // thread. At the moment this is only done for CEntryStubConstant(1).
3332 : DCHECK_EQ(1, fun->result_size);
3333 : // At the moment we only allow 4 parameters. If more parameters are needed,
3334 : // increase this constant accordingly.
3335 : static const int kMaxParams = 4;
3336 : DCHECK_GE(kMaxParams, parameter_count);
3337 : Node* inputs[kMaxParams + 6];
3338 : int count = 0;
3339 4021 : inputs[count++] = centry_stub_node_;
3340 9702 : for (int i = 0; i < parameter_count; i++) {
3341 5681 : inputs[count++] = parameters[i];
3342 : }
3343 4021 : inputs[count++] = jsgraph()->ExternalConstant(
3344 8041 : ExternalReference(f, jsgraph()->isolate())); // ref
3345 8040 : inputs[count++] = jsgraph()->Int32Constant(fun->nargs); // arity
3346 4020 : inputs[count++] = js_context; // js_context
3347 4020 : inputs[count++] = *effect_;
3348 4020 : inputs[count++] = *control_;
3349 :
3350 : Node* node = jsgraph()->graph()->NewNode(jsgraph()->common()->Call(desc),
3351 8040 : count, inputs);
3352 4021 : *effect_ = node;
3353 :
3354 4021 : return node;
3355 : }
3356 :
3357 3108 : Node* WasmGraphBuilder::BuildCallToRuntime(Runtime::FunctionId f,
3358 : Node** parameters,
3359 3108 : int parameter_count) {
3360 : return BuildCallToRuntimeWithContext(f, jsgraph()->NoContextConstant(),
3361 3110 : parameters, parameter_count);
3362 : }
3363 :
3364 39324 : Node* WasmGraphBuilder::GetGlobal(uint32_t index) {
3365 : MachineType mem_type =
3366 58983 : wasm::WasmOpcodes::MachineTypeFor(env_->module->globals[index].type);
3367 19661 : Node* base = nullptr;
3368 19661 : Node* offset = nullptr;
3369 19661 : GetGlobalBaseAndOffset(mem_type, env_->module->globals[index].offset, &base,
3370 19661 : &offset);
3371 : Node* node = graph()->NewNode(jsgraph()->machine()->Load(mem_type), base,
3372 39326 : offset, *effect_, *control_);
3373 19662 : *effect_ = node;
3374 19662 : return node;
3375 : }
3376 :
3377 23891 : Node* WasmGraphBuilder::SetGlobal(uint32_t index, Node* val) {
3378 : MachineType mem_type =
3379 35836 : wasm::WasmOpcodes::MachineTypeFor(env_->module->globals[index].type);
3380 11946 : Node* base = nullptr;
3381 11946 : Node* offset = nullptr;
3382 11946 : GetGlobalBaseAndOffset(mem_type, env_->module->globals[index].offset, &base,
3383 11946 : &offset);
3384 : const Operator* op = jsgraph()->machine()->Store(
3385 23892 : StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
3386 11945 : Node* node = graph()->NewNode(op, base, offset, val, *effect_, *control_);
3387 11945 : *effect_ = node;
3388 11945 : return node;
3389 : }
3390 :
3391 85691 : void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
3392 : uint32_t offset,
3393 161496 : wasm::WasmCodePosition position) {
3394 42843 : if (FLAG_wasm_no_bounds_checks) return;
3395 : DCHECK_NOT_NULL(*mem_size_);
3396 :
3397 42848 : uint32_t min_size = env_->module->initial_pages * wasm::WasmModule::kPageSize;
3398 : uint32_t max_size =
3399 : (env_->module->has_maximum_pages ? env_->module->maximum_pages
3400 : : wasm::kV8MaxWasmMemoryPages) *
3401 42848 : wasm::WasmModule::kPageSize;
3402 :
3403 : byte access_size = wasm::WasmOpcodes::MemSize(memtype);
3404 :
3405 42850 : if (access_size > max_size || offset > max_size - access_size) {
3406 : // The access will be out of bounds, even for the largest memory.
3407 : TrapIfEq32(wasm::kTrapMemOutOfBounds, jsgraph()->Int32Constant(0), 0,
3408 42 : position);
3409 47 : return;
3410 : }
3411 42808 : uint32_t end_offset = offset + access_size;
3412 :
3413 42808 : if (end_offset > min_size) {
3414 : // The end offset is larger than the smallest memory.
3415 : // Dynamically check the end offset against the actual memory size, which
3416 : // is not known at compile time.
3417 : Node* cond;
3418 33196 : if (jsgraph()->machine()->Is32()) {
3419 : cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(),
3420 0 : jsgraph()->Int32Constant(end_offset), *mem_size_);
3421 : } else {
3422 : cond = graph()->NewNode(
3423 : jsgraph()->machine()->Uint64LessThanOrEqual(),
3424 : jsgraph()->Int64Constant(static_cast<int64_t>(end_offset)),
3425 33194 : *mem_size_);
3426 : }
3427 16597 : TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
3428 : } else {
3429 : // The end offset is within the bounds of the smallest memory, so only
3430 : // one check is required. Check to see if the index is also a constant.
3431 : UintPtrMatcher m(index);
3432 26210 : if (m.HasValue()) {
3433 : uint64_t index_val = m.Value();
3434 52 : if ((index_val + offset + access_size) <= min_size) {
3435 : // The input index is a constant and everything is statically within
3436 : // bounds of the smallest possible memory.
3437 : return;
3438 : }
3439 : }
3440 : }
3441 :
3442 : Node* effective_size;
3443 85508 : if (jsgraph()->machine()->Is32()) {
3444 : effective_size =
3445 : graph()->NewNode(jsgraph()->machine()->Int32Sub(), *mem_size_,
3446 0 : jsgraph()->Int32Constant(end_offset - 1));
3447 : } else {
3448 : effective_size = graph()->NewNode(
3449 : jsgraph()->machine()->Int64Sub(), *mem_size_,
3450 85509 : jsgraph()->Int64Constant(static_cast<int64_t>(end_offset - 1)));
3451 : }
3452 :
3453 42751 : const Operator* less = jsgraph()->machine()->Is32()
3454 : ? jsgraph()->machine()->Uint32LessThan()
3455 42751 : : jsgraph()->machine()->Uint64LessThan();
3456 :
3457 : Node* cond = graph()->NewNode(less, index, effective_size);
3458 42755 : TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
3459 : }
3460 :
3461 120 : const Operator* WasmGraphBuilder::GetSafeLoadOperator(int offset,
3462 126 : wasm::ValueType type) {
3463 120 : int alignment = offset % (1 << ElementSizeLog2Of(type));
3464 120 : MachineType mach_type = wasm::WasmOpcodes::MachineTypeFor(type);
3465 132 : if (alignment == 0 || jsgraph()->machine()->UnalignedLoadSupported(type)) {
3466 120 : return jsgraph()->machine()->Load(mach_type);
3467 : }
3468 0 : return jsgraph()->machine()->UnalignedLoad(mach_type);
3469 : }
3470 :
3471 1023 : const Operator* WasmGraphBuilder::GetSafeStoreOperator(int offset,
3472 1039 : wasm::ValueType type) {
3473 1023 : int alignment = offset % (1 << ElementSizeLog2Of(type));
3474 1055 : if (alignment == 0 || jsgraph()->machine()->UnalignedStoreSupported(type)) {
3475 : StoreRepresentation rep(type, WriteBarrierKind::kNoWriteBarrier);
3476 1023 : return jsgraph()->machine()->Store(rep);
3477 : }
3478 : UnalignedStoreRepresentation rep(type);
3479 0 : return jsgraph()->machine()->UnalignedStore(rep);
3480 : }
3481 :
3482 55 : Node* WasmGraphBuilder::TraceMemoryOperation(bool is_store,
3483 : MachineRepresentation rep,
3484 : Node* index, uint32_t offset,
3485 293 : wasm::WasmCodePosition position) {
3486 : Node* address = graph()->NewNode(jsgraph()->machine()->Int32Add(),
3487 112 : Int32Constant(offset), index);
3488 : Node* addr_low = BuildChangeInt32ToSmi(graph()->NewNode(
3489 117 : jsgraph()->machine()->Word32And(), address, Int32Constant(0xffff)));
3490 : Node* addr_high = BuildChangeInt32ToSmi(graph()->NewNode(
3491 118 : jsgraph()->machine()->Word32Shr(), address, Int32Constant(16)));
3492 : int32_t rep_i = static_cast<int32_t>(rep);
3493 : Node* params[] = {
3494 60 : jsgraph()->SmiConstant(is_store), // is_store
3495 : jsgraph()->SmiConstant(rep_i), // mem rep
3496 : addr_low, // address lower half word
3497 : addr_high // address higher half word
3498 119 : };
3499 : Node* call =
3500 59 : BuildCallToRuntime(Runtime::kWasmTraceMemory, params, arraysize(params));
3501 59 : SetSourcePosition(call, position);
3502 60 : return call;
3503 : }
3504 :
3505 33073 : Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype,
3506 : Node* index, uint32_t offset,
3507 : uint32_t alignment,
3508 95579 : wasm::WasmCodePosition position) {
3509 : Node* load;
3510 :
3511 66146 : if (jsgraph()->machine()->Is64()) {
3512 : index =
3513 33076 : graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
3514 : }
3515 : // Wasm semantics throw on OOB. Introduce explicit bounds check.
3516 33076 : if (!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED) {
3517 29313 : BoundsCheckMem(memtype, index, offset, position);
3518 : }
3519 :
3520 62219 : if (memtype.representation() == MachineRepresentation::kWord8 ||
3521 29137 : jsgraph()->machine()->UnalignedLoadSupported(memtype.representation())) {
3522 33082 : if (trap_handler::UseTrapHandler()) {
3523 : load = graph()->NewNode(jsgraph()->machine()->ProtectedLoad(memtype),
3524 7528 : MemBuffer(offset), index, *effect_, *control_);
3525 3766 : SetSourcePosition(load, position);
3526 : } else {
3527 : load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
3528 58631 : MemBuffer(offset), index, *effect_, *control_);
3529 : }
3530 : } else {
3531 : // TODO(eholk): Support unaligned loads with trap handlers.
3532 : DCHECK(!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED);
3533 : load = graph()->NewNode(jsgraph()->machine()->UnalignedLoad(memtype),
3534 0 : MemBuffer(offset), index, *effect_, *control_);
3535 : }
3536 :
3537 33086 : *effect_ = load;
3538 :
3539 : #if defined(V8_TARGET_BIG_ENDIAN)
3540 : load = BuildChangeEndiannessLoad(load, memtype, type);
3541 : #endif
3542 :
3543 45809 : if (type == wasm::kWasmI64 &&
3544 12726 : ElementSizeLog2Of(memtype.representation()) < 3) {
3545 : // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes.
3546 292 : if (memtype.IsSigned()) {
3547 : // sign extend
3548 182 : load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
3549 : } else {
3550 : // zero extend
3551 : load =
3552 110 : graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load);
3553 : }
3554 : }
3555 :
3556 33083 : if (FLAG_wasm_trace_memory) {
3557 : TraceMemoryOperation(false, memtype.representation(), index, offset,
3558 34 : position);
3559 : }
3560 :
3561 33085 : return load;
3562 : }
3563 :
3564 14561 : Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
3565 : uint32_t offset, uint32_t alignment, Node* val,
3566 : wasm::WasmCodePosition position,
3567 43052 : wasm::ValueType type) {
3568 : Node* store;
3569 :
3570 29122 : if (jsgraph()->machine()->Is64()) {
3571 : index =
3572 14563 : graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
3573 : }
3574 : // Wasm semantics throw on OOB. Introduce explicit bounds check.
3575 14564 : if (!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED) {
3576 13028 : BoundsCheckMem(memtype, index, offset, position);
3577 : }
3578 :
3579 : #if defined(V8_TARGET_BIG_ENDIAN)
3580 : val = BuildChangeEndiannessStore(val, memtype, type);
3581 : #endif
3582 :
3583 28494 : if (memtype.representation() == MachineRepresentation::kWord8 ||
3584 13924 : jsgraph()->machine()->UnalignedStoreSupported(memtype.representation())) {
3585 14570 : if (FLAG_wasm_trap_handler && V8_TRAP_HANDLER_SUPPORTED) {
3586 : store = graph()->NewNode(
3587 : jsgraph()->machine()->ProtectedStore(memtype.representation()),
3588 3070 : MemBuffer(offset), index, val, *effect_, *control_);
3589 1535 : SetSourcePosition(store, position);
3590 : } else {
3591 : StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
3592 : store =
3593 : graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
3594 26067 : index, val, *effect_, *control_);
3595 : }
3596 : } else {
3597 : // TODO(eholk): Support unaligned stores with trap handlers.
3598 : DCHECK(!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED);
3599 : UnalignedStoreRepresentation rep(memtype.representation());
3600 : store =
3601 : graph()->NewNode(jsgraph()->machine()->UnalignedStore(rep),
3602 0 : MemBuffer(offset), index, val, *effect_, *control_);
3603 : }
3604 :
3605 14566 : *effect_ = store;
3606 :
3607 14566 : if (FLAG_wasm_trace_memory) {
3608 : TraceMemoryOperation(true, memtype.representation(), index, offset,
3609 23 : position);
3610 : }
3611 :
3612 14567 : return store;
3613 : }
3614 :
3615 151750 : Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) {
3616 : // TODO(turbofan): fold bounds checks for constant asm.js loads.
3617 : // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
3618 : DCHECK_NOT_NULL(*mem_size_);
3619 : DCHECK_NOT_NULL(*mem_start_);
3620 151750 : if (jsgraph()->machine()->Is64()) {
3621 : index =
3622 75875 : graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
3623 : }
3624 75875 : const Operator* op = jsgraph()->machine()->CheckedLoad(type);
3625 : Node* load =
3626 75875 : graph()->NewNode(op, *mem_start_, index, *mem_size_, *effect_, *control_);
3627 75875 : *effect_ = load;
3628 75875 : return load;
3629 : }
3630 :
3631 53998 : Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index,
3632 107996 : Node* val) {
3633 : // TODO(turbofan): fold bounds checks for constant asm.js stores.
3634 : // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
3635 : DCHECK_NOT_NULL(*mem_size_);
3636 : DCHECK_NOT_NULL(*mem_start_);
3637 107996 : if (jsgraph()->machine()->Is64()) {
3638 : index =
3639 53998 : graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
3640 : }
3641 : const Operator* op =
3642 107996 : jsgraph()->machine()->CheckedStore(type.representation());
3643 : Node* store = graph()->NewNode(op, *mem_start_, index, *mem_size_, val,
3644 53998 : *effect_, *control_);
3645 53998 : *effect_ = store;
3646 53998 : return val;
3647 : }
3648 :
3649 0 : void WasmGraphBuilder::PrintDebugName(Node* node) {
3650 0 : PrintF("#%d:%s", node->id(), node->op()->mnemonic());
3651 0 : }
3652 :
3653 0 : Node* WasmGraphBuilder::String(const char* string) {
3654 : return jsgraph()->Constant(
3655 0 : jsgraph()->isolate()->factory()->NewStringFromAsciiChecked(string));
3656 : }
3657 :
3658 12331108 : Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
3659 :
3660 238008 : void WasmGraphBuilder::LowerInt64() {
3661 714024 : if (jsgraph()->machine()->Is64()) return;
3662 : Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(), jsgraph()->common(),
3663 0 : jsgraph()->zone(), sig_);
3664 0 : r.LowerGraph();
3665 : }
3666 :
3667 0 : void WasmGraphBuilder::SimdScalarLoweringForTesting() {
3668 0 : SimdScalarLowering(jsgraph(), sig_).LowerGraph();
3669 0 : }
3670 :
3671 635962 : void WasmGraphBuilder::SetSourcePosition(Node* node,
3672 : wasm::WasmCodePosition position) {
3673 : DCHECK_NE(position, wasm::kNoCodePosition);
3674 635962 : if (source_position_table_)
3675 541298 : source_position_table_->SetSourcePosition(node, SourcePosition(position));
3676 635986 : }
3677 :
3678 1992 : Node* WasmGraphBuilder::S128Zero() {
3679 996 : has_simd_ = true;
3680 1992 : return graph()->NewNode(jsgraph()->machine()->S128Zero());
3681 : }
3682 :
3683 5388 : Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
3684 2694 : has_simd_ = true;
3685 2694 : switch (opcode) {
3686 : case wasm::kExprF32x4Splat:
3687 0 : return graph()->NewNode(jsgraph()->machine()->F32x4Splat(), inputs[0]);
3688 : case wasm::kExprF32x4SConvertI32x4:
3689 : return graph()->NewNode(jsgraph()->machine()->F32x4SConvertI32x4(),
3690 0 : inputs[0]);
3691 : case wasm::kExprF32x4UConvertI32x4:
3692 : return graph()->NewNode(jsgraph()->machine()->F32x4UConvertI32x4(),
3693 0 : inputs[0]);
3694 : case wasm::kExprF32x4Abs:
3695 0 : return graph()->NewNode(jsgraph()->machine()->F32x4Abs(), inputs[0]);
3696 : case wasm::kExprF32x4Neg:
3697 0 : return graph()->NewNode(jsgraph()->machine()->F32x4Neg(), inputs[0]);
3698 : case wasm::kExprF32x4RecipApprox:
3699 : return graph()->NewNode(jsgraph()->machine()->F32x4RecipApprox(),
3700 0 : inputs[0]);
3701 : case wasm::kExprF32x4RecipSqrtApprox:
3702 : return graph()->NewNode(jsgraph()->machine()->F32x4RecipSqrtApprox(),
3703 0 : inputs[0]);
3704 : case wasm::kExprF32x4Add:
3705 : return graph()->NewNode(jsgraph()->machine()->F32x4Add(), inputs[0],
3706 0 : inputs[1]);
3707 : case wasm::kExprF32x4AddHoriz:
3708 : return graph()->NewNode(jsgraph()->machine()->F32x4AddHoriz(), inputs[0],
3709 0 : inputs[1]);
3710 : case wasm::kExprF32x4Sub:
3711 : return graph()->NewNode(jsgraph()->machine()->F32x4Sub(), inputs[0],
3712 0 : inputs[1]);
3713 : case wasm::kExprF32x4Mul:
3714 : return graph()->NewNode(jsgraph()->machine()->F32x4Mul(), inputs[0],
3715 0 : inputs[1]);
3716 : case wasm::kExprF32x4Min:
3717 : return graph()->NewNode(jsgraph()->machine()->F32x4Min(), inputs[0],
3718 0 : inputs[1]);
3719 : case wasm::kExprF32x4Max:
3720 : return graph()->NewNode(jsgraph()->machine()->F32x4Max(), inputs[0],
3721 0 : inputs[1]);
3722 : case wasm::kExprF32x4Eq:
3723 : return graph()->NewNode(jsgraph()->machine()->F32x4Eq(), inputs[0],
3724 0 : inputs[1]);
3725 : case wasm::kExprF32x4Ne:
3726 : return graph()->NewNode(jsgraph()->machine()->F32x4Ne(), inputs[0],
3727 0 : inputs[1]);
3728 : case wasm::kExprF32x4Lt:
3729 : return graph()->NewNode(jsgraph()->machine()->F32x4Lt(), inputs[0],
3730 0 : inputs[1]);
3731 : case wasm::kExprF32x4Le:
3732 : return graph()->NewNode(jsgraph()->machine()->F32x4Le(), inputs[0],
3733 0 : inputs[1]);
3734 : case wasm::kExprF32x4Gt:
3735 : return graph()->NewNode(jsgraph()->machine()->F32x4Lt(), inputs[1],
3736 0 : inputs[0]);
3737 : case wasm::kExprF32x4Ge:
3738 : return graph()->NewNode(jsgraph()->machine()->F32x4Le(), inputs[1],
3739 0 : inputs[0]);
3740 : case wasm::kExprI32x4Splat:
3741 2016 : return graph()->NewNode(jsgraph()->machine()->I32x4Splat(), inputs[0]);
3742 : case wasm::kExprI32x4SConvertF32x4:
3743 : return graph()->NewNode(jsgraph()->machine()->I32x4SConvertF32x4(),
3744 0 : inputs[0]);
3745 : case wasm::kExprI32x4UConvertF32x4:
3746 : return graph()->NewNode(jsgraph()->machine()->I32x4UConvertF32x4(),
3747 0 : inputs[0]);
3748 : case wasm::kExprI32x4SConvertI16x8Low:
3749 : return graph()->NewNode(jsgraph()->machine()->I32x4SConvertI16x8Low(),
3750 0 : inputs[0]);
3751 : case wasm::kExprI32x4SConvertI16x8High:
3752 : return graph()->NewNode(jsgraph()->machine()->I32x4SConvertI16x8High(),
3753 0 : inputs[0]);
3754 : case wasm::kExprI32x4Neg:
3755 36 : return graph()->NewNode(jsgraph()->machine()->I32x4Neg(), inputs[0]);
3756 : case wasm::kExprI32x4Add:
3757 : return graph()->NewNode(jsgraph()->machine()->I32x4Add(), inputs[0],
3758 72 : inputs[1]);
3759 : case wasm::kExprI32x4AddHoriz:
3760 : return graph()->NewNode(jsgraph()->machine()->I32x4AddHoriz(), inputs[0],
3761 18 : inputs[1]);
3762 : case wasm::kExprI32x4Sub:
3763 : return graph()->NewNode(jsgraph()->machine()->I32x4Sub(), inputs[0],
3764 36 : inputs[1]);
3765 : case wasm::kExprI32x4Mul:
3766 : return graph()->NewNode(jsgraph()->machine()->I32x4Mul(), inputs[0],
3767 36 : inputs[1]);
3768 : case wasm::kExprI32x4MinS:
3769 : return graph()->NewNode(jsgraph()->machine()->I32x4MinS(), inputs[0],
3770 36 : inputs[1]);
3771 : case wasm::kExprI32x4MaxS:
3772 : return graph()->NewNode(jsgraph()->machine()->I32x4MaxS(), inputs[0],
3773 36 : inputs[1]);
3774 : case wasm::kExprI32x4Eq:
3775 : return graph()->NewNode(jsgraph()->machine()->I32x4Eq(), inputs[0],
3776 36 : inputs[1]);
3777 : case wasm::kExprI32x4Ne:
3778 : return graph()->NewNode(jsgraph()->machine()->I32x4Ne(), inputs[0],
3779 54 : inputs[1]);
3780 : case wasm::kExprI32x4LtS:
3781 : return graph()->NewNode(jsgraph()->machine()->I32x4GtS(), inputs[1],
3782 36 : inputs[0]);
3783 : case wasm::kExprI32x4LeS:
3784 : return graph()->NewNode(jsgraph()->machine()->I32x4GeS(), inputs[1],
3785 36 : inputs[0]);
3786 : case wasm::kExprI32x4GtS:
3787 : return graph()->NewNode(jsgraph()->machine()->I32x4GtS(), inputs[0],
3788 36 : inputs[1]);
3789 : case wasm::kExprI32x4GeS:
3790 : return graph()->NewNode(jsgraph()->machine()->I32x4GeS(), inputs[0],
3791 36 : inputs[1]);
3792 : case wasm::kExprI32x4UConvertI16x8Low:
3793 : return graph()->NewNode(jsgraph()->machine()->I32x4UConvertI16x8Low(),
3794 0 : inputs[0]);
3795 : case wasm::kExprI32x4UConvertI16x8High:
3796 : return graph()->NewNode(jsgraph()->machine()->I32x4UConvertI16x8High(),
3797 0 : inputs[0]);
3798 : case wasm::kExprI32x4MinU:
3799 : return graph()->NewNode(jsgraph()->machine()->I32x4MinU(), inputs[0],
3800 36 : inputs[1]);
3801 : case wasm::kExprI32x4MaxU:
3802 : return graph()->NewNode(jsgraph()->machine()->I32x4MaxU(), inputs[0],
3803 36 : inputs[1]);
3804 : case wasm::kExprI32x4LtU:
3805 : return graph()->NewNode(jsgraph()->machine()->I32x4GtU(), inputs[1],
3806 36 : inputs[0]);
3807 : case wasm::kExprI32x4LeU:
3808 : return graph()->NewNode(jsgraph()->machine()->I32x4GeU(), inputs[1],
3809 36 : inputs[0]);
3810 : case wasm::kExprI32x4GtU:
3811 : return graph()->NewNode(jsgraph()->machine()->I32x4GtU(), inputs[0],
3812 36 : inputs[1]);
3813 : case wasm::kExprI32x4GeU:
3814 : return graph()->NewNode(jsgraph()->machine()->I32x4GeU(), inputs[0],
3815 36 : inputs[1]);
3816 : case wasm::kExprI16x8Splat:
3817 1836 : return graph()->NewNode(jsgraph()->machine()->I16x8Splat(), inputs[0]);
3818 : case wasm::kExprI16x8SConvertI8x16Low:
3819 : return graph()->NewNode(jsgraph()->machine()->I16x8SConvertI8x16Low(),
3820 0 : inputs[0]);
3821 : case wasm::kExprI16x8SConvertI8x16High:
3822 : return graph()->NewNode(jsgraph()->machine()->I16x8SConvertI8x16High(),
3823 0 : inputs[0]);
3824 : case wasm::kExprI16x8Neg:
3825 36 : return graph()->NewNode(jsgraph()->machine()->I16x8Neg(), inputs[0]);
3826 : case wasm::kExprI16x8SConvertI32x4:
3827 : return graph()->NewNode(jsgraph()->machine()->I16x8SConvertI32x4(),
3828 0 : inputs[0], inputs[1]);
3829 : case wasm::kExprI16x8Add:
3830 : return graph()->NewNode(jsgraph()->machine()->I16x8Add(), inputs[0],
3831 36 : inputs[1]);
3832 : case wasm::kExprI16x8AddSaturateS:
3833 : return graph()->NewNode(jsgraph()->machine()->I16x8AddSaturateS(),
3834 36 : inputs[0], inputs[1]);
3835 : case wasm::kExprI16x8AddHoriz:
3836 : return graph()->NewNode(jsgraph()->machine()->I16x8AddHoriz(), inputs[0],
3837 18 : inputs[1]);
3838 : case wasm::kExprI16x8Sub:
3839 : return graph()->NewNode(jsgraph()->machine()->I16x8Sub(), inputs[0],
3840 36 : inputs[1]);
3841 : case wasm::kExprI16x8SubSaturateS:
3842 : return graph()->NewNode(jsgraph()->machine()->I16x8SubSaturateS(),
3843 36 : inputs[0], inputs[1]);
3844 : case wasm::kExprI16x8Mul:
3845 : return graph()->NewNode(jsgraph()->machine()->I16x8Mul(), inputs[0],
3846 36 : inputs[1]);
3847 : case wasm::kExprI16x8MinS:
3848 : return graph()->NewNode(jsgraph()->machine()->I16x8MinS(), inputs[0],
3849 36 : inputs[1]);
3850 : case wasm::kExprI16x8MaxS:
3851 : return graph()->NewNode(jsgraph()->machine()->I16x8MaxS(), inputs[0],
3852 36 : inputs[1]);
3853 : case wasm::kExprI16x8Eq:
3854 : return graph()->NewNode(jsgraph()->machine()->I16x8Eq(), inputs[0],
3855 36 : inputs[1]);
3856 : case wasm::kExprI16x8Ne:
3857 : return graph()->NewNode(jsgraph()->machine()->I16x8Ne(), inputs[0],
3858 54 : inputs[1]);
3859 : case wasm::kExprI16x8LtS:
3860 : return graph()->NewNode(jsgraph()->machine()->I16x8GtS(), inputs[1],
3861 36 : inputs[0]);
3862 : case wasm::kExprI16x8LeS:
3863 : return graph()->NewNode(jsgraph()->machine()->I16x8GeS(), inputs[1],
3864 36 : inputs[0]);
3865 : case wasm::kExprI16x8GtS:
3866 : return graph()->NewNode(jsgraph()->machine()->I16x8GtS(), inputs[0],
3867 36 : inputs[1]);
3868 : case wasm::kExprI16x8GeS:
3869 : return graph()->NewNode(jsgraph()->machine()->I16x8GeS(), inputs[0],
3870 36 : inputs[1]);
3871 : case wasm::kExprI16x8UConvertI8x16Low:
3872 : return graph()->NewNode(jsgraph()->machine()->I16x8UConvertI8x16Low(),
3873 0 : inputs[0]);
3874 : case wasm::kExprI16x8UConvertI8x16High:
3875 : return graph()->NewNode(jsgraph()->machine()->I16x8UConvertI8x16High(),
3876 0 : inputs[0]);
3877 : case wasm::kExprI16x8UConvertI32x4:
3878 : return graph()->NewNode(jsgraph()->machine()->I16x8UConvertI32x4(),
3879 0 : inputs[0], inputs[1]);
3880 : case wasm::kExprI16x8AddSaturateU:
3881 : return graph()->NewNode(jsgraph()->machine()->I16x8AddSaturateU(),
3882 36 : inputs[0], inputs[1]);
3883 : case wasm::kExprI16x8SubSaturateU:
3884 : return graph()->NewNode(jsgraph()->machine()->I16x8SubSaturateU(),
3885 36 : inputs[0], inputs[1]);
3886 : case wasm::kExprI16x8MinU:
3887 : return graph()->NewNode(jsgraph()->machine()->I16x8MinU(), inputs[0],
3888 36 : inputs[1]);
3889 : case wasm::kExprI16x8MaxU:
3890 : return graph()->NewNode(jsgraph()->machine()->I16x8MaxU(), inputs[0],
3891 36 : inputs[1]);
3892 : case wasm::kExprI16x8LtU:
3893 : return graph()->NewNode(jsgraph()->machine()->I16x8GtU(), inputs[1],
3894 36 : inputs[0]);
3895 : case wasm::kExprI16x8LeU:
3896 : return graph()->NewNode(jsgraph()->machine()->I16x8GeU(), inputs[1],
3897 36 : inputs[0]);
3898 : case wasm::kExprI16x8GtU:
3899 : return graph()->NewNode(jsgraph()->machine()->I16x8GtU(), inputs[0],
3900 36 : inputs[1]);
3901 : case wasm::kExprI16x8GeU:
3902 : return graph()->NewNode(jsgraph()->machine()->I16x8GeU(), inputs[0],
3903 36 : inputs[1]);
3904 : case wasm::kExprI8x16Splat:
3905 1656 : return graph()->NewNode(jsgraph()->machine()->I8x16Splat(), inputs[0]);
3906 : case wasm::kExprI8x16Neg:
3907 36 : return graph()->NewNode(jsgraph()->machine()->I8x16Neg(), inputs[0]);
3908 : case wasm::kExprI8x16SConvertI16x8:
3909 : return graph()->NewNode(jsgraph()->machine()->I8x16SConvertI16x8(),
3910 0 : inputs[0], inputs[1]);
3911 : case wasm::kExprI8x16Add:
3912 : return graph()->NewNode(jsgraph()->machine()->I8x16Add(), inputs[0],
3913 36 : inputs[1]);
3914 : case wasm::kExprI8x16AddSaturateS:
3915 : return graph()->NewNode(jsgraph()->machine()->I8x16AddSaturateS(),
3916 36 : inputs[0], inputs[1]);
3917 : case wasm::kExprI8x16Sub:
3918 : return graph()->NewNode(jsgraph()->machine()->I8x16Sub(), inputs[0],
3919 36 : inputs[1]);
3920 : case wasm::kExprI8x16SubSaturateS:
3921 : return graph()->NewNode(jsgraph()->machine()->I8x16SubSaturateS(),
3922 36 : inputs[0], inputs[1]);
3923 : case wasm::kExprI8x16Mul:
3924 : return graph()->NewNode(jsgraph()->machine()->I8x16Mul(), inputs[0],
3925 0 : inputs[1]);
3926 : case wasm::kExprI8x16MinS:
3927 : return graph()->NewNode(jsgraph()->machine()->I8x16MinS(), inputs[0],
3928 36 : inputs[1]);
3929 : case wasm::kExprI8x16MaxS:
3930 : return graph()->NewNode(jsgraph()->machine()->I8x16MaxS(), inputs[0],
3931 36 : inputs[1]);
3932 : case wasm::kExprI8x16Eq:
3933 : return graph()->NewNode(jsgraph()->machine()->I8x16Eq(), inputs[0],
3934 36 : inputs[1]);
3935 : case wasm::kExprI8x16Ne:
3936 : return graph()->NewNode(jsgraph()->machine()->I8x16Ne(), inputs[0],
3937 54 : inputs[1]);
3938 : case wasm::kExprI8x16LtS:
3939 : return graph()->NewNode(jsgraph()->machine()->I8x16GtS(), inputs[1],
3940 36 : inputs[0]);
3941 : case wasm::kExprI8x16LeS:
3942 : return graph()->NewNode(jsgraph()->machine()->I8x16GeS(), inputs[1],
3943 36 : inputs[0]);
3944 : case wasm::kExprI8x16GtS:
3945 : return graph()->NewNode(jsgraph()->machine()->I8x16GtS(), inputs[0],
3946 36 : inputs[1]);
3947 : case wasm::kExprI8x16GeS:
3948 : return graph()->NewNode(jsgraph()->machine()->I8x16GeS(), inputs[0],
3949 36 : inputs[1]);
3950 : case wasm::kExprI8x16UConvertI16x8:
3951 : return graph()->NewNode(jsgraph()->machine()->I8x16UConvertI16x8(),
3952 0 : inputs[0], inputs[1]);
3953 : case wasm::kExprI8x16AddSaturateU:
3954 : return graph()->NewNode(jsgraph()->machine()->I8x16AddSaturateU(),
3955 36 : inputs[0], inputs[1]);
3956 : case wasm::kExprI8x16SubSaturateU:
3957 : return graph()->NewNode(jsgraph()->machine()->I8x16SubSaturateU(),
3958 36 : inputs[0], inputs[1]);
3959 : case wasm::kExprI8x16MinU:
3960 : return graph()->NewNode(jsgraph()->machine()->I8x16MinU(), inputs[0],
3961 36 : inputs[1]);
3962 : case wasm::kExprI8x16MaxU:
3963 : return graph()->NewNode(jsgraph()->machine()->I8x16MaxU(), inputs[0],
3964 36 : inputs[1]);
3965 : case wasm::kExprI8x16LtU:
3966 : return graph()->NewNode(jsgraph()->machine()->I8x16GtU(), inputs[1],
3967 36 : inputs[0]);
3968 : case wasm::kExprI8x16LeU:
3969 : return graph()->NewNode(jsgraph()->machine()->I8x16GeU(), inputs[1],
3970 36 : inputs[0]);
3971 : case wasm::kExprI8x16GtU:
3972 : return graph()->NewNode(jsgraph()->machine()->I8x16GtU(), inputs[0],
3973 36 : inputs[1]);
3974 : case wasm::kExprI8x16GeU:
3975 : return graph()->NewNode(jsgraph()->machine()->I8x16GeU(), inputs[0],
3976 36 : inputs[1]);
3977 : case wasm::kExprS128And:
3978 : return graph()->NewNode(jsgraph()->machine()->S128And(), inputs[0],
3979 36 : inputs[1]);
3980 : case wasm::kExprS128Or:
3981 : return graph()->NewNode(jsgraph()->machine()->S128Or(), inputs[0],
3982 36 : inputs[1]);
3983 : case wasm::kExprS128Xor:
3984 : return graph()->NewNode(jsgraph()->machine()->S128Xor(), inputs[0],
3985 36 : inputs[1]);
3986 : case wasm::kExprS128Not:
3987 36 : return graph()->NewNode(jsgraph()->machine()->S128Not(), inputs[0]);
3988 : case wasm::kExprS128Select:
3989 : return graph()->NewNode(jsgraph()->machine()->S128Select(), inputs[0],
3990 108 : inputs[1], inputs[2]);
3991 : case wasm::kExprS1x4AnyTrue:
3992 0 : return graph()->NewNode(jsgraph()->machine()->S1x4AnyTrue(), inputs[0]);
3993 : case wasm::kExprS1x4AllTrue:
3994 0 : return graph()->NewNode(jsgraph()->machine()->S1x4AllTrue(), inputs[0]);
3995 : case wasm::kExprS1x8AnyTrue:
3996 0 : return graph()->NewNode(jsgraph()->machine()->S1x8AnyTrue(), inputs[0]);
3997 : case wasm::kExprS1x8AllTrue:
3998 0 : return graph()->NewNode(jsgraph()->machine()->S1x8AllTrue(), inputs[0]);
3999 : case wasm::kExprS1x16AnyTrue:
4000 0 : return graph()->NewNode(jsgraph()->machine()->S1x16AnyTrue(), inputs[0]);
4001 : case wasm::kExprS1x16AllTrue:
4002 0 : return graph()->NewNode(jsgraph()->machine()->S1x16AllTrue(), inputs[0]);
4003 : default:
4004 0 : FATAL_UNSUPPORTED_OPCODE(opcode);
4005 : }
4006 : }
4007 :
4008 12654 : Node* WasmGraphBuilder::SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane,
4009 12654 : Node* const* inputs) {
4010 12654 : has_simd_ = true;
4011 12654 : switch (opcode) {
4012 : case wasm::kExprF32x4ExtractLane:
4013 : return graph()->NewNode(jsgraph()->machine()->F32x4ExtractLane(lane),
4014 0 : inputs[0]);
4015 : case wasm::kExprF32x4ReplaceLane:
4016 : return graph()->NewNode(jsgraph()->machine()->F32x4ReplaceLane(lane),
4017 0 : inputs[0], inputs[1]);
4018 : case wasm::kExprI32x4ExtractLane:
4019 : return graph()->NewNode(jsgraph()->machine()->I32x4ExtractLane(lane),
4020 4878 : inputs[0]);
4021 : case wasm::kExprI32x4ReplaceLane:
4022 : return graph()->NewNode(jsgraph()->machine()->I32x4ReplaceLane(lane),
4023 396 : inputs[0], inputs[1]);
4024 : case wasm::kExprI16x8ExtractLane:
4025 : return graph()->NewNode(jsgraph()->machine()->I16x8ExtractLane(lane),
4026 9936 : inputs[0]);
4027 : case wasm::kExprI16x8ReplaceLane:
4028 : return graph()->NewNode(jsgraph()->machine()->I16x8ReplaceLane(lane),
4029 360 : inputs[0], inputs[1]);
4030 : case wasm::kExprI8x16ExtractLane:
4031 : return graph()->NewNode(jsgraph()->machine()->I8x16ExtractLane(lane),
4032 21744 : inputs[0]);
4033 : case wasm::kExprI8x16ReplaceLane:
4034 : return graph()->NewNode(jsgraph()->machine()->I8x16ReplaceLane(lane),
4035 648 : inputs[0], inputs[1]);
4036 : default:
4037 0 : FATAL_UNSUPPORTED_OPCODE(opcode);
4038 : }
4039 : }
4040 :
4041 72 : Node* WasmGraphBuilder::SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
4042 72 : Node* const* inputs) {
4043 72 : has_simd_ = true;
4044 72 : switch (opcode) {
4045 : case wasm::kExprI32x4Shl:
4046 36 : return graph()->NewNode(jsgraph()->machine()->I32x4Shl(shift), inputs[0]);
4047 : case wasm::kExprI32x4ShrS:
4048 : return graph()->NewNode(jsgraph()->machine()->I32x4ShrS(shift),
4049 36 : inputs[0]);
4050 : case wasm::kExprI32x4ShrU:
4051 : return graph()->NewNode(jsgraph()->machine()->I32x4ShrU(shift),
4052 36 : inputs[0]);
4053 : case wasm::kExprI16x8Shl:
4054 36 : return graph()->NewNode(jsgraph()->machine()->I16x8Shl(shift), inputs[0]);
4055 : case wasm::kExprI16x8ShrS:
4056 : return graph()->NewNode(jsgraph()->machine()->I16x8ShrS(shift),
4057 36 : inputs[0]);
4058 : case wasm::kExprI16x8ShrU:
4059 : return graph()->NewNode(jsgraph()->machine()->I16x8ShrU(shift),
4060 36 : inputs[0]);
4061 : case wasm::kExprI8x16Shl:
4062 0 : return graph()->NewNode(jsgraph()->machine()->I8x16Shl(shift), inputs[0]);
4063 : case wasm::kExprI8x16ShrS:
4064 : return graph()->NewNode(jsgraph()->machine()->I8x16ShrS(shift),
4065 0 : inputs[0]);
4066 : case wasm::kExprI8x16ShrU:
4067 : return graph()->NewNode(jsgraph()->machine()->I8x16ShrU(shift),
4068 0 : inputs[0]);
4069 : default:
4070 0 : FATAL_UNSUPPORTED_OPCODE(opcode);
4071 : }
4072 : }
4073 :
4074 0 : Node* WasmGraphBuilder::Simd8x16ShuffleOp(const uint8_t shuffle[16],
4075 0 : Node* const* inputs) {
4076 0 : has_simd_ = true;
4077 : return graph()->NewNode(jsgraph()->machine()->S8x16Shuffle(shuffle),
4078 0 : inputs[0], inputs[1]);
4079 : }
4080 :
4081 : #define ATOMIC_BINOP_LIST(V) \
4082 : V(I32AtomicAdd, Add, Uint32) \
4083 : V(I32AtomicSub, Sub, Uint32) \
4084 : V(I32AtomicAnd, And, Uint32) \
4085 : V(I32AtomicOr, Or, Uint32) \
4086 : V(I32AtomicXor, Xor, Uint32) \
4087 : V(I32AtomicExchange, Exchange, Uint32) \
4088 : V(I32AtomicAdd8U, Add, Uint8) \
4089 : V(I32AtomicSub8U, Sub, Uint8) \
4090 : V(I32AtomicAnd8U, And, Uint8) \
4091 : V(I32AtomicOr8U, Or, Uint8) \
4092 : V(I32AtomicXor8U, Xor, Uint8) \
4093 : V(I32AtomicExchange8U, Exchange, Uint8) \
4094 : V(I32AtomicAdd16U, Add, Uint16) \
4095 : V(I32AtomicSub16U, Sub, Uint16) \
4096 : V(I32AtomicAnd16U, And, Uint16) \
4097 : V(I32AtomicOr16U, Or, Uint16) \
4098 : V(I32AtomicXor16U, Xor, Uint16) \
4099 : V(I32AtomicExchange16U, Exchange, Uint16)
4100 :
4101 : #define ATOMIC_TERNARY_LIST(V) \
4102 : V(I32AtomicCompareExchange, CompareExchange, Uint32) \
4103 : V(I32AtomicCompareExchange8U, CompareExchange, Uint8) \
4104 : V(I32AtomicCompareExchange16U, CompareExchange, Uint16)
4105 :
4106 : #define ATOMIC_LOAD_LIST(V) \
4107 : V(I32AtomicLoad, Uint32) \
4108 : V(I32AtomicLoad8U, Uint8) \
4109 : V(I32AtomicLoad16U, Uint16)
4110 :
4111 : #define ATOMIC_STORE_LIST(V) \
4112 : V(I32AtomicStore, Uint32, kWord32) \
4113 : V(I32AtomicStore8U, Uint8, kWord8) \
4114 : V(I32AtomicStore16U, Uint16, kWord16)
4115 :
4116 512 : Node* WasmGraphBuilder::AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs,
4117 : uint32_t alignment, uint32_t offset,
4118 512 : wasm::WasmCodePosition position) {
4119 : // TODO(gdeepti): Add alignment validation, traps on misalignment
4120 : Node* node;
4121 512 : switch (opcode) {
4122 : #define BUILD_ATOMIC_BINOP(Name, Operation, Type) \
4123 : case wasm::kExpr##Name: { \
4124 : BoundsCheckMem(MachineType::Type(), inputs[0], offset, position); \
4125 : node = graph()->NewNode( \
4126 : jsgraph()->machine()->Atomic##Operation(MachineType::Type()), \
4127 : MemBuffer(offset), inputs[0], inputs[1], *effect_, *control_); \
4128 : break; \
4129 : }
4130 592 : ATOMIC_BINOP_LIST(BUILD_ATOMIC_BINOP)
4131 : #undef BUILD_ATOMIC_BINOP
4132 :
4133 : #define BUILD_ATOMIC_TERNARY_OP(Name, Operation, Type) \
4134 : case wasm::kExpr##Name: { \
4135 : BoundsCheckMem(MachineType::Type(), inputs[0], offset, position); \
4136 : node = graph()->NewNode( \
4137 : jsgraph()->machine()->Atomic##Operation(MachineType::Type()), \
4138 : MemBuffer(offset), inputs[0], inputs[1], inputs[2], *effect_, \
4139 : *control_); \
4140 : break; \
4141 : }
4142 112 : ATOMIC_TERNARY_LIST(BUILD_ATOMIC_TERNARY_OP)
4143 : #undef BUILD_ATOMIC_TERNARY_OP
4144 :
4145 : #define BUILD_ATOMIC_LOAD_OP(Name, Type) \
4146 : case wasm::kExpr##Name: { \
4147 : BoundsCheckMem(MachineType::Type(), inputs[0], offset, position); \
4148 : node = graph()->NewNode( \
4149 : jsgraph()->machine()->AtomicLoad(MachineType::Type()), \
4150 : MemBuffer(offset), inputs[0], *effect_, *control_); \
4151 : break; \
4152 : }
4153 232 : ATOMIC_LOAD_LIST(BUILD_ATOMIC_LOAD_OP)
4154 : #undef BUILD_ATOMIC_LOAD_OP
4155 :
4156 : #define BUILD_ATOMIC_STORE_OP(Name, Type, Rep) \
4157 : case wasm::kExpr##Name: { \
4158 : BoundsCheckMem(MachineType::Type(), inputs[0], offset, position); \
4159 : node = graph()->NewNode( \
4160 : jsgraph()->machine()->AtomicStore(MachineRepresentation::Rep), \
4161 : MemBuffer(offset), inputs[0], inputs[1], *effect_, *control_); \
4162 : break; \
4163 : }
4164 220 : ATOMIC_STORE_LIST(BUILD_ATOMIC_STORE_OP)
4165 : #undef BUILD_ATOMIC_STORE_OP
4166 : default:
4167 0 : FATAL_UNSUPPORTED_OPCODE(opcode);
4168 : }
4169 512 : *effect_ = node;
4170 512 : return node;
4171 : }
4172 :
4173 : #undef ATOMIC_BINOP_LIST
4174 : #undef ATOMIC_TERNARY_LIST
4175 : #undef ATOMIC_LOAD_LIST
4176 : #undef ATOMIC_STORE_LIST
4177 :
4178 : namespace {
4179 805094 : bool must_record_function_compilation(Isolate* isolate) {
4180 805094 : return isolate->logger()->is_logging_code_events() || isolate->is_profiling();
4181 : }
4182 :
4183 : PRINTF_FORMAT(4, 5)
4184 0 : void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
4185 : Isolate* isolate, Handle<Code> code,
4186 : const char* format, ...) {
4187 : DCHECK(must_record_function_compilation(isolate));
4188 :
4189 : ScopedVector<char> buffer(128);
4190 : va_list arguments;
4191 0 : va_start(arguments, format);
4192 0 : int len = VSNPrintF(buffer, format, arguments);
4193 0 : CHECK_LT(0, len);
4194 0 : va_end(arguments);
4195 : Handle<String> name_str =
4196 0 : isolate->factory()->NewStringFromAsciiChecked(buffer.start());
4197 : Handle<String> script_str =
4198 0 : isolate->factory()->NewStringFromAsciiChecked("(wasm)");
4199 : Handle<SharedFunctionInfo> shared =
4200 0 : isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
4201 0 : PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
4202 : *script_str, 0, 0));
4203 0 : }
4204 : } // namespace
4205 :
4206 320352 : Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
4207 : Handle<Code> wasm_code, uint32_t index,
4208 : Address wasm_context_address) {
4209 320352 : const wasm::WasmFunction* func = &module->functions[index];
4210 :
4211 : //----------------------------------------------------------------------------
4212 : // Create the Graph
4213 : //----------------------------------------------------------------------------
4214 160176 : Zone zone(isolate->allocator(), ZONE_NAME);
4215 160176 : Graph graph(&zone);
4216 160176 : CommonOperatorBuilder common(&zone);
4217 : MachineOperatorBuilder machine(
4218 : &zone, MachineType::PointerRepresentation(),
4219 : InstructionSelector::SupportedMachineOperatorFlags(),
4220 160176 : InstructionSelector::AlignmentRequirements());
4221 : JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
4222 :
4223 160176 : Node* control = nullptr;
4224 160176 : Node* effect = nullptr;
4225 :
4226 : // TODO(titzer): compile JS to WASM wrappers without a {ModuleEnv}.
4227 : ModuleEnv env = {
4228 : module,
4229 : std::vector<Address>(), // function_tables
4230 : std::vector<Address>(), // signature_tables
4231 : std::vector<Handle<Code>>(), // function_code
4232 160176 : BUILTIN_CODE(isolate, Illegal) // default_function_code
4233 480528 : };
4234 :
4235 : WasmGraphBuilder builder(&env, &zone, &jsgraph,
4236 480528 : CEntryStub(isolate, 1).GetCode(), func->sig);
4237 : builder.set_control_ptr(&control);
4238 : builder.set_effect_ptr(&effect);
4239 160176 : builder.BuildJSToWasmWrapper(wasm_code, wasm_context_address);
4240 :
4241 : //----------------------------------------------------------------------------
4242 : // Run the compilation pipeline.
4243 : //----------------------------------------------------------------------------
4244 160176 : if (FLAG_trace_turbo_graph) { // Simple textual RPO.
4245 0 : OFStream os(stdout);
4246 0 : os << "-- Graph after change lowering -- " << std::endl;
4247 0 : os << AsRPO(graph);
4248 : }
4249 :
4250 : // Schedule and compile to machine code.
4251 : int params =
4252 160176 : static_cast<int>(module->functions[index].sig->parameter_count());
4253 : CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
4254 160176 : &zone, false, params + 1, CallDescriptor::kNoFlags);
4255 :
4256 : #ifdef DEBUG
4257 : EmbeddedVector<char, 32> func_name;
4258 : static unsigned id = 0;
4259 : func_name.Truncate(SNPrintF(func_name, "js-to-wasm#%d", id++));
4260 : #else
4261 : Vector<const char> func_name = CStrVector("js-to-wasm");
4262 : #endif
4263 :
4264 320352 : CompilationInfo info(func_name, isolate, &zone, Code::JS_TO_WASM_FUNCTION);
4265 160176 : Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
4266 : #ifdef ENABLE_DISASSEMBLER
4267 : if (FLAG_print_opt_code && !code.is_null()) {
4268 : OFStream os(stdout);
4269 : code->Disassemble(func_name.start(), os);
4270 : }
4271 : #endif
4272 :
4273 160176 : if (must_record_function_compilation(isolate)) {
4274 : RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code,
4275 0 : "%.*s", func_name.length(), func_name.start());
4276 : }
4277 :
4278 320352 : return code;
4279 : }
4280 :
4281 0 : void ValidateImportWrapperReferencesImmovables(Handle<Code> wrapper) {
4282 : #if !DEBUG
4283 : return;
4284 : #endif
4285 : // We expect the only embedded objects to be those originating from
4286 : // a snapshot, which are immovable.
4287 : DisallowHeapAllocation no_gc;
4288 : if (wrapper.is_null()) return;
4289 : static constexpr int kAllGCRefs = (1 << (RelocInfo::LAST_GCED_ENUM + 1)) - 1;
4290 : for (RelocIterator it(*wrapper, kAllGCRefs); !it.done(); it.next()) {
4291 : RelocInfo::Mode mode = it.rinfo()->rmode();
4292 : Object* target = nullptr;
4293 : switch (mode) {
4294 : case RelocInfo::CODE_TARGET:
4295 : // this would be either one of the stubs or builtins, because
4296 : // we didn't link yet.
4297 : target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
4298 : break;
4299 : case RelocInfo::EMBEDDED_OBJECT:
4300 : target = it.rinfo()->target_object();
4301 : break;
4302 : default:
4303 : UNREACHABLE();
4304 : }
4305 : CHECK_NOT_NULL(target);
4306 : bool is_immovable =
4307 : target->IsSmi() || Heap::IsImmovable(HeapObject::cast(target));
4308 : bool is_allowed_stub = false;
4309 : if (target->IsCode()) {
4310 : Code* code = Code::cast(target);
4311 : is_allowed_stub =
4312 : code->kind() == Code::STUB &&
4313 : CodeStub::MajorKeyFromKey(code->stub_key()) == CodeStub::DoubleToI;
4314 : }
4315 : CHECK(is_immovable || is_allowed_stub);
4316 : }
4317 : }
4318 :
4319 13492 : Handle<Code> CompileWasmToJSWrapper(
4320 13492 : Isolate* isolate, Handle<JSReceiver> target, wasm::FunctionSig* sig,
4321 : uint32_t index, wasm::ModuleOrigin origin,
4322 : Handle<FixedArray> global_js_imports_table) {
4323 : //----------------------------------------------------------------------------
4324 : // Create the Graph
4325 : //----------------------------------------------------------------------------
4326 13492 : Zone zone(isolate->allocator(), ZONE_NAME);
4327 13492 : Graph graph(&zone);
4328 13492 : CommonOperatorBuilder common(&zone);
4329 : MachineOperatorBuilder machine(
4330 : &zone, MachineType::PointerRepresentation(),
4331 : InstructionSelector::SupportedMachineOperatorFlags(),
4332 13492 : InstructionSelector::AlignmentRequirements());
4333 : JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
4334 :
4335 13492 : Node* control = nullptr;
4336 13492 : Node* effect = nullptr;
4337 :
4338 : SourcePositionTable* source_position_table =
4339 4311 : origin == wasm::kAsmJsOrigin ? new (&zone) SourcePositionTable(&graph)
4340 13492 : : nullptr;
4341 :
4342 : WasmGraphBuilder builder(nullptr, &zone, &jsgraph,
4343 : CEntryStub(isolate, 1).GetCode(), sig,
4344 26984 : source_position_table);
4345 : builder.set_control_ptr(&control);
4346 : builder.set_effect_ptr(&effect);
4347 13492 : if (builder.BuildWasmToJSWrapper(target, global_js_imports_table, index)) {
4348 : global_js_imports_table->set(
4349 13442 : OffsetForImportData(index, WasmGraphBuilder::kFunction), *target);
4350 13442 : if (target->IsJSFunction()) {
4351 : Handle<JSFunction> function = Handle<JSFunction>::cast(target);
4352 : global_js_imports_table->set(
4353 : OffsetForImportData(index, WasmGraphBuilder::kFunctionContext),
4354 11492 : function->context());
4355 : global_js_imports_table->set(
4356 : OffsetForImportData(index, WasmGraphBuilder::kGlobalProxy),
4357 22984 : function->context()->global_proxy());
4358 : }
4359 : }
4360 :
4361 13492 : if (FLAG_trace_turbo_graph) { // Simple textual RPO.
4362 0 : OFStream os(stdout);
4363 0 : os << "-- Graph after change lowering -- " << std::endl;
4364 0 : os << AsRPO(graph);
4365 : }
4366 :
4367 : // Schedule and compile to machine code.
4368 13492 : CallDescriptor* incoming = GetWasmCallDescriptor(&zone, sig);
4369 13492 : if (machine.Is32()) {
4370 0 : incoming = GetI32WasmCallDescriptor(&zone, incoming);
4371 : }
4372 :
4373 : #ifdef DEBUG
4374 : EmbeddedVector<char, 32> func_name;
4375 : static unsigned id = 0;
4376 : func_name.Truncate(SNPrintF(func_name, "wasm-to-js#%d", id++));
4377 : #else
4378 : Vector<const char> func_name = CStrVector("wasm-to-js");
4379 : #endif
4380 :
4381 26984 : CompilationInfo info(func_name, isolate, &zone, Code::WASM_TO_JS_FUNCTION);
4382 : Handle<Code> code = Pipeline::GenerateCodeForTesting(
4383 13492 : &info, incoming, &graph, nullptr, source_position_table);
4384 : ValidateImportWrapperReferencesImmovables(code);
4385 : Handle<FixedArray> deopt_data =
4386 13492 : isolate->factory()->NewFixedArray(2, TENURED);
4387 : intptr_t loc =
4388 : reinterpret_cast<intptr_t>(global_js_imports_table.location());
4389 13492 : Handle<Object> loc_handle = isolate->factory()->NewHeapNumberFromBits(loc);
4390 13492 : deopt_data->set(0, *loc_handle);
4391 : Handle<Object> index_handle = isolate->factory()->NewNumberFromInt(
4392 13492 : OffsetForImportData(index, WasmGraphBuilder::kFunction));
4393 13492 : deopt_data->set(1, *index_handle);
4394 13492 : code->set_deoptimization_data(*deopt_data);
4395 : #ifdef ENABLE_DISASSEMBLER
4396 : if (FLAG_print_opt_code && !code.is_null()) {
4397 : OFStream os(stdout);
4398 : code->Disassemble(func_name.start(), os);
4399 : }
4400 : #endif
4401 :
4402 13492 : if (must_record_function_compilation(isolate)) {
4403 : RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code,
4404 0 : "%.*s", func_name.length(), func_name.start());
4405 : }
4406 :
4407 26984 : return code;
4408 : }
4409 :
4410 407685 : Handle<Code> CompileWasmToWasmWrapper(Isolate* isolate, Handle<Code> target,
4411 : wasm::FunctionSig* sig,
4412 : uint32_t func_index,
4413 : Address new_wasm_context_address) {
4414 : //----------------------------------------------------------------------------
4415 : // Create the Graph
4416 : //----------------------------------------------------------------------------
4417 135895 : Zone zone(isolate->allocator(), ZONE_NAME);
4418 135895 : Graph graph(&zone);
4419 135895 : CommonOperatorBuilder common(&zone);
4420 : MachineOperatorBuilder machine(
4421 : &zone, MachineType::PointerRepresentation(),
4422 : InstructionSelector::SupportedMachineOperatorFlags(),
4423 135895 : InstructionSelector::AlignmentRequirements());
4424 : JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
4425 :
4426 135895 : Node* control = nullptr;
4427 135895 : Node* effect = nullptr;
4428 :
4429 135895 : WasmGraphBuilder builder(nullptr, &zone, &jsgraph, Handle<Code>(), sig);
4430 : builder.set_control_ptr(&control);
4431 : builder.set_effect_ptr(&effect);
4432 135895 : builder.BuildWasmToWasmWrapper(target, new_wasm_context_address);
4433 135895 : if (HasInt64ParamOrReturn(sig)) builder.LowerInt64();
4434 :
4435 135895 : if (FLAG_trace_turbo_graph) { // Simple textual RPO.
4436 0 : OFStream os(stdout);
4437 0 : os << "-- Graph after change lowering -- " << std::endl;
4438 0 : os << AsRPO(graph);
4439 : }
4440 :
4441 : // Schedule and compile to machine code.
4442 135895 : CallDescriptor* incoming = GetWasmCallDescriptor(&zone, sig);
4443 135895 : if (machine.Is32()) {
4444 0 : incoming = GetI32WasmCallDescriptor(&zone, incoming);
4445 : }
4446 : bool debugging =
4447 : #if DEBUG
4448 : true;
4449 : #else
4450 135895 : FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
4451 : #endif
4452 135895 : Vector<const char> func_name = ArrayVector("wasm-to-wasm");
4453 : static unsigned id = 0;
4454 135895 : Vector<char> buffer;
4455 135895 : if (debugging) {
4456 0 : buffer = Vector<char>::New(128);
4457 0 : int chars = SNPrintF(buffer, "wasm-to-wasm#%d", id);
4458 0 : func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
4459 : }
4460 :
4461 271790 : CompilationInfo info(func_name, isolate, &zone, Code::WASM_FUNCTION);
4462 135895 : Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
4463 : #ifdef ENABLE_DISASSEMBLER
4464 : if (FLAG_print_opt_code && !code.is_null()) {
4465 : OFStream os(stdout);
4466 : code->Disassemble(buffer.start(), os);
4467 : }
4468 : #endif
4469 135895 : if (debugging) {
4470 : buffer.Dispose();
4471 : }
4472 271790 : if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
4473 : RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code,
4474 0 : "wasm-to-wasm");
4475 : }
4476 :
4477 271790 : return code;
4478 : }
4479 :
4480 1125 : Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index,
4481 : wasm::FunctionSig* sig,
4482 : Handle<WasmInstanceObject> instance) {
4483 : //----------------------------------------------------------------------------
4484 : // Create the Graph
4485 : //----------------------------------------------------------------------------
4486 1125 : Zone zone(isolate->allocator(), ZONE_NAME);
4487 1125 : Graph graph(&zone);
4488 1125 : CommonOperatorBuilder common(&zone);
4489 : MachineOperatorBuilder machine(
4490 : &zone, MachineType::PointerRepresentation(),
4491 : InstructionSelector::SupportedMachineOperatorFlags(),
4492 1125 : InstructionSelector::AlignmentRequirements());
4493 : JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
4494 :
4495 1125 : Node* control = nullptr;
4496 1125 : Node* effect = nullptr;
4497 :
4498 : WasmGraphBuilder builder(nullptr, &zone, &jsgraph,
4499 2250 : CEntryStub(isolate, 1).GetCode(), sig);
4500 : builder.set_control_ptr(&control);
4501 : builder.set_effect_ptr(&effect);
4502 1125 : builder.BuildWasmInterpreterEntry(func_index, instance);
4503 :
4504 : Handle<Code> code = Handle<Code>::null();
4505 : {
4506 1125 : if (FLAG_trace_turbo_graph) { // Simple textual RPO.
4507 0 : OFStream os(stdout);
4508 0 : os << "-- Wasm interpreter entry graph -- " << std::endl;
4509 0 : os << AsRPO(graph);
4510 : }
4511 :
4512 : // Schedule and compile to machine code.
4513 1125 : CallDescriptor* incoming = GetWasmCallDescriptor(&zone, sig);
4514 1125 : if (machine.Is32()) {
4515 0 : incoming = GetI32WasmCallDescriptor(&zone, incoming);
4516 : }
4517 : #ifdef DEBUG
4518 : EmbeddedVector<char, 32> func_name;
4519 : func_name.Truncate(
4520 : SNPrintF(func_name, "wasm-interpreter-entry#%d", func_index));
4521 : #else
4522 : Vector<const char> func_name = CStrVector("wasm-interpreter-entry");
4523 : #endif
4524 :
4525 : CompilationInfo info(func_name, isolate, &zone,
4526 1125 : Code::WASM_INTERPRETER_ENTRY);
4527 1125 : code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
4528 : #ifdef ENABLE_DISASSEMBLER
4529 : if (FLAG_print_opt_code && !code.is_null()) {
4530 : OFStream os(stdout);
4531 : code->Disassemble(func_name.start(), os);
4532 : }
4533 : #endif
4534 :
4535 1125 : if (must_record_function_compilation(isolate)) {
4536 : RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code,
4537 0 : "%.*s", func_name.length(), func_name.start());
4538 1125 : }
4539 : }
4540 :
4541 1125 : Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(1, TENURED);
4542 1125 : Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance);
4543 1125 : deopt_data->set(0, *weak_instance);
4544 1125 : code->set_deoptimization_data(*deopt_data);
4545 :
4546 1125 : return code;
4547 : }
4548 :
4549 96 : Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig,
4550 : Address wasm_context_address) {
4551 96 : Zone zone(isolate->allocator(), ZONE_NAME);
4552 96 : Graph graph(&zone);
4553 96 : CommonOperatorBuilder common(&zone);
4554 : MachineOperatorBuilder machine(
4555 : &zone, MachineType::PointerRepresentation(),
4556 : InstructionSelector::SupportedMachineOperatorFlags(),
4557 96 : InstructionSelector::AlignmentRequirements());
4558 : JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
4559 :
4560 96 : Node* control = nullptr;
4561 96 : Node* effect = nullptr;
4562 :
4563 : WasmGraphBuilder builder(nullptr, &zone, &jsgraph,
4564 192 : CEntryStub(isolate, 1).GetCode(), sig);
4565 : builder.set_control_ptr(&control);
4566 : builder.set_effect_ptr(&effect);
4567 96 : builder.BuildCWasmEntry(wasm_context_address);
4568 :
4569 96 : if (FLAG_trace_turbo_graph) { // Simple textual RPO.
4570 0 : OFStream os(stdout);
4571 0 : os << "-- C Wasm entry graph -- " << std::endl;
4572 0 : os << AsRPO(graph);
4573 : }
4574 :
4575 : // Schedule and compile to machine code.
4576 : CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
4577 : &zone, false, CWasmEntryParameters::kNumParameters + 1,
4578 96 : CallDescriptor::kNoFlags);
4579 :
4580 : // Build a name in the form "c-wasm-entry:<params>:<returns>".
4581 : static constexpr size_t kMaxNameLen = 128;
4582 96 : char debug_name[kMaxNameLen] = "c-wasm-entry:";
4583 96 : size_t name_len = strlen(debug_name);
4584 : auto append_name_char = [&](char c) {
4585 312 : if (name_len + 1 < kMaxNameLen) debug_name[name_len++] = c;
4586 : };
4587 216 : for (wasm::ValueType t : sig->parameters()) {
4588 : append_name_char(wasm::WasmOpcodes::ShortNameOf(t));
4589 : }
4590 : append_name_char(':');
4591 192 : for (wasm::ValueType t : sig->returns()) {
4592 : append_name_char(wasm::WasmOpcodes::ShortNameOf(t));
4593 : }
4594 96 : debug_name[name_len] = '\0';
4595 : Vector<const char> debug_name_vec(debug_name, name_len);
4596 :
4597 192 : CompilationInfo info(debug_name_vec, isolate, &zone, Code::C_WASM_ENTRY);
4598 96 : Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
4599 : #ifdef ENABLE_DISASSEMBLER
4600 : if (FLAG_print_opt_code && !code.is_null()) {
4601 : OFStream os(stdout);
4602 : code->Disassemble(debug_name, os);
4603 : }
4604 : #endif
4605 :
4606 192 : return code;
4607 : }
4608 :
4609 233699 : SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
4610 : double* decode_ms) {
4611 : #if DEBUG
4612 : if (env_) {
4613 : size_t tables_size = env_->module->function_tables.size();
4614 : DCHECK_EQ(tables_size, env_->function_tables.size());
4615 : DCHECK_EQ(tables_size, env_->signature_tables.size());
4616 : }
4617 : #endif
4618 :
4619 : base::ElapsedTimer decode_timer;
4620 233699 : if (FLAG_trace_wasm_decode_time) {
4621 : decode_timer.Start();
4622 : }
4623 : // Create a TF graph during decoding.
4624 :
4625 : SourcePositionTable* source_position_table =
4626 467388 : new (jsgraph_->zone()) SourcePositionTable(jsgraph_->graph());
4627 : WasmGraphBuilder builder(env_, jsgraph_->zone(), jsgraph_, centry_stub_,
4628 : func_body_.sig, source_position_table,
4629 467346 : runtime_exception_support_);
4630 701128 : graph_construction_result_ =
4631 : wasm::BuildTFGraph(isolate_->allocator(), &builder, func_body_);
4632 :
4633 233719 : if (graph_construction_result_.failed()) {
4634 5743 : if (FLAG_trace_wasm_compiler) {
4635 0 : OFStream os(stdout);
4636 0 : os << "Compilation failed: " << graph_construction_result_.error_msg()
4637 0 : << std::endl;
4638 : }
4639 : return nullptr;
4640 : }
4641 :
4642 227976 : builder.LowerInt64();
4643 :
4644 456914 : if (builder.has_simd() &&
4645 1038 : (!CpuFeatures::SupportsWasmSimd128() || lower_simd_)) {
4646 984 : SimdScalarLowering(jsgraph_, func_body_.sig).LowerGraph();
4647 : }
4648 :
4649 455882 : if (func_index_ >= FLAG_trace_wasm_ast_start &&
4650 227944 : func_index_ < FLAG_trace_wasm_ast_end) {
4651 0 : PrintRawWasmCode(isolate_->allocator(), func_body_, env_->module);
4652 : }
4653 227943 : if (FLAG_trace_wasm_decode_time) {
4654 0 : *decode_ms = decode_timer.Elapsed().InMillisecondsF();
4655 : }
4656 227943 : return source_position_table;
4657 : }
4658 :
4659 : namespace {
4660 : Vector<const char> GetDebugName(Zone* zone, wasm::WasmName name, int index) {
4661 227966 : if (!name.is_empty()) {
4662 : return name;
4663 : }
4664 : #ifndef DEBUG
4665 : return {};
4666 : #endif
4667 : constexpr int kBufferLength = 15;
4668 :
4669 : EmbeddedVector<char, kBufferLength> name_vector;
4670 : int name_len = SNPrintF(name_vector, "wasm#%d", index);
4671 : DCHECK(name_len > 0 && name_len < name_vector.length());
4672 :
4673 : char* index_name = zone->NewArray<char>(name_len);
4674 : memcpy(index_name, name_vector.start(), name_len);
4675 : return Vector<const char>(index_name, name_len);
4676 : }
4677 : } // namespace
4678 :
4679 90265 : WasmCompilationUnit::WasmCompilationUnit(
4680 : Isolate* isolate, ModuleEnv* env, wasm::FunctionBody body,
4681 : wasm::WasmName name, int index, Handle<Code> centry_stub,
4682 : Counters* counters, RuntimeExceptionSupport exception_support,
4683 : bool lower_simd)
4684 : : isolate_(isolate),
4685 : env_(env),
4686 : func_body_(body),
4687 : func_name_(name),
4688 : counters_(counters ? counters : isolate->counters()),
4689 : centry_stub_(centry_stub),
4690 : func_index_(index),
4691 : runtime_exception_support_(exception_support),
4692 701400 : lower_simd_(lower_simd) {}
4693 :
4694 695249 : void WasmCompilationUnit::ExecuteCompilation() {
4695 461644 : auto timed_histogram = env_->module->is_wasm()
4696 : ? counters()->wasm_compile_wasm_function_time()
4697 467418 : : counters()->wasm_compile_asm_function_time();
4698 : TimedHistogramScope wasm_compile_function_time_scope(timed_histogram);
4699 :
4700 233698 : if (FLAG_trace_wasm_compiler) {
4701 0 : if (func_name_.start() != nullptr) {
4702 : PrintF("Compiling wasm function %d:'%.*s'\n\n", func_index(),
4703 0 : func_name_.length(), func_name_.start());
4704 : } else {
4705 0 : PrintF("Compiling wasm function %d:<unnamed>\n\n", func_index());
4706 : }
4707 : }
4708 :
4709 233698 : double decode_ms = 0;
4710 : size_t node_count = 0;
4711 :
4712 : // Scope for the {graph_zone}.
4713 : {
4714 461647 : Zone graph_zone(isolate_->allocator(), ZONE_NAME);
4715 : jsgraph_ = new (&graph_zone) JSGraph(
4716 233723 : isolate_, new (&graph_zone) Graph(&graph_zone),
4717 233711 : new (&graph_zone) CommonOperatorBuilder(&graph_zone), nullptr, nullptr,
4718 : new (&graph_zone) MachineOperatorBuilder(
4719 : &graph_zone, MachineType::PointerRepresentation(),
4720 : InstructionSelector::SupportedMachineOperatorFlags(),
4721 934855 : InstructionSelector::AlignmentRequirements()));
4722 : SourcePositionTable* source_positions =
4723 233708 : BuildGraphForWasmFunction(&decode_ms);
4724 :
4725 233692 : if (graph_construction_result_.failed()) {
4726 5743 : ok_ = false;
4727 239424 : return;
4728 : }
4729 :
4730 : base::ElapsedTimer pipeline_timer;
4731 227949 : if (FLAG_trace_wasm_decode_time) {
4732 455797 : node_count = jsgraph_->graph()->NodeCount();
4733 : pipeline_timer.Start();
4734 : }
4735 :
4736 455898 : compilation_zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME));
4737 :
4738 : // Run the compiler pipeline to generate machine code.
4739 : CallDescriptor* descriptor =
4740 455920 : GetWasmCallDescriptor(compilation_zone_.get(), func_body_.sig);
4741 455932 : if (jsgraph_->machine()->Is32()) {
4742 : descriptor =
4743 0 : GetI32WasmCallDescriptor(compilation_zone_.get(), descriptor);
4744 : }
4745 : info_.reset(new CompilationInfo(
4746 : GetDebugName(compilation_zone_.get(), func_name_, func_index_),
4747 683867 : isolate_, compilation_zone_.get(), Code::WASM_FUNCTION));
4748 : ZoneVector<trap_handler::ProtectedInstructionData> protected_instructions(
4749 : compilation_zone_.get());
4750 :
4751 : job_.reset(Pipeline::NewWasmCompilationJob(
4752 : info_.get(), jsgraph_, descriptor, source_positions,
4753 683805 : &protected_instructions, env_->module->origin()));
4754 227966 : ok_ = job_->ExecuteJob() == CompilationJob::SUCCEEDED;
4755 : // TODO(bradnelson): Improve histogram handling of size_t.
4756 : counters()->wasm_compile_function_peak_memory_bytes()->AddSample(
4757 683493 : static_cast<int>(jsgraph_->graph()->zone()->allocation_size()));
4758 :
4759 227922 : if (FLAG_trace_wasm_decode_time) {
4760 0 : double pipeline_ms = pipeline_timer.Elapsed().InMillisecondsF();
4761 : PrintF(
4762 : "wasm-compilation phase 1 ok: %u bytes, %0.3f ms decode, %zu nodes, "
4763 : "%0.3f ms pipeline\n",
4764 0 : static_cast<unsigned>(func_body_.end - func_body_.start), decode_ms,
4765 0 : node_count, pipeline_ms);
4766 : }
4767 : // The graph zone is about to get out of scope. Avoid invalid references.
4768 227922 : jsgraph_ = nullptr;
4769 : }
4770 :
4771 : // Record the memory cost this unit places on the system until
4772 : // it is finalized.
4773 227977 : size_t cost = job_->AllocatedMemory();
4774 : set_memory_cost(cost);
4775 : }
4776 :
4777 233497 : MaybeHandle<Code> WasmCompilationUnit::FinishCompilation(
4778 : wasm::ErrorThrower* thrower) {
4779 233497 : if (!ok_) {
4780 5743 : if (graph_construction_result_.failed()) {
4781 : // Add the function as another context for the exception.
4782 : EmbeddedVector<char, 128> message;
4783 5743 : if (func_name_.start() == nullptr) {
4784 5483 : SNPrintF(message, "Compiling wasm function #%d failed", func_index_);
4785 : } else {
4786 : wasm::TruncatedUserString<> trunc_name(func_name_);
4787 : SNPrintF(message, "Compiling wasm function #%d:%.*s failed",
4788 260 : func_index_, trunc_name.length(), trunc_name.start());
4789 : }
4790 5743 : thrower->CompileFailed(message.start(), graph_construction_result_);
4791 : }
4792 :
4793 5743 : return {};
4794 : }
4795 : base::ElapsedTimer codegen_timer;
4796 227754 : if (FLAG_trace_wasm_decode_time) {
4797 : codegen_timer.Start();
4798 : }
4799 227754 : if (job_->FinalizeJob() != CompilationJob::SUCCEEDED) {
4800 0 : return Handle<Code>::null();
4801 : }
4802 : Handle<Code> code = info_->code();
4803 : DCHECK(!code.is_null());
4804 :
4805 455508 : if (must_record_function_compilation(isolate_)) {
4806 : wasm::TruncatedUserString<> trunc_name(func_name_);
4807 : RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate_, code,
4808 : "wasm_function#%d:%.*s", func_index_,
4809 0 : trunc_name.length(), trunc_name.start());
4810 : }
4811 :
4812 227754 : if (FLAG_trace_wasm_decode_time) {
4813 0 : double codegen_ms = codegen_timer.Elapsed().InMillisecondsF();
4814 : PrintF("wasm-code-generation ok: %u bytes, %0.3f ms code generation\n",
4815 0 : static_cast<unsigned>(func_body_.end - func_body_.start),
4816 0 : codegen_ms);
4817 : }
4818 :
4819 227754 : return code;
4820 : }
4821 :
4822 : // static
4823 143535 : MaybeHandle<Code> WasmCompilationUnit::CompileWasmFunction(
4824 : wasm::ErrorThrower* thrower, Isolate* isolate,
4825 : const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env,
4826 : const wasm::WasmFunction* function) {
4827 : wasm::FunctionBody function_body{
4828 143535 : function->sig, function->code.offset(),
4829 143535 : wire_bytes.start() + function->code.offset(),
4830 287070 : wire_bytes.start() + function->code.end_offset()};
4831 : WasmCompilationUnit unit(
4832 : isolate, env, function_body, wire_bytes.GetNameOrNull(function),
4833 287070 : function->func_index, CEntryStub(isolate, 1).GetCode());
4834 143535 : unit.ExecuteCompilation();
4835 143535 : return unit.FinishCompilation(thrower);
4836 : }
4837 :
4838 : #undef WASM_64
4839 : #undef FATAL_UNSUPPORTED_OPCODE
4840 :
4841 : } // namespace compiler
4842 : } // namespace internal
4843 : } // namespace v8
|