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/assembler.h" 11 #include "src/base/optional.h" 12 #include "src/base/platform/elapsed-timer.h" 13 #include "src/base/platform/platform.h" 14 #include "src/base/v8-fallthrough.h" 15 #include "src/builtins/builtins.h" 16 #include "src/code-factory.h" 17 #include "src/compiler.h" 18 #include "src/compiler/access-builder.h" 19 #include "src/compiler/code-generator.h" 20 #include "src/compiler/common-operator.h" 21 #include "src/compiler/compiler-source-position-table.h" 22 #include "src/compiler/diamond.h" 23 #include "src/compiler/graph-visualizer.h" 24 #include "src/compiler/graph.h" 25 #include "src/compiler/instruction-selector.h" 26 #include "src/compiler/int64-lowering.h" 27 #include "src/compiler/js-graph.h" 28 #include "src/compiler/js-operator.h" 29 #include "src/compiler/linkage.h" 30 #include "src/compiler/machine-operator.h" 31 #include "src/compiler/node-matchers.h" 32 #include "src/compiler/node-origin-table.h" 33 #include "src/compiler/pipeline.h" 34 #include "src/compiler/simd-scalar-lowering.h" 35 #include "src/compiler/zone-stats.h" 36 #include "src/heap/factory.h" 37 #include "src/isolate-inl.h" 38 #include "src/log-inl.h" 39 #include "src/optimized-compilation-info.h" 40 #include "src/tracing/trace-event.h" 41 #include "src/trap-handler/trap-handler.h" 42 #include "src/wasm/function-body-decoder.h" 43 #include "src/wasm/function-compiler.h" 44 #include "src/wasm/jump-table-assembler.h" 45 #include "src/wasm/memory-tracing.h" 46 #include "src/wasm/wasm-code-manager.h" 47 #include "src/wasm/wasm-limits.h" 48 #include "src/wasm/wasm-linkage.h" 49 #include "src/wasm/wasm-module.h" 50 #include "src/wasm/wasm-objects-inl.h" 51 #include "src/wasm/wasm-opcodes.h" 52 #include "src/wasm/wasm-text.h" 53 54 namespace v8 { 55 namespace internal { 56 namespace compiler { 57 58 // TODO(titzer): pull WASM_64 up to a common header. 59 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 60 #define WASM_64 1 61 #else 62 #define WASM_64 0 63 #endif 64 65 #define FATAL_UNSUPPORTED_OPCODE(opcode) \ 66 FATAL("Unsupported opcode 0x%x:%s", (opcode), \ 67 wasm::WasmOpcodes::OpcodeName(opcode)); 68 69 #define WASM_INSTANCE_OBJECT_OFFSET(name) \ 70 (WasmInstanceObject::k##name##Offset - kHeapObjectTag) 71 72 #define LOAD_INSTANCE_FIELD(name, type) \ 73 SetEffect(graph()->NewNode( \ 74 mcgraph()->machine()->Load(type), instance_node_.get(), \ 75 mcgraph()->Int32Constant(WASM_INSTANCE_OBJECT_OFFSET(name)), Effect(), \ 76 Control())) 77 78 #define LOAD_FIXED_ARRAY_SLOT(array_node, index) \ 79 SetEffect(graph()->NewNode( \ 80 mcgraph()->machine()->Load(MachineType::TaggedPointer()), array_node, \ 81 mcgraph()->Int32Constant(FixedArrayOffsetMinusTag(index)), Effect(), \ 82 Control())) 83 84 int FixedArrayOffsetMinusTag(uint32_t index) { 85 auto access = AccessBuilder::ForFixedArraySlot(index); 86 return access.offset - access.tag(); 87 } 88 89 namespace { 90 91 constexpr uint32_t kBytesPerExceptionValuesArrayElement = 2; 92 93 void MergeControlToEnd(MachineGraph* mcgraph, Node* node) { 94 Graph* g = mcgraph->graph(); 95 if (g->end()) { 96 NodeProperties::MergeControlToEnd(g, mcgraph->common(), node); 97 } else { 98 g->SetEnd(g->NewNode(mcgraph->common()->End(1), node)); 99 } 100 } 101 102 bool ContainsSimd(wasm::FunctionSig* sig) { 103 for (auto type : sig->all()) { 104 if (type == wasm::kWasmS128) return true; 105 } 106 return false; 107 } 108 109 bool ContainsInt64(wasm::FunctionSig* sig) { 110 for (auto type : sig->all()) { 111 if (type == wasm::kWasmI64) return true; 112 } 113 return false; 114 } 115 } // namespace 116 117 WasmGraphBuilder::WasmGraphBuilder( 118 wasm::ModuleEnv* env, Zone* zone, MachineGraph* mcgraph, 119 wasm::FunctionSig* sig, 120 compiler::SourcePositionTable* source_position_table) 121 : zone_(zone), 122 mcgraph_(mcgraph), 123 env_(env), 124 cur_buffer_(def_buffer_), 125 cur_bufsize_(kDefaultBufferSize), 126 has_simd_(ContainsSimd(sig)), 127 untrusted_code_mitigations_(FLAG_untrusted_code_mitigations), 128 sig_(sig), 129 source_position_table_(source_position_table) { 130 DCHECK_IMPLIES(use_trap_handler(), trap_handler::IsTrapHandlerEnabled()); 131 DCHECK_NOT_NULL(mcgraph_); 132 } 133 134 Node* WasmGraphBuilder::Error() { return mcgraph()->Dead(); } 135 136 Node* WasmGraphBuilder::Start(unsigned params) { 137 Node* start = graph()->NewNode(mcgraph()->common()->Start(params)); 138 graph()->SetStart(start); 139 return start; 140 } 141 142 Node* WasmGraphBuilder::Param(unsigned index) { 143 return graph()->NewNode(mcgraph()->common()->Parameter(index), 144 graph()->start()); 145 } 146 147 Node* WasmGraphBuilder::Loop(Node* entry) { 148 return graph()->NewNode(mcgraph()->common()->Loop(1), entry); 149 } 150 151 Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) { 152 Node* terminate = 153 graph()->NewNode(mcgraph()->common()->Terminate(), effect, control); 154 MergeControlToEnd(mcgraph(), terminate); 155 return terminate; 156 } 157 158 bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) { 159 return phi && IrOpcode::IsPhiOpcode(phi->opcode()) && 160 NodeProperties::GetControlInput(phi) == merge; 161 } 162 163 bool WasmGraphBuilder::ThrowsException(Node* node, Node** if_success, 164 Node** if_exception) { 165 if (node->op()->HasProperty(compiler::Operator::kNoThrow)) { 166 return false; 167 } 168 169 *if_success = graph()->NewNode(mcgraph()->common()->IfSuccess(), node); 170 *if_exception = 171 graph()->NewNode(mcgraph()->common()->IfException(), node, node); 172 173 return true; 174 } 175 176 void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) { 177 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode())); 178 merge->AppendInput(mcgraph()->zone(), from); 179 int new_size = merge->InputCount(); 180 NodeProperties::ChangeOp( 181 merge, mcgraph()->common()->ResizeMergeOrPhi(merge->op(), new_size)); 182 } 183 184 void WasmGraphBuilder::AppendToPhi(Node* phi, Node* from) { 185 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode())); 186 int new_size = phi->InputCount(); 187 phi->InsertInput(mcgraph()->zone(), phi->InputCount() - 1, from); 188 NodeProperties::ChangeOp( 189 phi, mcgraph()->common()->ResizeMergeOrPhi(phi->op(), new_size)); 190 } 191 192 Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) { 193 return graph()->NewNode(mcgraph()->common()->Merge(count), count, controls); 194 } 195 196 Node* WasmGraphBuilder::Phi(wasm::ValueType type, unsigned count, Node** vals, 197 Node* control) { 198 DCHECK(IrOpcode::IsMergeOpcode(control->opcode())); 199 Node** buf = Realloc(vals, count, count + 1); 200 buf[count] = control; 201 return graph()->NewNode( 202 mcgraph()->common()->Phi(wasm::ValueTypes::MachineRepresentationFor(type), 203 count), 204 count + 1, buf); 205 } 206 207 Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects, 208 Node* control) { 209 DCHECK(IrOpcode::IsMergeOpcode(control->opcode())); 210 Node** buf = Realloc(effects, count, count + 1); 211 buf[count] = control; 212 return graph()->NewNode(mcgraph()->common()->EffectPhi(count), count + 1, 213 buf); 214 } 215 216 Node* WasmGraphBuilder::RefNull() { 217 return LOAD_INSTANCE_FIELD(NullValue, MachineType::TaggedPointer()); 218 } 219 220 Node* WasmGraphBuilder::NoContextConstant() { 221 // TODO(titzer): avoiding a dependency on JSGraph here. Refactor. 222 return mcgraph()->IntPtrConstant(0); 223 } 224 225 Node* WasmGraphBuilder::Uint32Constant(uint32_t value) { 226 return mcgraph()->Uint32Constant(value); 227 } 228 229 Node* WasmGraphBuilder::Int32Constant(int32_t value) { 230 return mcgraph()->Int32Constant(value); 231 } 232 233 Node* WasmGraphBuilder::Int64Constant(int64_t value) { 234 return mcgraph()->Int64Constant(value); 235 } 236 237 Node* WasmGraphBuilder::IntPtrConstant(intptr_t value) { 238 return mcgraph()->IntPtrConstant(value); 239 } 240 241 void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position, 242 Node** effect, Node** control) { 243 DCHECK_NOT_NULL(env_); // Wrappers don't get stack checks. 244 if (FLAG_wasm_no_stack_checks || !env_->runtime_exception_support) { 245 return; 246 } 247 if (effect == nullptr) effect = effect_; 248 if (control == nullptr) control = control_; 249 250 // This instruction sequence is matched in the instruction selector to 251 // load the stack pointer directly on some platforms. Hence, when modifying 252 // please also fix WasmStackCheckMatcher in node-matchers.h 253 254 Node* limit_address = graph()->NewNode( 255 mcgraph()->machine()->Load(MachineType::Pointer()), instance_node_.get(), 256 mcgraph()->Int32Constant(WASM_INSTANCE_OBJECT_OFFSET(StackLimitAddress)), 257 *effect, *control); 258 Node* limit = graph()->NewNode( 259 mcgraph()->machine()->Load(MachineType::Pointer()), limit_address, 260 mcgraph()->IntPtrConstant(0), limit_address, *control); 261 *effect = limit; 262 Node* pointer = graph()->NewNode(mcgraph()->machine()->LoadStackPointer()); 263 264 Node* check = 265 graph()->NewNode(mcgraph()->machine()->UintLessThan(), limit, pointer); 266 267 Diamond stack_check(graph(), mcgraph()->common(), check, BranchHint::kTrue); 268 stack_check.Chain(*control); 269 270 if (stack_check_call_operator_ == nullptr) { 271 // Build and cache the stack check call operator and the constant 272 // representing the stack check code. 273 auto call_descriptor = Linkage::GetStubCallDescriptor( 274 mcgraph()->zone(), // zone 275 NoContextDescriptor{}, // descriptor 276 0, // stack parameter count 277 CallDescriptor::kNoFlags, // flags 278 Operator::kNoProperties, // properties 279 StubCallMode::kCallWasmRuntimeStub); // stub call mode 280 // A direct call to a wasm runtime stub defined in this module. 281 // Just encode the stub index. This will be patched at relocation. 282 stack_check_code_node_.set(mcgraph()->RelocatableIntPtrConstant( 283 wasm::WasmCode::kWasmStackGuard, RelocInfo::WASM_STUB_CALL)); 284 stack_check_call_operator_ = mcgraph()->common()->Call(call_descriptor); 285 } 286 287 Node* call = graph()->NewNode(stack_check_call_operator_.get(), 288 stack_check_code_node_.get(), *effect, 289 stack_check.if_false); 290 291 SetSourcePosition(call, position); 292 293 Node* ephi = stack_check.EffectPhi(*effect, call); 294 295 *control = stack_check.merge; 296 *effect = ephi; 297 } 298 299 void WasmGraphBuilder::PatchInStackCheckIfNeeded() { 300 if (!needs_stack_check_) return; 301 302 Node* start = graph()->start(); 303 // Place a stack check which uses a dummy node as control and effect. 304 Node* dummy = graph()->NewNode(mcgraph()->common()->Dead()); 305 Node* control = dummy; 306 Node* effect = dummy; 307 // The function-prologue stack check is associated with position 0, which 308 // is never a position of any instruction in the function. 309 StackCheck(0, &effect, &control); 310 311 // In testing, no steck checks were emitted. Nothing to rewire then. 312 if (effect == dummy) return; 313 314 // Now patch all control uses of {start} to use {control} and all effect uses 315 // to use {effect} instead. Then rewire the dummy node to use start instead. 316 NodeProperties::ReplaceUses(start, start, effect, control); 317 NodeProperties::ReplaceUses(dummy, nullptr, start, start); 318 } 319 320 Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right, 321 wasm::WasmCodePosition position) { 322 const Operator* op; 323 MachineOperatorBuilder* m = mcgraph()->machine(); 324 switch (opcode) { 325 case wasm::kExprI32Add: 326 op = m->Int32Add(); 327 break; 328 case wasm::kExprI32Sub: 329 op = m->Int32Sub(); 330 break; 331 case wasm::kExprI32Mul: 332 op = m->Int32Mul(); 333 break; 334 case wasm::kExprI32DivS: 335 return BuildI32DivS(left, right, position); 336 case wasm::kExprI32DivU: 337 return BuildI32DivU(left, right, position); 338 case wasm::kExprI32RemS: 339 return BuildI32RemS(left, right, position); 340 case wasm::kExprI32RemU: 341 return BuildI32RemU(left, right, position); 342 case wasm::kExprI32And: 343 op = m->Word32And(); 344 break; 345 case wasm::kExprI32Ior: 346 op = m->Word32Or(); 347 break; 348 case wasm::kExprI32Xor: 349 op = m->Word32Xor(); 350 break; 351 case wasm::kExprI32Shl: 352 op = m->Word32Shl(); 353 right = MaskShiftCount32(right); 354 break; 355 case wasm::kExprI32ShrU: 356 op = m->Word32Shr(); 357 right = MaskShiftCount32(right); 358 break; 359 case wasm::kExprI32ShrS: 360 op = m->Word32Sar(); 361 right = MaskShiftCount32(right); 362 break; 363 case wasm::kExprI32Ror: 364 op = m->Word32Ror(); 365 right = MaskShiftCount32(right); 366 break; 367 case wasm::kExprI32Rol: 368 right = MaskShiftCount32(right); 369 return BuildI32Rol(left, right); 370 case wasm::kExprI32Eq: 371 op = m->Word32Equal(); 372 break; 373 case wasm::kExprI32Ne: 374 return Invert(Binop(wasm::kExprI32Eq, left, right)); 375 case wasm::kExprI32LtS: 376 op = m->Int32LessThan(); 377 break; 378 case wasm::kExprI32LeS: 379 op = m->Int32LessThanOrEqual(); 380 break; 381 case wasm::kExprI32LtU: 382 op = m->Uint32LessThan(); 383 break; 384 case wasm::kExprI32LeU: 385 op = m->Uint32LessThanOrEqual(); 386 break; 387 case wasm::kExprI32GtS: 388 op = m->Int32LessThan(); 389 std::swap(left, right); 390 break; 391 case wasm::kExprI32GeS: 392 op = m->Int32LessThanOrEqual(); 393 std::swap(left, right); 394 break; 395 case wasm::kExprI32GtU: 396 op = m->Uint32LessThan(); 397 std::swap(left, right); 398 break; 399 case wasm::kExprI32GeU: 400 op = m->Uint32LessThanOrEqual(); 401 std::swap(left, right); 402 break; 403 case wasm::kExprI64And: 404 op = m->Word64And(); 405 break; 406 case wasm::kExprI64Add: 407 op = m->Int64Add(); 408 break; 409 case wasm::kExprI64Sub: 410 op = m->Int64Sub(); 411 break; 412 case wasm::kExprI64Mul: 413 op = m->Int64Mul(); 414 break; 415 case wasm::kExprI64DivS: 416 return BuildI64DivS(left, right, position); 417 case wasm::kExprI64DivU: 418 return BuildI64DivU(left, right, position); 419 case wasm::kExprI64RemS: 420 return BuildI64RemS(left, right, position); 421 case wasm::kExprI64RemU: 422 return BuildI64RemU(left, right, position); 423 case wasm::kExprI64Ior: 424 op = m->Word64Or(); 425 break; 426 case wasm::kExprI64Xor: 427 op = m->Word64Xor(); 428 break; 429 case wasm::kExprI64Shl: 430 op = m->Word64Shl(); 431 right = MaskShiftCount64(right); 432 break; 433 case wasm::kExprI64ShrU: 434 op = m->Word64Shr(); 435 right = MaskShiftCount64(right); 436 break; 437 case wasm::kExprI64ShrS: 438 op = m->Word64Sar(); 439 right = MaskShiftCount64(right); 440 break; 441 case wasm::kExprI64Eq: 442 op = m->Word64Equal(); 443 break; 444 case wasm::kExprI64Ne: 445 return Invert(Binop(wasm::kExprI64Eq, left, right)); 446 case wasm::kExprI64LtS: 447 op = m->Int64LessThan(); 448 break; 449 case wasm::kExprI64LeS: 450 op = m->Int64LessThanOrEqual(); 451 break; 452 case wasm::kExprI64LtU: 453 op = m->Uint64LessThan(); 454 break; 455 case wasm::kExprI64LeU: 456 op = m->Uint64LessThanOrEqual(); 457 break; 458 case wasm::kExprI64GtS: 459 op = m->Int64LessThan(); 460 std::swap(left, right); 461 break; 462 case wasm::kExprI64GeS: 463 op = m->Int64LessThanOrEqual(); 464 std::swap(left, right); 465 break; 466 case wasm::kExprI64GtU: 467 op = m->Uint64LessThan(); 468 std::swap(left, right); 469 break; 470 case wasm::kExprI64GeU: 471 op = m->Uint64LessThanOrEqual(); 472 std::swap(left, right); 473 break; 474 case wasm::kExprI64Ror: 475 op = m->Word64Ror(); 476 right = MaskShiftCount64(right); 477 break; 478 case wasm::kExprI64Rol: 479 return BuildI64Rol(left, right); 480 case wasm::kExprF32CopySign: 481 return BuildF32CopySign(left, right); 482 case wasm::kExprF64CopySign: 483 return BuildF64CopySign(left, right); 484 case wasm::kExprF32Add: 485 op = m->Float32Add(); 486 break; 487 case wasm::kExprF32Sub: 488 op = m->Float32Sub(); 489 break; 490 case wasm::kExprF32Mul: 491 op = m->Float32Mul(); 492 break; 493 case wasm::kExprF32Div: 494 op = m->Float32Div(); 495 break; 496 case wasm::kExprF32Eq: 497 op = m->Float32Equal(); 498 break; 499 case wasm::kExprF32Ne: 500 return Invert(Binop(wasm::kExprF32Eq, left, right)); 501 case wasm::kExprF32Lt: 502 op = m->Float32LessThan(); 503 break; 504 case wasm::kExprF32Ge: 505 op = m->Float32LessThanOrEqual(); 506 std::swap(left, right); 507 break; 508 case wasm::kExprF32Gt: 509 op = m->Float32LessThan(); 510 std::swap(left, right); 511 break; 512 case wasm::kExprF32Le: 513 op = m->Float32LessThanOrEqual(); 514 break; 515 case wasm::kExprF64Add: 516 op = m->Float64Add(); 517 break; 518 case wasm::kExprF64Sub: 519 op = m->Float64Sub(); 520 break; 521 case wasm::kExprF64Mul: 522 op = m->Float64Mul(); 523 break; 524 case wasm::kExprF64Div: 525 op = m->Float64Div(); 526 break; 527 case wasm::kExprF64Eq: 528 op = m->Float64Equal(); 529 break; 530 case wasm::kExprF64Ne: 531 return Invert(Binop(wasm::kExprF64Eq, left, right)); 532 case wasm::kExprF64Lt: 533 op = m->Float64LessThan(); 534 break; 535 case wasm::kExprF64Le: 536 op = m->Float64LessThanOrEqual(); 537 break; 538 case wasm::kExprF64Gt: 539 op = m->Float64LessThan(); 540 std::swap(left, right); 541 break; 542 case wasm::kExprF64Ge: 543 op = m->Float64LessThanOrEqual(); 544 std::swap(left, right); 545 break; 546 case wasm::kExprF32Min: 547 op = m->Float32Min(); 548 break; 549 case wasm::kExprF64Min: 550 op = m->Float64Min(); 551 break; 552 case wasm::kExprF32Max: 553 op = m->Float32Max(); 554 break; 555 case wasm::kExprF64Max: 556 op = m->Float64Max(); 557 break; 558 case wasm::kExprF64Pow: 559 return BuildF64Pow(left, right); 560 case wasm::kExprF64Atan2: 561 op = m->Float64Atan2(); 562 break; 563 case wasm::kExprF64Mod: 564 return BuildF64Mod(left, right); 565 case wasm::kExprI32AsmjsDivS: 566 return BuildI32AsmjsDivS(left, right); 567 case wasm::kExprI32AsmjsDivU: 568 return BuildI32AsmjsDivU(left, right); 569 case wasm::kExprI32AsmjsRemS: 570 return BuildI32AsmjsRemS(left, right); 571 case wasm::kExprI32AsmjsRemU: 572 return BuildI32AsmjsRemU(left, right); 573 case wasm::kExprI32AsmjsStoreMem8: 574 return BuildAsmjsStoreMem(MachineType::Int8(), left, right); 575 case wasm::kExprI32AsmjsStoreMem16: 576 return BuildAsmjsStoreMem(MachineType::Int16(), left, right); 577 case wasm::kExprI32AsmjsStoreMem: 578 return BuildAsmjsStoreMem(MachineType::Int32(), left, right); 579 case wasm::kExprF32AsmjsStoreMem: 580 return BuildAsmjsStoreMem(MachineType::Float32(), left, right); 581 case wasm::kExprF64AsmjsStoreMem: 582 return BuildAsmjsStoreMem(MachineType::Float64(), left, right); 583 default: 584 FATAL_UNSUPPORTED_OPCODE(opcode); 585 } 586 return graph()->NewNode(op, left, right); 587 } 588 589 Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input, 590 wasm::WasmCodePosition position) { 591 const Operator* op; 592 MachineOperatorBuilder* m = mcgraph()->machine(); 593 switch (opcode) { 594 case wasm::kExprI32Eqz: 595 op = m->Word32Equal(); 596 return graph()->NewNode(op, input, mcgraph()->Int32Constant(0)); 597 case wasm::kExprF32Abs: 598 op = m->Float32Abs(); 599 break; 600 case wasm::kExprF32Neg: { 601 op = m->Float32Neg(); 602 break; 603 } 604 case wasm::kExprF32Sqrt: 605 op = m->Float32Sqrt(); 606 break; 607 case wasm::kExprF64Abs: 608 op = m->Float64Abs(); 609 break; 610 case wasm::kExprF64Neg: { 611 op = m->Float64Neg(); 612 break; 613 } 614 case wasm::kExprF64Sqrt: 615 op = m->Float64Sqrt(); 616 break; 617 case wasm::kExprI32SConvertF32: 618 case wasm::kExprI32UConvertF32: 619 case wasm::kExprI32SConvertF64: 620 case wasm::kExprI32UConvertF64: 621 case wasm::kExprI32SConvertSatF64: 622 case wasm::kExprI32UConvertSatF64: 623 case wasm::kExprI32SConvertSatF32: 624 case wasm::kExprI32UConvertSatF32: 625 return BuildIntConvertFloat(input, position, opcode); 626 case wasm::kExprI32AsmjsSConvertF64: 627 return BuildI32AsmjsSConvertF64(input); 628 case wasm::kExprI32AsmjsUConvertF64: 629 return BuildI32AsmjsUConvertF64(input); 630 case wasm::kExprF32ConvertF64: 631 op = m->TruncateFloat64ToFloat32(); 632 break; 633 case wasm::kExprF64SConvertI32: 634 op = m->ChangeInt32ToFloat64(); 635 break; 636 case wasm::kExprF64UConvertI32: 637 op = m->ChangeUint32ToFloat64(); 638 break; 639 case wasm::kExprF32SConvertI32: 640 op = m->RoundInt32ToFloat32(); 641 break; 642 case wasm::kExprF32UConvertI32: 643 op = m->RoundUint32ToFloat32(); 644 break; 645 case wasm::kExprI32AsmjsSConvertF32: 646 return BuildI32AsmjsSConvertF32(input); 647 case wasm::kExprI32AsmjsUConvertF32: 648 return BuildI32AsmjsUConvertF32(input); 649 case wasm::kExprF64ConvertF32: 650 op = m->ChangeFloat32ToFloat64(); 651 break; 652 case wasm::kExprF32ReinterpretI32: 653 op = m->BitcastInt32ToFloat32(); 654 break; 655 case wasm::kExprI32ReinterpretF32: 656 op = m->BitcastFloat32ToInt32(); 657 break; 658 case wasm::kExprI32Clz: 659 op = m->Word32Clz(); 660 break; 661 case wasm::kExprI32Ctz: { 662 if (m->Word32Ctz().IsSupported()) { 663 op = m->Word32Ctz().op(); 664 break; 665 } else if (m->Word32ReverseBits().IsSupported()) { 666 Node* reversed = graph()->NewNode(m->Word32ReverseBits().op(), input); 667 Node* result = graph()->NewNode(m->Word32Clz(), reversed); 668 return result; 669 } else { 670 return BuildI32Ctz(input); 671 } 672 } 673 case wasm::kExprI32Popcnt: { 674 if (m->Word32Popcnt().IsSupported()) { 675 op = m->Word32Popcnt().op(); 676 break; 677 } else { 678 return BuildI32Popcnt(input); 679 } 680 } 681 case wasm::kExprF32Floor: { 682 if (!m->Float32RoundDown().IsSupported()) return BuildF32Floor(input); 683 op = m->Float32RoundDown().op(); 684 break; 685 } 686 case wasm::kExprF32Ceil: { 687 if (!m->Float32RoundUp().IsSupported()) return BuildF32Ceil(input); 688 op = m->Float32RoundUp().op(); 689 break; 690 } 691 case wasm::kExprF32Trunc: { 692 if (!m->Float32RoundTruncate().IsSupported()) return BuildF32Trunc(input); 693 op = m->Float32RoundTruncate().op(); 694 break; 695 } 696 case wasm::kExprF32NearestInt: { 697 if (!m->Float32RoundTiesEven().IsSupported()) 698 return BuildF32NearestInt(input); 699 op = m->Float32RoundTiesEven().op(); 700 break; 701 } 702 case wasm::kExprF64Floor: { 703 if (!m->Float64RoundDown().IsSupported()) return BuildF64Floor(input); 704 op = m->Float64RoundDown().op(); 705 break; 706 } 707 case wasm::kExprF64Ceil: { 708 if (!m->Float64RoundUp().IsSupported()) return BuildF64Ceil(input); 709 op = m->Float64RoundUp().op(); 710 break; 711 } 712 case wasm::kExprF64Trunc: { 713 if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input); 714 op = m->Float64RoundTruncate().op(); 715 break; 716 } 717 case wasm::kExprF64NearestInt: { 718 if (!m->Float64RoundTiesEven().IsSupported()) 719 return BuildF64NearestInt(input); 720 op = m->Float64RoundTiesEven().op(); 721 break; 722 } 723 case wasm::kExprF64Acos: { 724 return BuildF64Acos(input); 725 } 726 case wasm::kExprF64Asin: { 727 return BuildF64Asin(input); 728 } 729 case wasm::kExprF64Atan: 730 op = m->Float64Atan(); 731 break; 732 case wasm::kExprF64Cos: { 733 op = m->Float64Cos(); 734 break; 735 } 736 case wasm::kExprF64Sin: { 737 op = m->Float64Sin(); 738 break; 739 } 740 case wasm::kExprF64Tan: { 741 op = m->Float64Tan(); 742 break; 743 } 744 case wasm::kExprF64Exp: { 745 op = m->Float64Exp(); 746 break; 747 } 748 case wasm::kExprF64Log: 749 op = m->Float64Log(); 750 break; 751 case wasm::kExprI32ConvertI64: 752 op = m->TruncateInt64ToInt32(); 753 break; 754 case wasm::kExprI64SConvertI32: 755 op = m->ChangeInt32ToInt64(); 756 break; 757 case wasm::kExprI64UConvertI32: 758 op = m->ChangeUint32ToUint64(); 759 break; 760 case wasm::kExprF64ReinterpretI64: 761 op = m->BitcastInt64ToFloat64(); 762 break; 763 case wasm::kExprI64ReinterpretF64: 764 op = m->BitcastFloat64ToInt64(); 765 break; 766 case wasm::kExprI64Clz: 767 op = m->Word64Clz(); 768 break; 769 case wasm::kExprI64Ctz: { 770 OptionalOperator ctz64 = m->Word64Ctz(); 771 if (ctz64.IsSupported()) { 772 op = ctz64.op(); 773 break; 774 } else if (m->Is32() && m->Word32Ctz().IsSupported()) { 775 op = ctz64.placeholder(); 776 break; 777 } else if (m->Word64ReverseBits().IsSupported()) { 778 Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input); 779 Node* result = graph()->NewNode(m->Word64Clz(), reversed); 780 return result; 781 } else { 782 return BuildI64Ctz(input); 783 } 784 } 785 case wasm::kExprI64Popcnt: { 786 OptionalOperator popcnt64 = m->Word64Popcnt(); 787 if (popcnt64.IsSupported()) { 788 op = popcnt64.op(); 789 } else if (m->Is32() && m->Word32Popcnt().IsSupported()) { 790 op = popcnt64.placeholder(); 791 } else { 792 return BuildI64Popcnt(input); 793 } 794 break; 795 } 796 case wasm::kExprI64Eqz: 797 op = m->Word64Equal(); 798 return graph()->NewNode(op, input, mcgraph()->Int64Constant(0)); 799 case wasm::kExprF32SConvertI64: 800 if (m->Is32()) { 801 return BuildF32SConvertI64(input); 802 } 803 op = m->RoundInt64ToFloat32(); 804 break; 805 case wasm::kExprF32UConvertI64: 806 if (m->Is32()) { 807 return BuildF32UConvertI64(input); 808 } 809 op = m->RoundUint64ToFloat32(); 810 break; 811 case wasm::kExprF64SConvertI64: 812 if (m->Is32()) { 813 return BuildF64SConvertI64(input); 814 } 815 op = m->RoundInt64ToFloat64(); 816 break; 817 case wasm::kExprF64UConvertI64: 818 if (m->Is32()) { 819 return BuildF64UConvertI64(input); 820 } 821 op = m->RoundUint64ToFloat64(); 822 break; 823 case wasm::kExprI32SExtendI8: 824 op = m->SignExtendWord8ToInt32(); 825 break; 826 case wasm::kExprI32SExtendI16: 827 op = m->SignExtendWord16ToInt32(); 828 break; 829 case wasm::kExprI64SExtendI8: 830 op = m->SignExtendWord8ToInt64(); 831 break; 832 case wasm::kExprI64SExtendI16: 833 op = m->SignExtendWord16ToInt64(); 834 break; 835 case wasm::kExprI64SExtendI32: 836 op = m->SignExtendWord32ToInt64(); 837 break; 838 case wasm::kExprI64SConvertF32: 839 case wasm::kExprI64UConvertF32: 840 case wasm::kExprI64SConvertF64: 841 case wasm::kExprI64UConvertF64: 842 case wasm::kExprI64SConvertSatF32: 843 case wasm::kExprI64UConvertSatF32: 844 case wasm::kExprI64SConvertSatF64: 845 case wasm::kExprI64UConvertSatF64: 846 return mcgraph()->machine()->Is32() 847 ? BuildCcallConvertFloat(input, position, opcode) 848 : BuildIntConvertFloat(input, position, opcode); 849 case wasm::kExprRefIsNull: 850 return graph()->NewNode(m->WordEqual(), input, RefNull()); 851 case wasm::kExprI32AsmjsLoadMem8S: 852 return BuildAsmjsLoadMem(MachineType::Int8(), input); 853 case wasm::kExprI32AsmjsLoadMem8U: 854 return BuildAsmjsLoadMem(MachineType::Uint8(), input); 855 case wasm::kExprI32AsmjsLoadMem16S: 856 return BuildAsmjsLoadMem(MachineType::Int16(), input); 857 case wasm::kExprI32AsmjsLoadMem16U: 858 return BuildAsmjsLoadMem(MachineType::Uint16(), input); 859 case wasm::kExprI32AsmjsLoadMem: 860 return BuildAsmjsLoadMem(MachineType::Int32(), input); 861 case wasm::kExprF32AsmjsLoadMem: 862 return BuildAsmjsLoadMem(MachineType::Float32(), input); 863 case wasm::kExprF64AsmjsLoadMem: 864 return BuildAsmjsLoadMem(MachineType::Float64(), input); 865 default: 866 FATAL_UNSUPPORTED_OPCODE(opcode); 867 } 868 return graph()->NewNode(op, input); 869 } 870 871 Node* WasmGraphBuilder::Float32Constant(float value) { 872 return mcgraph()->Float32Constant(value); 873 } 874 875 Node* WasmGraphBuilder::Float64Constant(double value) { 876 return mcgraph()->Float64Constant(value); 877 } 878 879 namespace { 880 Node* Branch(MachineGraph* mcgraph, Node* cond, Node** true_node, 881 Node** false_node, Node* control, BranchHint hint) { 882 DCHECK_NOT_NULL(cond); 883 DCHECK_NOT_NULL(control); 884 Node* branch = 885 mcgraph->graph()->NewNode(mcgraph->common()->Branch(hint), cond, control); 886 *true_node = mcgraph->graph()->NewNode(mcgraph->common()->IfTrue(), branch); 887 *false_node = mcgraph->graph()->NewNode(mcgraph->common()->IfFalse(), branch); 888 return branch; 889 } 890 } // namespace 891 892 Node* WasmGraphBuilder::BranchNoHint(Node* cond, Node** true_node, 893 Node** false_node) { 894 return Branch(mcgraph(), cond, true_node, false_node, Control(), 895 BranchHint::kNone); 896 } 897 898 Node* WasmGraphBuilder::BranchExpectTrue(Node* cond, Node** true_node, 899 Node** false_node) { 900 return Branch(mcgraph(), cond, true_node, false_node, Control(), 901 BranchHint::kTrue); 902 } 903 904 Node* WasmGraphBuilder::BranchExpectFalse(Node* cond, Node** true_node, 905 Node** false_node) { 906 return Branch(mcgraph(), cond, true_node, false_node, Control(), 907 BranchHint::kFalse); 908 } 909 910 TrapId WasmGraphBuilder::GetTrapIdForTrap(wasm::TrapReason reason) { 911 // TODO(wasm): "!env_" should not happen when compiling an actual wasm 912 // function. 913 if (!env_ || !env_->runtime_exception_support) { 914 // We use TrapId::kInvalid as a marker to tell the code generator 915 // to generate a call to a testing c-function instead of a runtime 916 // stub. This code should only be called from a cctest. 917 return TrapId::kInvalid; 918 } 919 920 switch (reason) { 921 #define TRAPREASON_TO_TRAPID(name) \ 922 case wasm::k##name: \ 923 static_assert( \ 924 static_cast<int>(TrapId::k##name) == wasm::WasmCode::kThrowWasm##name, \ 925 "trap id mismatch"); \ 926 return TrapId::k##name; 927 FOREACH_WASM_TRAPREASON(TRAPREASON_TO_TRAPID) 928 #undef TRAPREASON_TO_TRAPID 929 default: 930 UNREACHABLE(); 931 } 932 } 933 934 Node* WasmGraphBuilder::TrapIfTrue(wasm::TrapReason reason, Node* cond, 935 wasm::WasmCodePosition position) { 936 TrapId trap_id = GetTrapIdForTrap(reason); 937 Node* node = SetControl(graph()->NewNode(mcgraph()->common()->TrapIf(trap_id), 938 cond, Effect(), Control())); 939 SetSourcePosition(node, position); 940 return node; 941 } 942 943 Node* WasmGraphBuilder::TrapIfFalse(wasm::TrapReason reason, Node* cond, 944 wasm::WasmCodePosition position) { 945 TrapId trap_id = GetTrapIdForTrap(reason); 946 Node* node = SetControl(graph()->NewNode( 947 mcgraph()->common()->TrapUnless(trap_id), cond, Effect(), Control())); 948 SetSourcePosition(node, position); 949 return node; 950 } 951 952 // Add a check that traps if {node} is equal to {val}. 953 Node* WasmGraphBuilder::TrapIfEq32(wasm::TrapReason reason, Node* node, 954 int32_t val, 955 wasm::WasmCodePosition position) { 956 Int32Matcher m(node); 957 if (m.HasValue() && !m.Is(val)) return graph()->start(); 958 if (val == 0) { 959 return TrapIfFalse(reason, node, position); 960 } else { 961 return TrapIfTrue(reason, 962 graph()->NewNode(mcgraph()->machine()->Word32Equal(), 963 node, mcgraph()->Int32Constant(val)), 964 position); 965 } 966 } 967 968 // Add a check that traps if {node} is zero. 969 Node* WasmGraphBuilder::ZeroCheck32(wasm::TrapReason reason, Node* node, 970 wasm::WasmCodePosition position) { 971 return TrapIfEq32(reason, node, 0, position); 972 } 973 974 // Add a check that traps if {node} is equal to {val}. 975 Node* WasmGraphBuilder::TrapIfEq64(wasm::TrapReason reason, Node* node, 976 int64_t val, 977 wasm::WasmCodePosition position) { 978 Int64Matcher m(node); 979 if (m.HasValue() && !m.Is(val)) return graph()->start(); 980 return TrapIfTrue(reason, 981 graph()->NewNode(mcgraph()->machine()->Word64Equal(), node, 982 mcgraph()->Int64Constant(val)), 983 position); 984 } 985 986 // Add a check that traps if {node} is zero. 987 Node* WasmGraphBuilder::ZeroCheck64(wasm::TrapReason reason, Node* node, 988 wasm::WasmCodePosition position) { 989 return TrapIfEq64(reason, node, 0, position); 990 } 991 992 Node* WasmGraphBuilder::Switch(unsigned count, Node* key) { 993 return graph()->NewNode(mcgraph()->common()->Switch(count), key, Control()); 994 } 995 996 Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) { 997 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode()); 998 return graph()->NewNode(mcgraph()->common()->IfValue(value), sw); 999 } 1000 1001 Node* WasmGraphBuilder::IfDefault(Node* sw) { 1002 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode()); 1003 return graph()->NewNode(mcgraph()->common()->IfDefault(), sw); 1004 } 1005 1006 Node* WasmGraphBuilder::Return(unsigned count, Node** vals) { 1007 static const int kStackAllocatedNodeBufferSize = 8; 1008 Node* stack_buffer[kStackAllocatedNodeBufferSize]; 1009 std::vector<Node*> heap_buffer; 1010 1011 Node** buf = stack_buffer; 1012 if (count + 3 > kStackAllocatedNodeBufferSize) { 1013 heap_buffer.resize(count + 3); 1014 buf = heap_buffer.data(); 1015 } 1016 1017 buf[0] = mcgraph()->Int32Constant(0); 1018 memcpy(buf + 1, vals, sizeof(void*) * count); 1019 buf[count + 1] = Effect(); 1020 buf[count + 2] = Control(); 1021 Node* ret = 1022 graph()->NewNode(mcgraph()->common()->Return(count), count + 3, buf); 1023 1024 MergeControlToEnd(mcgraph(), ret); 1025 return ret; 1026 } 1027 1028 Node* WasmGraphBuilder::ReturnVoid() { return Return(0, nullptr); } 1029 1030 Node* WasmGraphBuilder::Unreachable(wasm::WasmCodePosition position) { 1031 TrapIfFalse(wasm::TrapReason::kTrapUnreachable, Int32Constant(0), position); 1032 ReturnVoid(); 1033 return nullptr; 1034 } 1035 1036 Node* WasmGraphBuilder::MaskShiftCount32(Node* node) { 1037 static const int32_t kMask32 = 0x1F; 1038 if (!mcgraph()->machine()->Word32ShiftIsSafe()) { 1039 // Shifts by constants are so common we pattern-match them here. 1040 Int32Matcher match(node); 1041 if (match.HasValue()) { 1042 int32_t masked = (match.Value() & kMask32); 1043 if (match.Value() != masked) node = mcgraph()->Int32Constant(masked); 1044 } else { 1045 node = graph()->NewNode(mcgraph()->machine()->Word32And(), node, 1046 mcgraph()->Int32Constant(kMask32)); 1047 } 1048 } 1049 return node; 1050 } 1051 1052 Node* WasmGraphBuilder::MaskShiftCount64(Node* node) { 1053 static const int64_t kMask64 = 0x3F; 1054 if (!mcgraph()->machine()->Word32ShiftIsSafe()) { 1055 // Shifts by constants are so common we pattern-match them here. 1056 Int64Matcher match(node); 1057 if (match.HasValue()) { 1058 int64_t masked = (match.Value() & kMask64); 1059 if (match.Value() != masked) node = mcgraph()->Int64Constant(masked); 1060 } else { 1061 node = graph()->NewNode(mcgraph()->machine()->Word64And(), node, 1062 mcgraph()->Int64Constant(kMask64)); 1063 } 1064 } 1065 return node; 1066 } 1067 1068 static bool ReverseBytesSupported(MachineOperatorBuilder* m, 1069 size_t size_in_bytes) { 1070 switch (size_in_bytes) { 1071 case 4: 1072 case 16: 1073 return true; 1074 case 8: 1075 return m->Is64(); 1076 default: 1077 break; 1078 } 1079 return false; 1080 } 1081 1082 Node* WasmGraphBuilder::BuildChangeEndiannessStore( 1083 Node* node, MachineRepresentation mem_rep, wasm::ValueType wasmtype) { 1084 Node* result; 1085 Node* value = node; 1086 MachineOperatorBuilder* m = mcgraph()->machine(); 1087 int valueSizeInBytes = wasm::ValueTypes::ElementSizeInBytes(wasmtype); 1088 int valueSizeInBits = 8 * valueSizeInBytes; 1089 bool isFloat = false; 1090 1091 switch (wasmtype) { 1092 case wasm::kWasmF64: 1093 value = graph()->NewNode(m->BitcastFloat64ToInt64(), node); 1094 isFloat = true; 1095 V8_FALLTHROUGH; 1096 case wasm::kWasmI64: 1097 result = mcgraph()->Int64Constant(0); 1098 break; 1099 case wasm::kWasmF32: 1100 value = graph()->NewNode(m->BitcastFloat32ToInt32(), node); 1101 isFloat = true; 1102 V8_FALLTHROUGH; 1103 case wasm::kWasmI32: 1104 result = mcgraph()->Int32Constant(0); 1105 break; 1106 case wasm::kWasmS128: 1107 DCHECK(ReverseBytesSupported(m, valueSizeInBytes)); 1108 break; 1109 default: 1110 UNREACHABLE(); 1111 break; 1112 } 1113 1114 if (mem_rep == MachineRepresentation::kWord8) { 1115 // No need to change endianness for byte size, return original node 1116 return node; 1117 } 1118 if (wasmtype == wasm::kWasmI64 && mem_rep < MachineRepresentation::kWord64) { 1119 // In case we store lower part of WasmI64 expression, we can truncate 1120 // upper 32bits 1121 value = graph()->NewNode(m->TruncateInt64ToInt32(), value); 1122 valueSizeInBytes = wasm::ValueTypes::ElementSizeInBytes(wasm::kWasmI32); 1123 valueSizeInBits = 8 * valueSizeInBytes; 1124 if (mem_rep == MachineRepresentation::kWord16) { 1125 value = 1126 graph()->NewNode(m->Word32Shl(), value, mcgraph()->Int32Constant(16)); 1127 } 1128 } else if (wasmtype == wasm::kWasmI32 && 1129 mem_rep == MachineRepresentation::kWord16) { 1130 value = 1131 graph()->NewNode(m->Word32Shl(), value, mcgraph()->Int32Constant(16)); 1132 } 1133 1134 int i; 1135 uint32_t shiftCount; 1136 1137 if (ReverseBytesSupported(m, valueSizeInBytes)) { 1138 switch (valueSizeInBytes) { 1139 case 4: 1140 result = graph()->NewNode(m->Word32ReverseBytes(), value); 1141 break; 1142 case 8: 1143 result = graph()->NewNode(m->Word64ReverseBytes(), value); 1144 break; 1145 case 16: { 1146 Node* byte_reversed_lanes[4]; 1147 for (int lane = 0; lane < 4; lane++) { 1148 byte_reversed_lanes[lane] = graph()->NewNode( 1149 m->Word32ReverseBytes(), 1150 graph()->NewNode(mcgraph()->machine()->I32x4ExtractLane(lane), 1151 value)); 1152 } 1153 1154 // This is making a copy of the value. 1155 result = 1156 graph()->NewNode(mcgraph()->machine()->S128And(), value, value); 1157 1158 for (int lane = 0; lane < 4; lane++) { 1159 result = 1160 graph()->NewNode(mcgraph()->machine()->I32x4ReplaceLane(3 - lane), 1161 result, byte_reversed_lanes[lane]); 1162 } 1163 1164 break; 1165 } 1166 default: 1167 UNREACHABLE(); 1168 break; 1169 } 1170 } else { 1171 for (i = 0, shiftCount = valueSizeInBits - 8; i < valueSizeInBits / 2; 1172 i += 8, shiftCount -= 16) { 1173 Node* shiftLower; 1174 Node* shiftHigher; 1175 Node* lowerByte; 1176 Node* higherByte; 1177 1178 DCHECK_LT(0, shiftCount); 1179 DCHECK_EQ(0, (shiftCount + 8) % 16); 1180 1181 if (valueSizeInBits > 32) { 1182 shiftLower = graph()->NewNode(m->Word64Shl(), value, 1183 mcgraph()->Int64Constant(shiftCount)); 1184 shiftHigher = graph()->NewNode(m->Word64Shr(), value, 1185 mcgraph()->Int64Constant(shiftCount)); 1186 lowerByte = graph()->NewNode( 1187 m->Word64And(), shiftLower, 1188 mcgraph()->Int64Constant(static_cast<uint64_t>(0xFF) 1189 << (valueSizeInBits - 8 - i))); 1190 higherByte = graph()->NewNode( 1191 m->Word64And(), shiftHigher, 1192 mcgraph()->Int64Constant(static_cast<uint64_t>(0xFF) << i)); 1193 result = graph()->NewNode(m->Word64Or(), result, lowerByte); 1194 result = graph()->NewNode(m->Word64Or(), result, higherByte); 1195 } else { 1196 shiftLower = graph()->NewNode(m->Word32Shl(), value, 1197 mcgraph()->Int32Constant(shiftCount)); 1198 shiftHigher = graph()->NewNode(m->Word32Shr(), value, 1199 mcgraph()->Int32Constant(shiftCount)); 1200 lowerByte = graph()->NewNode( 1201 m->Word32And(), shiftLower, 1202 mcgraph()->Int32Constant(static_cast<uint32_t>(0xFF) 1203 << (valueSizeInBits - 8 - i))); 1204 higherByte = graph()->NewNode( 1205 m->Word32And(), shiftHigher, 1206 mcgraph()->Int32Constant(static_cast<uint32_t>(0xFF) << i)); 1207 result = graph()->NewNode(m->Word32Or(), result, lowerByte); 1208 result = graph()->NewNode(m->Word32Or(), result, higherByte); 1209 } 1210 } 1211 } 1212 1213 if (isFloat) { 1214 switch (wasmtype) { 1215 case wasm::kWasmF64: 1216 result = graph()->NewNode(m->BitcastInt64ToFloat64(), result); 1217 break; 1218 case wasm::kWasmF32: 1219 result = graph()->NewNode(m->BitcastInt32ToFloat32(), result); 1220 break; 1221 default: 1222 UNREACHABLE(); 1223 break; 1224 } 1225 } 1226 1227 return result; 1228 } 1229 1230 Node* WasmGraphBuilder::BuildChangeEndiannessLoad(Node* node, 1231 MachineType memtype, 1232 wasm::ValueType wasmtype) { 1233 Node* result; 1234 Node* value = node; 1235 MachineOperatorBuilder* m = mcgraph()->machine(); 1236 int valueSizeInBytes = ElementSizeInBytes(memtype.representation()); 1237 int valueSizeInBits = 8 * valueSizeInBytes; 1238 bool isFloat = false; 1239 1240 switch (memtype.representation()) { 1241 case MachineRepresentation::kFloat64: 1242 value = graph()->NewNode(m->BitcastFloat64ToInt64(), node); 1243 isFloat = true; 1244 V8_FALLTHROUGH; 1245 case MachineRepresentation::kWord64: 1246 result = mcgraph()->Int64Constant(0); 1247 break; 1248 case MachineRepresentation::kFloat32: 1249 value = graph()->NewNode(m->BitcastFloat32ToInt32(), node); 1250 isFloat = true; 1251 V8_FALLTHROUGH; 1252 case MachineRepresentation::kWord32: 1253 case MachineRepresentation::kWord16: 1254 result = mcgraph()->Int32Constant(0); 1255 break; 1256 case MachineRepresentation::kWord8: 1257 // No need to change endianness for byte size, return original node 1258 return node; 1259 break; 1260 case MachineRepresentation::kSimd128: 1261 DCHECK(ReverseBytesSupported(m, valueSizeInBytes)); 1262 break; 1263 default: 1264 UNREACHABLE(); 1265 break; 1266 } 1267 1268 int i; 1269 uint32_t shiftCount; 1270 1271 if (ReverseBytesSupported(m, valueSizeInBytes < 4 ? 4 : valueSizeInBytes)) { 1272 switch (valueSizeInBytes) { 1273 case 2: 1274 result = 1275 graph()->NewNode(m->Word32ReverseBytes(), 1276 graph()->NewNode(m->Word32Shl(), value, 1277 mcgraph()->Int32Constant(16))); 1278 break; 1279 case 4: 1280 result = graph()->NewNode(m->Word32ReverseBytes(), value); 1281 break; 1282 case 8: 1283 result = graph()->NewNode(m->Word64ReverseBytes(), value); 1284 break; 1285 case 16: { 1286 Node* byte_reversed_lanes[4]; 1287 for (int lane = 0; lane < 4; lane++) { 1288 byte_reversed_lanes[lane] = graph()->NewNode( 1289 m->Word32ReverseBytes(), 1290 graph()->NewNode(mcgraph()->machine()->I32x4ExtractLane(lane), 1291 value)); 1292 } 1293 1294 // This is making a copy of the value. 1295 result = 1296 graph()->NewNode(mcgraph()->machine()->S128And(), value, value); 1297 1298 for (int lane = 0; lane < 4; lane++) { 1299 result = 1300 graph()->NewNode(mcgraph()->machine()->I32x4ReplaceLane(3 - lane), 1301 result, byte_reversed_lanes[lane]); 1302 } 1303 1304 break; 1305 } 1306 default: 1307 UNREACHABLE(); 1308 } 1309 } else { 1310 for (i = 0, shiftCount = valueSizeInBits - 8; i < valueSizeInBits / 2; 1311 i += 8, shiftCount -= 16) { 1312 Node* shiftLower; 1313 Node* shiftHigher; 1314 Node* lowerByte; 1315 Node* higherByte; 1316 1317 DCHECK_LT(0, shiftCount); 1318 DCHECK_EQ(0, (shiftCount + 8) % 16); 1319 1320 if (valueSizeInBits > 32) { 1321 shiftLower = graph()->NewNode(m->Word64Shl(), value, 1322 mcgraph()->Int64Constant(shiftCount)); 1323 shiftHigher = graph()->NewNode(m->Word64Shr(), value, 1324 mcgraph()->Int64Constant(shiftCount)); 1325 lowerByte = graph()->NewNode( 1326 m->Word64And(), shiftLower, 1327 mcgraph()->Int64Constant(static_cast<uint64_t>(0xFF) 1328 << (valueSizeInBits - 8 - i))); 1329 higherByte = graph()->NewNode( 1330 m->Word64And(), shiftHigher, 1331 mcgraph()->Int64Constant(static_cast<uint64_t>(0xFF) << i)); 1332 result = graph()->NewNode(m->Word64Or(), result, lowerByte); 1333 result = graph()->NewNode(m->Word64Or(), result, higherByte); 1334 } else { 1335 shiftLower = graph()->NewNode(m->Word32Shl(), value, 1336 mcgraph()->Int32Constant(shiftCount)); 1337 shiftHigher = graph()->NewNode(m->Word32Shr(), value, 1338 mcgraph()->Int32Constant(shiftCount)); 1339 lowerByte = graph()->NewNode( 1340 m->Word32And(), shiftLower, 1341 mcgraph()->Int32Constant(static_cast<uint32_t>(0xFF) 1342 << (valueSizeInBits - 8 - i))); 1343 higherByte = graph()->NewNode( 1344 m->Word32And(), shiftHigher, 1345 mcgraph()->Int32Constant(static_cast<uint32_t>(0xFF) << i)); 1346 result = graph()->NewNode(m->Word32Or(), result, lowerByte); 1347 result = graph()->NewNode(m->Word32Or(), result, higherByte); 1348 } 1349 } 1350 } 1351 1352 if (isFloat) { 1353 switch (memtype.representation()) { 1354 case MachineRepresentation::kFloat64: 1355 result = graph()->NewNode(m->BitcastInt64ToFloat64(), result); 1356 break; 1357 case MachineRepresentation::kFloat32: 1358 result = graph()->NewNode(m->BitcastInt32ToFloat32(), result); 1359 break; 1360 default: 1361 UNREACHABLE(); 1362 break; 1363 } 1364 } 1365 1366 // We need to sign extend the value 1367 if (memtype.IsSigned()) { 1368 DCHECK(!isFloat); 1369 if (valueSizeInBits < 32) { 1370 Node* shiftBitCount; 1371 // Perform sign extension using following trick 1372 // result = (x << machine_width - type_width) >> (machine_width - 1373 // type_width) 1374 if (wasmtype == wasm::kWasmI64) { 1375 shiftBitCount = mcgraph()->Int32Constant(64 - valueSizeInBits); 1376 result = graph()->NewNode( 1377 m->Word64Sar(), 1378 graph()->NewNode(m->Word64Shl(), 1379 graph()->NewNode(m->ChangeInt32ToInt64(), result), 1380 shiftBitCount), 1381 shiftBitCount); 1382 } else if (wasmtype == wasm::kWasmI32) { 1383 shiftBitCount = mcgraph()->Int32Constant(32 - valueSizeInBits); 1384 result = graph()->NewNode( 1385 m->Word32Sar(), 1386 graph()->NewNode(m->Word32Shl(), result, shiftBitCount), 1387 shiftBitCount); 1388 } 1389 } 1390 } 1391 1392 return result; 1393 } 1394 1395 Node* WasmGraphBuilder::BuildF32CopySign(Node* left, Node* right) { 1396 Node* result = Unop( 1397 wasm::kExprF32ReinterpretI32, 1398 Binop(wasm::kExprI32Ior, 1399 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, left), 1400 mcgraph()->Int32Constant(0x7FFFFFFF)), 1401 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, right), 1402 mcgraph()->Int32Constant(0x80000000)))); 1403 1404 return result; 1405 } 1406 1407 Node* WasmGraphBuilder::BuildF64CopySign(Node* left, Node* right) { 1408 #if WASM_64 1409 Node* result = Unop( 1410 wasm::kExprF64ReinterpretI64, 1411 Binop(wasm::kExprI64Ior, 1412 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, left), 1413 mcgraph()->Int64Constant(0x7FFFFFFFFFFFFFFF)), 1414 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, right), 1415 mcgraph()->Int64Constant(0x8000000000000000)))); 1416 1417 return result; 1418 #else 1419 MachineOperatorBuilder* m = mcgraph()->machine(); 1420 1421 Node* high_word_left = graph()->NewNode(m->Float64ExtractHighWord32(), left); 1422 Node* high_word_right = 1423 graph()->NewNode(m->Float64ExtractHighWord32(), right); 1424 1425 Node* new_high_word = Binop(wasm::kExprI32Ior, 1426 Binop(wasm::kExprI32And, high_word_left, 1427 mcgraph()->Int32Constant(0x7FFFFFFF)), 1428 Binop(wasm::kExprI32And, high_word_right, 1429 mcgraph()->Int32Constant(0x80000000))); 1430 1431 return graph()->NewNode(m->Float64InsertHighWord32(), left, new_high_word); 1432 #endif 1433 } 1434 1435 namespace { 1436 1437 MachineType IntConvertType(wasm::WasmOpcode opcode) { 1438 switch (opcode) { 1439 case wasm::kExprI32SConvertF32: 1440 case wasm::kExprI32SConvertF64: 1441 case wasm::kExprI32SConvertSatF32: 1442 case wasm::kExprI32SConvertSatF64: 1443 return MachineType::Int32(); 1444 case wasm::kExprI32UConvertF32: 1445 case wasm::kExprI32UConvertF64: 1446 case wasm::kExprI32UConvertSatF32: 1447 case wasm::kExprI32UConvertSatF64: 1448 return MachineType::Uint32(); 1449 case wasm::kExprI64SConvertF32: 1450 case wasm::kExprI64SConvertF64: 1451 case wasm::kExprI64SConvertSatF32: 1452 case wasm::kExprI64SConvertSatF64: 1453 return MachineType::Int64(); 1454 case wasm::kExprI64UConvertF32: 1455 case wasm::kExprI64UConvertF64: 1456 case wasm::kExprI64UConvertSatF32: 1457 case wasm::kExprI64UConvertSatF64: 1458 return MachineType::Uint64(); 1459 default: 1460 UNREACHABLE(); 1461 } 1462 } 1463 1464 MachineType FloatConvertType(wasm::WasmOpcode opcode) { 1465 switch (opcode) { 1466 case wasm::kExprI32SConvertF32: 1467 case wasm::kExprI32UConvertF32: 1468 case wasm::kExprI32SConvertSatF32: 1469 case wasm::kExprI64SConvertF32: 1470 case wasm::kExprI64UConvertF32: 1471 case wasm::kExprI32UConvertSatF32: 1472 case wasm::kExprI64SConvertSatF32: 1473 case wasm::kExprI64UConvertSatF32: 1474 return MachineType::Float32(); 1475 case wasm::kExprI32SConvertF64: 1476 case wasm::kExprI32UConvertF64: 1477 case wasm::kExprI64SConvertF64: 1478 case wasm::kExprI64UConvertF64: 1479 case wasm::kExprI32SConvertSatF64: 1480 case wasm::kExprI32UConvertSatF64: 1481 case wasm::kExprI64SConvertSatF64: 1482 case wasm::kExprI64UConvertSatF64: 1483 return MachineType::Float64(); 1484 default: 1485 UNREACHABLE(); 1486 } 1487 } 1488 1489 const Operator* ConvertOp(WasmGraphBuilder* builder, wasm::WasmOpcode opcode) { 1490 switch (opcode) { 1491 case wasm::kExprI32SConvertF32: 1492 case wasm::kExprI32SConvertSatF32: 1493 return builder->mcgraph()->machine()->TruncateFloat32ToInt32(); 1494 case wasm::kExprI32UConvertF32: 1495 case wasm::kExprI32UConvertSatF32: 1496 return builder->mcgraph()->machine()->TruncateFloat32ToUint32(); 1497 case wasm::kExprI32SConvertF64: 1498 case wasm::kExprI32SConvertSatF64: 1499 return builder->mcgraph()->machine()->ChangeFloat64ToInt32(); 1500 case wasm::kExprI32UConvertF64: 1501 case wasm::kExprI32UConvertSatF64: 1502 return builder->mcgraph()->machine()->TruncateFloat64ToUint32(); 1503 case wasm::kExprI64SConvertF32: 1504 case wasm::kExprI64SConvertSatF32: 1505 return builder->mcgraph()->machine()->TryTruncateFloat32ToInt64(); 1506 case wasm::kExprI64UConvertF32: 1507 case wasm::kExprI64UConvertSatF32: 1508 return builder->mcgraph()->machine()->TryTruncateFloat32ToUint64(); 1509 case wasm::kExprI64SConvertF64: 1510 case wasm::kExprI64SConvertSatF64: 1511 return builder->mcgraph()->machine()->TryTruncateFloat64ToInt64(); 1512 case wasm::kExprI64UConvertF64: 1513 case wasm::kExprI64UConvertSatF64: 1514 return builder->mcgraph()->machine()->TryTruncateFloat64ToUint64(); 1515 default: 1516 UNREACHABLE(); 1517 } 1518 } 1519 1520 wasm::WasmOpcode ConvertBackOp(wasm::WasmOpcode opcode) { 1521 switch (opcode) { 1522 case wasm::kExprI32SConvertF32: 1523 case wasm::kExprI32SConvertSatF32: 1524 return wasm::kExprF32SConvertI32; 1525 case wasm::kExprI32UConvertF32: 1526 case wasm::kExprI32UConvertSatF32: 1527 return wasm::kExprF32UConvertI32; 1528 case wasm::kExprI32SConvertF64: 1529 case wasm::kExprI32SConvertSatF64: 1530 return wasm::kExprF64SConvertI32; 1531 case wasm::kExprI32UConvertF64: 1532 case wasm::kExprI32UConvertSatF64: 1533 return wasm::kExprF64UConvertI32; 1534 default: 1535 UNREACHABLE(); 1536 } 1537 } 1538 1539 bool IsTrappingConvertOp(wasm::WasmOpcode opcode) { 1540 switch (opcode) { 1541 case wasm::kExprI32SConvertF32: 1542 case wasm::kExprI32UConvertF32: 1543 case wasm::kExprI32SConvertF64: 1544 case wasm::kExprI32UConvertF64: 1545 case wasm::kExprI64SConvertF32: 1546 case wasm::kExprI64UConvertF32: 1547 case wasm::kExprI64SConvertF64: 1548 case wasm::kExprI64UConvertF64: 1549 return true; 1550 case wasm::kExprI32SConvertSatF64: 1551 case wasm::kExprI32UConvertSatF64: 1552 case wasm::kExprI32SConvertSatF32: 1553 case wasm::kExprI32UConvertSatF32: 1554 case wasm::kExprI64SConvertSatF32: 1555 case wasm::kExprI64UConvertSatF32: 1556 case wasm::kExprI64SConvertSatF64: 1557 case wasm::kExprI64UConvertSatF64: 1558 return false; 1559 default: 1560 UNREACHABLE(); 1561 } 1562 } 1563 1564 Node* Zero(WasmGraphBuilder* builder, const MachineType& ty) { 1565 switch (ty.representation()) { 1566 case MachineRepresentation::kWord32: 1567 return builder->Int32Constant(0); 1568 case MachineRepresentation::kWord64: 1569 return builder->Int64Constant(0); 1570 case MachineRepresentation::kFloat32: 1571 return builder->Float32Constant(0.0); 1572 case MachineRepresentation::kFloat64: 1573 return builder->Float64Constant(0.0); 1574 default: 1575 UNREACHABLE(); 1576 } 1577 } 1578 1579 Node* Min(WasmGraphBuilder* builder, const MachineType& ty) { 1580 switch (ty.semantic()) { 1581 case MachineSemantic::kInt32: 1582 return builder->Int32Constant(std::numeric_limits<int32_t>::min()); 1583 case MachineSemantic::kUint32: 1584 return builder->Int32Constant(std::numeric_limits<uint32_t>::min()); 1585 case MachineSemantic::kInt64: 1586 return builder->Int64Constant(std::numeric_limits<int64_t>::min()); 1587 case MachineSemantic::kUint64: 1588 return builder->Int64Constant(std::numeric_limits<uint64_t>::min()); 1589 default: 1590 UNREACHABLE(); 1591 } 1592 } 1593 1594 Node* Max(WasmGraphBuilder* builder, const MachineType& ty) { 1595 switch (ty.semantic()) { 1596 case MachineSemantic::kInt32: 1597 return builder->Int32Constant(std::numeric_limits<int32_t>::max()); 1598 case MachineSemantic::kUint32: 1599 return builder->Int32Constant(std::numeric_limits<uint32_t>::max()); 1600 case MachineSemantic::kInt64: 1601 return builder->Int64Constant(std::numeric_limits<int64_t>::max()); 1602 case MachineSemantic::kUint64: 1603 return builder->Int64Constant(std::numeric_limits<uint64_t>::max()); 1604 default: 1605 UNREACHABLE(); 1606 } 1607 } 1608 1609 wasm::WasmOpcode TruncOp(const MachineType& ty) { 1610 switch (ty.representation()) { 1611 case MachineRepresentation::kFloat32: 1612 return wasm::kExprF32Trunc; 1613 case MachineRepresentation::kFloat64: 1614 return wasm::kExprF64Trunc; 1615 default: 1616 UNREACHABLE(); 1617 } 1618 } 1619 1620 wasm::WasmOpcode NeOp(const MachineType& ty) { 1621 switch (ty.representation()) { 1622 case MachineRepresentation::kFloat32: 1623 return wasm::kExprF32Ne; 1624 case MachineRepresentation::kFloat64: 1625 return wasm::kExprF64Ne; 1626 default: 1627 UNREACHABLE(); 1628 } 1629 } 1630 1631 wasm::WasmOpcode LtOp(const MachineType& ty) { 1632 switch (ty.representation()) { 1633 case MachineRepresentation::kFloat32: 1634 return wasm::kExprF32Lt; 1635 case MachineRepresentation::kFloat64: 1636 return wasm::kExprF64Lt; 1637 default: 1638 UNREACHABLE(); 1639 } 1640 } 1641 1642 Node* ConvertTrapTest(WasmGraphBuilder* builder, wasm::WasmOpcode opcode, 1643 const MachineType& int_ty, const MachineType& float_ty, 1644 Node* trunc, Node* converted_value) { 1645 if (int_ty.representation() == MachineRepresentation::kWord32) { 1646 Node* check = builder->Unop(ConvertBackOp(opcode), converted_value); 1647 return builder->Binop(NeOp(float_ty), trunc, check); 1648 } 1649 return builder->graph()->NewNode(builder->mcgraph()->common()->Projection(1), 1650 trunc, builder->graph()->start()); 1651 } 1652 1653 Node* ConvertSaturateTest(WasmGraphBuilder* builder, wasm::WasmOpcode opcode, 1654 const MachineType& int_ty, 1655 const MachineType& float_ty, Node* trunc, 1656 Node* converted_value) { 1657 Node* test = ConvertTrapTest(builder, opcode, int_ty, float_ty, trunc, 1658 converted_value); 1659 if (int_ty.representation() == MachineRepresentation::kWord64) { 1660 test = builder->Binop(wasm::kExprI64Eq, test, builder->Int64Constant(0)); 1661 } 1662 return test; 1663 } 1664 1665 } // namespace 1666 1667 Node* WasmGraphBuilder::BuildIntConvertFloat(Node* input, 1668 wasm::WasmCodePosition position, 1669 wasm::WasmOpcode opcode) { 1670 const MachineType int_ty = IntConvertType(opcode); 1671 const MachineType float_ty = FloatConvertType(opcode); 1672 const Operator* conv_op = ConvertOp(this, opcode); 1673 Node* trunc = nullptr; 1674 Node* converted_value = nullptr; 1675 const bool is_int32 = 1676 int_ty.representation() == MachineRepresentation::kWord32; 1677 if (is_int32) { 1678 trunc = Unop(TruncOp(float_ty), input); 1679 converted_value = graph()->NewNode(conv_op, trunc); 1680 } else { 1681 trunc = graph()->NewNode(conv_op, input); 1682 converted_value = graph()->NewNode(mcgraph()->common()->Projection(0), 1683 trunc, graph()->start()); 1684 } 1685 if (IsTrappingConvertOp(opcode)) { 1686 Node* test = 1687 ConvertTrapTest(this, opcode, int_ty, float_ty, trunc, converted_value); 1688 if (is_int32) { 1689 TrapIfTrue(wasm::kTrapFloatUnrepresentable, test, position); 1690 } else { 1691 ZeroCheck64(wasm::kTrapFloatUnrepresentable, test, position); 1692 } 1693 return converted_value; 1694 } 1695 Node* test = ConvertSaturateTest(this, opcode, int_ty, float_ty, trunc, 1696 converted_value); 1697 Diamond tl_d(graph(), mcgraph()->common(), test, BranchHint::kFalse); 1698 tl_d.Chain(Control()); 1699 Node* nan_test = Binop(NeOp(float_ty), input, input); 1700 Diamond nan_d(graph(), mcgraph()->common(), nan_test, BranchHint::kFalse); 1701 nan_d.Nest(tl_d, true); 1702 Node* neg_test = Binop(LtOp(float_ty), input, Zero(this, float_ty)); 1703 Diamond sat_d(graph(), mcgraph()->common(), neg_test, BranchHint::kNone); 1704 sat_d.Nest(nan_d, false); 1705 Node* sat_val = 1706 sat_d.Phi(int_ty.representation(), Min(this, int_ty), Max(this, int_ty)); 1707 Node* nan_val = 1708 nan_d.Phi(int_ty.representation(), Zero(this, int_ty), sat_val); 1709 return tl_d.Phi(int_ty.representation(), nan_val, converted_value); 1710 } 1711 1712 Node* WasmGraphBuilder::BuildI32AsmjsSConvertF32(Node* input) { 1713 MachineOperatorBuilder* m = mcgraph()->machine(); 1714 // asm.js must use the wacky JS semantics. 1715 input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input); 1716 return graph()->NewNode(m->TruncateFloat64ToWord32(), input); 1717 } 1718 1719 Node* WasmGraphBuilder::BuildI32AsmjsSConvertF64(Node* input) { 1720 MachineOperatorBuilder* m = mcgraph()->machine(); 1721 // asm.js must use the wacky JS semantics. 1722 return graph()->NewNode(m->TruncateFloat64ToWord32(), input); 1723 } 1724 1725 Node* WasmGraphBuilder::BuildI32AsmjsUConvertF32(Node* input) { 1726 MachineOperatorBuilder* m = mcgraph()->machine(); 1727 // asm.js must use the wacky JS semantics. 1728 input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input); 1729 return graph()->NewNode(m->TruncateFloat64ToWord32(), input); 1730 } 1731 1732 Node* WasmGraphBuilder::BuildI32AsmjsUConvertF64(Node* input) { 1733 MachineOperatorBuilder* m = mcgraph()->machine(); 1734 // asm.js must use the wacky JS semantics. 1735 return graph()->NewNode(m->TruncateFloat64ToWord32(), input); 1736 } 1737 1738 Node* WasmGraphBuilder::BuildBitCountingCall(Node* input, ExternalReference ref, 1739 MachineRepresentation input_type) { 1740 Node* stack_slot_param = 1741 graph()->NewNode(mcgraph()->machine()->StackSlot(input_type)); 1742 1743 const Operator* store_op = mcgraph()->machine()->Store( 1744 StoreRepresentation(input_type, kNoWriteBarrier)); 1745 SetEffect(graph()->NewNode(store_op, stack_slot_param, 1746 mcgraph()->Int32Constant(0), input, Effect(), 1747 Control())); 1748 1749 MachineType sig_types[] = {MachineType::Int32(), MachineType::Pointer()}; 1750 MachineSignature sig(1, 1, sig_types); 1751 1752 Node* function = graph()->NewNode(mcgraph()->common()->ExternalConstant(ref)); 1753 1754 return BuildCCall(&sig, function, stack_slot_param); 1755 } 1756 1757 Node* WasmGraphBuilder::BuildI32Ctz(Node* input) { 1758 return BuildBitCountingCall(input, ExternalReference::wasm_word32_ctz(), 1759 MachineRepresentation::kWord32); 1760 } 1761 1762 Node* WasmGraphBuilder::BuildI64Ctz(Node* input) { 1763 return Unop(wasm::kExprI64UConvertI32, 1764 BuildBitCountingCall(input, ExternalReference::wasm_word64_ctz(), 1765 MachineRepresentation::kWord64)); 1766 } 1767 1768 Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) { 1769 return BuildBitCountingCall(input, ExternalReference::wasm_word32_popcnt(), 1770 MachineRepresentation::kWord32); 1771 } 1772 1773 Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) { 1774 return Unop( 1775 wasm::kExprI64UConvertI32, 1776 BuildBitCountingCall(input, ExternalReference::wasm_word64_popcnt(), 1777 MachineRepresentation::kWord64)); 1778 } 1779 1780 Node* WasmGraphBuilder::BuildF32Trunc(Node* input) { 1781 MachineType type = MachineType::Float32(); 1782 ExternalReference ref = ExternalReference::wasm_f32_trunc(); 1783 1784 return BuildCFuncInstruction(ref, type, input); 1785 } 1786 1787 Node* WasmGraphBuilder::BuildF32Floor(Node* input) { 1788 MachineType type = MachineType::Float32(); 1789 ExternalReference ref = ExternalReference::wasm_f32_floor(); 1790 return BuildCFuncInstruction(ref, type, input); 1791 } 1792 1793 Node* WasmGraphBuilder::BuildF32Ceil(Node* input) { 1794 MachineType type = MachineType::Float32(); 1795 ExternalReference ref = ExternalReference::wasm_f32_ceil(); 1796 return BuildCFuncInstruction(ref, type, input); 1797 } 1798 1799 Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) { 1800 MachineType type = MachineType::Float32(); 1801 ExternalReference ref = ExternalReference::wasm_f32_nearest_int(); 1802 return BuildCFuncInstruction(ref, type, input); 1803 } 1804 1805 Node* WasmGraphBuilder::BuildF64Trunc(Node* input) { 1806 MachineType type = MachineType::Float64(); 1807 ExternalReference ref = ExternalReference::wasm_f64_trunc(); 1808 return BuildCFuncInstruction(ref, type, input); 1809 } 1810 1811 Node* WasmGraphBuilder::BuildF64Floor(Node* input) { 1812 MachineType type = MachineType::Float64(); 1813 ExternalReference ref = ExternalReference::wasm_f64_floor(); 1814 return BuildCFuncInstruction(ref, type, input); 1815 } 1816 1817 Node* WasmGraphBuilder::BuildF64Ceil(Node* input) { 1818 MachineType type = MachineType::Float64(); 1819 ExternalReference ref = ExternalReference::wasm_f64_ceil(); 1820 return BuildCFuncInstruction(ref, type, input); 1821 } 1822 1823 Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) { 1824 MachineType type = MachineType::Float64(); 1825 ExternalReference ref = ExternalReference::wasm_f64_nearest_int(); 1826 return BuildCFuncInstruction(ref, type, input); 1827 } 1828 1829 Node* WasmGraphBuilder::BuildF64Acos(Node* input) { 1830 MachineType type = MachineType::Float64(); 1831 ExternalReference ref = ExternalReference::f64_acos_wrapper_function(); 1832 return BuildCFuncInstruction(ref, type, input); 1833 } 1834 1835 Node* WasmGraphBuilder::BuildF64Asin(Node* input) { 1836 MachineType type = MachineType::Float64(); 1837 ExternalReference ref = ExternalReference::f64_asin_wrapper_function(); 1838 return BuildCFuncInstruction(ref, type, input); 1839 } 1840 1841 Node* WasmGraphBuilder::BuildF64Pow(Node* left, Node* right) { 1842 MachineType type = MachineType::Float64(); 1843 ExternalReference ref = ExternalReference::wasm_float64_pow(); 1844 return BuildCFuncInstruction(ref, type, left, right); 1845 } 1846 1847 Node* WasmGraphBuilder::BuildF64Mod(Node* left, Node* right) { 1848 MachineType type = MachineType::Float64(); 1849 ExternalReference ref = ExternalReference::f64_mod_wrapper_function(); 1850 return BuildCFuncInstruction(ref, type, left, right); 1851 } 1852 1853 Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref, 1854 MachineType type, Node* input0, 1855 Node* input1) { 1856 // We do truncation by calling a C function which calculates the result. 1857 // The input is passed to the C function as a byte buffer holding the two 1858 // input doubles. We reserve this byte buffer as a stack slot, store the 1859 // parameters in this buffer slots, pass a pointer to the buffer to the C 1860 // function, and after calling the C function we collect the return value from 1861 // the buffer. 1862 1863 const int type_size = ElementSizeInBytes(type.representation()); 1864 const int stack_slot_bytes = (input1 == nullptr ? 1 : 2) * type_size; 1865 Node* stack_slot = 1866 graph()->NewNode(mcgraph()->machine()->StackSlot(stack_slot_bytes)); 1867 1868 const Operator* store_op = mcgraph()->machine()->Store( 1869 StoreRepresentation(type.representation(), kNoWriteBarrier)); 1870 SetEffect(graph()->NewNode(store_op, stack_slot, mcgraph()->Int32Constant(0), 1871 input0, Effect(), Control())); 1872 1873 Node* function = graph()->NewNode(mcgraph()->common()->ExternalConstant(ref)); 1874 1875 if (input1 != nullptr) { 1876 SetEffect(graph()->NewNode(store_op, stack_slot, 1877 mcgraph()->Int32Constant(type_size), input1, 1878 Effect(), Control())); 1879 } 1880 1881 MachineType sig_types[] = {MachineType::Pointer()}; 1882 MachineSignature sig(0, 1, sig_types); 1883 BuildCCall(&sig, function, stack_slot); 1884 1885 return SetEffect(graph()->NewNode(mcgraph()->machine()->Load(type), 1886 stack_slot, mcgraph()->Int32Constant(0), 1887 Effect(), Control())); 1888 } 1889 1890 Node* WasmGraphBuilder::BuildF32SConvertI64(Node* input) { 1891 // TODO(titzer/bradnelson): Check handlng of asm.js case. 1892 return BuildIntToFloatConversionInstruction( 1893 input, ExternalReference::wasm_int64_to_float32(), 1894 MachineRepresentation::kWord64, MachineType::Float32()); 1895 } 1896 Node* WasmGraphBuilder::BuildF32UConvertI64(Node* input) { 1897 // TODO(titzer/bradnelson): Check handlng of asm.js case. 1898 return BuildIntToFloatConversionInstruction( 1899 input, ExternalReference::wasm_uint64_to_float32(), 1900 MachineRepresentation::kWord64, MachineType::Float32()); 1901 } 1902 Node* WasmGraphBuilder::BuildF64SConvertI64(Node* input) { 1903 return BuildIntToFloatConversionInstruction( 1904 input, ExternalReference::wasm_int64_to_float64(), 1905 MachineRepresentation::kWord64, MachineType::Float64()); 1906 } 1907 Node* WasmGraphBuilder::BuildF64UConvertI64(Node* input) { 1908 return BuildIntToFloatConversionInstruction( 1909 input, ExternalReference::wasm_uint64_to_float64(), 1910 MachineRepresentation::kWord64, MachineType::Float64()); 1911 } 1912 1913 Node* WasmGraphBuilder::BuildIntToFloatConversionInstruction( 1914 Node* input, ExternalReference ref, 1915 MachineRepresentation parameter_representation, 1916 const MachineType result_type) { 1917 int stack_slot_size = 1918 std::max(ElementSizeInBytes(parameter_representation), 1919 ElementSizeInBytes(result_type.representation())); 1920 Node* stack_slot = 1921 graph()->NewNode(mcgraph()->machine()->StackSlot(stack_slot_size)); 1922 const Operator* store_op = mcgraph()->machine()->Store( 1923 StoreRepresentation(parameter_representation, kNoWriteBarrier)); 1924 SetEffect(graph()->NewNode(store_op, stack_slot, mcgraph()->Int32Constant(0), 1925 input, Effect(), Control())); 1926 MachineType sig_types[] = {MachineType::Pointer()}; 1927 MachineSignature sig(0, 1, sig_types); 1928 Node* function = graph()->NewNode(mcgraph()->common()->ExternalConstant(ref)); 1929 BuildCCall(&sig, function, stack_slot); 1930 return SetEffect(graph()->NewNode(mcgraph()->machine()->Load(result_type), 1931 stack_slot, mcgraph()->Int32Constant(0), 1932 Effect(), Control())); 1933 } 1934 1935 namespace { 1936 1937 ExternalReference convert_ccall_ref(WasmGraphBuilder* builder, 1938 wasm::WasmOpcode opcode) { 1939 switch (opcode) { 1940 case wasm::kExprI64SConvertF32: 1941 case wasm::kExprI64SConvertSatF32: 1942 return ExternalReference::wasm_float32_to_int64(); 1943 case wasm::kExprI64UConvertF32: 1944 case wasm::kExprI64UConvertSatF32: 1945 return ExternalReference::wasm_float32_to_uint64(); 1946 case wasm::kExprI64SConvertF64: 1947 case wasm::kExprI64SConvertSatF64: 1948 return ExternalReference::wasm_float64_to_int64(); 1949 case wasm::kExprI64UConvertF64: 1950 case wasm::kExprI64UConvertSatF64: 1951 return ExternalReference::wasm_float64_to_uint64(); 1952 default: 1953 UNREACHABLE(); 1954 } 1955 } 1956 1957 } // namespace 1958 1959 Node* WasmGraphBuilder::BuildCcallConvertFloat(Node* input, 1960 wasm::WasmCodePosition position, 1961 wasm::WasmOpcode opcode) { 1962 const MachineType int_ty = IntConvertType(opcode); 1963 const MachineType float_ty = FloatConvertType(opcode); 1964 ExternalReference call_ref = convert_ccall_ref(this, opcode); 1965 int stack_slot_size = std::max(ElementSizeInBytes(int_ty.representation()), 1966 ElementSizeInBytes(float_ty.representation())); 1967 Node* stack_slot = 1968 graph()->NewNode(mcgraph()->machine()->StackSlot(stack_slot_size)); 1969 const Operator* store_op = mcgraph()->machine()->Store( 1970 StoreRepresentation(float_ty.representation(), kNoWriteBarrier)); 1971 SetEffect(graph()->NewNode(store_op, stack_slot, Int32Constant(0), input, 1972 Effect(), Control())); 1973 MachineType sig_types[] = {MachineType::Int32(), MachineType::Pointer()}; 1974 MachineSignature sig(1, 1, sig_types); 1975 Node* function = 1976 graph()->NewNode(mcgraph()->common()->ExternalConstant(call_ref)); 1977 Node* overflow = BuildCCall(&sig, function, stack_slot); 1978 if (IsTrappingConvertOp(opcode)) { 1979 ZeroCheck32(wasm::kTrapFloatUnrepresentable, overflow, position); 1980 return SetEffect(graph()->NewNode(mcgraph()->machine()->Load(int_ty), 1981 stack_slot, Int32Constant(0), Effect(), 1982 Control())); 1983 } 1984 Node* test = Binop(wasm::kExprI32Eq, overflow, Int32Constant(0), position); 1985 Diamond tl_d(graph(), mcgraph()->common(), test, BranchHint::kFalse); 1986 tl_d.Chain(Control()); 1987 Node* nan_test = Binop(NeOp(float_ty), input, input); 1988 Diamond nan_d(graph(), mcgraph()->common(), nan_test, BranchHint::kFalse); 1989 nan_d.Nest(tl_d, true); 1990 Node* neg_test = Binop(LtOp(float_ty), input, Zero(this, float_ty)); 1991 Diamond sat_d(graph(), mcgraph()->common(), neg_test, BranchHint::kNone); 1992 sat_d.Nest(nan_d, false); 1993 Node* sat_val = 1994 sat_d.Phi(int_ty.representation(), Min(this, int_ty), Max(this, int_ty)); 1995 Node* load = 1996 SetEffect(graph()->NewNode(mcgraph()->machine()->Load(int_ty), stack_slot, 1997 Int32Constant(0), Effect(), Control())); 1998 Node* nan_val = 1999 nan_d.Phi(int_ty.representation(), Zero(this, int_ty), sat_val); 2000 return tl_d.Phi(int_ty.representation(), nan_val, load); 2001 } 2002 2003 Node* WasmGraphBuilder::GrowMemory(Node* input) { 2004 SetNeedsStackCheck(); 2005 2006 WasmGrowMemoryDescriptor interface_descriptor; 2007 auto call_descriptor = Linkage::GetStubCallDescriptor( 2008 mcgraph()->zone(), // zone 2009 interface_descriptor, // descriptor 2010 interface_descriptor.GetStackParameterCount(), // stack parameter count 2011 CallDescriptor::kNoFlags, // flags 2012 Operator::kNoProperties, // properties 2013 StubCallMode::kCallWasmRuntimeStub); // stub call mode 2014 // A direct call to a wasm runtime stub defined in this module. 2015 // Just encode the stub index. This will be patched at relocation. 2016 Node* call_target = mcgraph()->RelocatableIntPtrConstant( 2017 wasm::WasmCode::kWasmGrowMemory, RelocInfo::WASM_STUB_CALL); 2018 return SetEffect( 2019 SetControl(graph()->NewNode(mcgraph()->common()->Call(call_descriptor), 2020 call_target, input, Effect(), Control()))); 2021 } 2022 2023 uint32_t WasmGraphBuilder::GetExceptionEncodedSize( 2024 const wasm::WasmException* exception) const { 2025 const wasm::WasmExceptionSig* sig = exception->sig; 2026 uint32_t encoded_size = 0; 2027 for (size_t i = 0; i < sig->parameter_count(); ++i) { 2028 size_t byte_size = static_cast<size_t>( 2029 wasm::ValueTypes::ElementSizeInBytes(sig->GetParam(i))); 2030 DCHECK_EQ(byte_size % kBytesPerExceptionValuesArrayElement, 0); 2031 DCHECK_LE(1, byte_size / kBytesPerExceptionValuesArrayElement); 2032 encoded_size += byte_size / kBytesPerExceptionValuesArrayElement; 2033 } 2034 return encoded_size; 2035 } 2036 2037 Node* WasmGraphBuilder::Throw(uint32_t tag, 2038 const wasm::WasmException* exception, 2039 const Vector<Node*> values) { 2040 SetNeedsStackCheck(); 2041 uint32_t encoded_size = GetExceptionEncodedSize(exception); 2042 Node* create_parameters[] = { 2043 BuildChangeUint31ToSmi(ConvertExceptionTagToRuntimeId(tag)), 2044 BuildChangeUint31ToSmi(Uint32Constant(encoded_size))}; 2045 BuildCallToRuntime(Runtime::kWasmThrowCreate, create_parameters, 2046 arraysize(create_parameters)); 2047 uint32_t index = 0; 2048 const wasm::WasmExceptionSig* sig = exception->sig; 2049 MachineOperatorBuilder* m = mcgraph()->machine(); 2050 for (size_t i = 0; i < sig->parameter_count(); ++i) { 2051 Node* value = values[i]; 2052 switch (sig->GetParam(i)) { 2053 case wasm::kWasmF32: 2054 value = graph()->NewNode(m->BitcastFloat32ToInt32(), value); 2055 V8_FALLTHROUGH; 2056 case wasm::kWasmI32: 2057 BuildEncodeException32BitValue(&index, value); 2058 break; 2059 case wasm::kWasmF64: 2060 value = graph()->NewNode(m->BitcastFloat64ToInt64(), value); 2061 V8_FALLTHROUGH; 2062 case wasm::kWasmI64: { 2063 Node* upper32 = graph()->NewNode( 2064 m->TruncateInt64ToInt32(), 2065 Binop(wasm::kExprI64ShrU, value, Int64Constant(32))); 2066 BuildEncodeException32BitValue(&index, upper32); 2067 Node* lower32 = graph()->NewNode(m->TruncateInt64ToInt32(), value); 2068 BuildEncodeException32BitValue(&index, lower32); 2069 break; 2070 } 2071 default: 2072 UNREACHABLE(); 2073 } 2074 } 2075 DCHECK_EQ(encoded_size, index); 2076 return BuildCallToRuntime(Runtime::kWasmThrow, nullptr, 0); 2077 } 2078 2079 void WasmGraphBuilder::BuildEncodeException32BitValue(uint32_t* index, 2080 Node* value) { 2081 MachineOperatorBuilder* machine = mcgraph()->machine(); 2082 Node* upper_parameters[] = { 2083 BuildChangeUint31ToSmi(Int32Constant(*index)), 2084 BuildChangeUint31ToSmi( 2085 graph()->NewNode(machine->Word32Shr(), value, Int32Constant(16))), 2086 }; 2087 BuildCallToRuntime(Runtime::kWasmExceptionSetElement, upper_parameters, 2088 arraysize(upper_parameters)); 2089 ++(*index); 2090 Node* lower_parameters[] = { 2091 BuildChangeUint31ToSmi(Int32Constant(*index)), 2092 BuildChangeUint31ToSmi(graph()->NewNode(machine->Word32And(), value, 2093 Int32Constant(0xFFFFu))), 2094 }; 2095 BuildCallToRuntime(Runtime::kWasmExceptionSetElement, lower_parameters, 2096 arraysize(lower_parameters)); 2097 ++(*index); 2098 } 2099 2100 Node* WasmGraphBuilder::BuildDecodeException32BitValue(Node* const* values, 2101 uint32_t* index) { 2102 MachineOperatorBuilder* machine = mcgraph()->machine(); 2103 Node* upper = BuildChangeSmiToInt32(values[*index]); 2104 (*index)++; 2105 upper = graph()->NewNode(machine->Word32Shl(), upper, Int32Constant(16)); 2106 Node* lower = BuildChangeSmiToInt32(values[*index]); 2107 (*index)++; 2108 Node* value = graph()->NewNode(machine->Word32Or(), upper, lower); 2109 return value; 2110 } 2111 2112 Node* WasmGraphBuilder::Rethrow() { 2113 SetNeedsStackCheck(); 2114 Node* result = BuildCallToRuntime(Runtime::kWasmThrow, nullptr, 0); 2115 return result; 2116 } 2117 2118 Node* WasmGraphBuilder::ConvertExceptionTagToRuntimeId(uint32_t tag) { 2119 // TODO(kschimpf): Handle exceptions from different modules, when they are 2120 // linked at runtime. 2121 return Uint32Constant(tag); 2122 } 2123 2124 Node* WasmGraphBuilder::GetExceptionRuntimeId() { 2125 SetNeedsStackCheck(); 2126 return BuildChangeSmiToInt32( 2127 BuildCallToRuntime(Runtime::kWasmGetExceptionRuntimeId, nullptr, 0)); 2128 } 2129 2130 Node** WasmGraphBuilder::GetExceptionValues( 2131 const wasm::WasmException* except_decl) { 2132 // TODO(kschimpf): We need to move this code to the function-body-decoder.cc 2133 // in order to build landing-pad (exception) edges in case the runtime 2134 // call causes an exception. 2135 2136 // Start by getting the encoded values from the exception. 2137 uint32_t encoded_size = GetExceptionEncodedSize(except_decl); 2138 Node** values = Buffer(encoded_size); 2139 for (uint32_t i = 0; i < encoded_size; ++i) { 2140 Node* parameters[] = {BuildChangeUint31ToSmi(Uint32Constant(i))}; 2141 values[i] = BuildCallToRuntime(Runtime::kWasmExceptionGetElement, 2142 parameters, arraysize(parameters)); 2143 } 2144 2145 // Now convert the leading entries to the corresponding parameter values. 2146 uint32_t index = 0; 2147 const wasm::WasmExceptionSig* sig = except_decl->sig; 2148 for (size_t i = 0; i < sig->parameter_count(); ++i) { 2149 Node* value = BuildDecodeException32BitValue(values, &index); 2150 switch (wasm::ValueType type = sig->GetParam(i)) { 2151 case wasm::kWasmF32: { 2152 value = Unop(wasm::kExprF32ReinterpretI32, value); 2153 break; 2154 } 2155 case wasm::kWasmI32: 2156 break; 2157 case wasm::kWasmF64: 2158 case wasm::kWasmI64: { 2159 Node* upper = 2160 Binop(wasm::kExprI64Shl, Unop(wasm::kExprI64UConvertI32, value), 2161 Int64Constant(32)); 2162 Node* lower = Unop(wasm::kExprI64UConvertI32, 2163 BuildDecodeException32BitValue(values, &index)); 2164 value = Binop(wasm::kExprI64Ior, upper, lower); 2165 if (type == wasm::kWasmF64) { 2166 value = Unop(wasm::kExprF64ReinterpretI64, value); 2167 } 2168 break; 2169 } 2170 default: 2171 UNREACHABLE(); 2172 } 2173 values[i] = value; 2174 } 2175 DCHECK_EQ(index, encoded_size); 2176 return values; 2177 } 2178 2179 Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right, 2180 wasm::WasmCodePosition position) { 2181 MachineOperatorBuilder* m = mcgraph()->machine(); 2182 ZeroCheck32(wasm::kTrapDivByZero, right, position); 2183 Node* before = Control(); 2184 Node* denom_is_m1; 2185 Node* denom_is_not_m1; 2186 BranchExpectFalse( 2187 graph()->NewNode(m->Word32Equal(), right, mcgraph()->Int32Constant(-1)), 2188 &denom_is_m1, &denom_is_not_m1); 2189 SetControl(denom_is_m1); 2190 TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt, position); 2191 if (Control() != denom_is_m1) { 2192 SetControl(graph()->NewNode(mcgraph()->common()->Merge(2), denom_is_not_m1, 2193 Control())); 2194 } else { 2195 SetControl(before); 2196 } 2197 return graph()->NewNode(m->Int32Div(), left, right, Control()); 2198 } 2199 2200 Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right, 2201 wasm::WasmCodePosition position) { 2202 MachineOperatorBuilder* m = mcgraph()->machine(); 2203 2204 ZeroCheck32(wasm::kTrapRemByZero, right, position); 2205 2206 Diamond d( 2207 graph(), mcgraph()->common(), 2208 graph()->NewNode(m->Word32Equal(), right, mcgraph()->Int32Constant(-1)), 2209 BranchHint::kFalse); 2210 d.Chain(Control()); 2211 2212 return d.Phi(MachineRepresentation::kWord32, mcgraph()->Int32Constant(0), 2213 graph()->NewNode(m->Int32Mod(), left, right, d.if_false)); 2214 } 2215 2216 Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right, 2217 wasm::WasmCodePosition position) { 2218 MachineOperatorBuilder* m = mcgraph()->machine(); 2219 return graph()->NewNode(m->Uint32Div(), left, right, 2220 ZeroCheck32(wasm::kTrapDivByZero, right, position)); 2221 } 2222 2223 Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right, 2224 wasm::WasmCodePosition position) { 2225 MachineOperatorBuilder* m = mcgraph()->machine(); 2226 return graph()->NewNode(m->Uint32Mod(), left, right, 2227 ZeroCheck32(wasm::kTrapRemByZero, right, position)); 2228 } 2229 2230 Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) { 2231 MachineOperatorBuilder* m = mcgraph()->machine(); 2232 2233 Int32Matcher mr(right); 2234 if (mr.HasValue()) { 2235 if (mr.Value() == 0) { 2236 return mcgraph()->Int32Constant(0); 2237 } else if (mr.Value() == -1) { 2238 // The result is the negation of the left input. 2239 return graph()->NewNode(m->Int32Sub(), mcgraph()->Int32Constant(0), left); 2240 } 2241 return graph()->NewNode(m->Int32Div(), left, right, Control()); 2242 } 2243 2244 // asm.js semantics return 0 on divide or mod by zero. 2245 if (m->Int32DivIsSafe()) { 2246 // The hardware instruction does the right thing (e.g. arm). 2247 return graph()->NewNode(m->Int32Div(), left, right, graph()->start()); 2248 } 2249 2250 // Check denominator for zero. 2251 Diamond z( 2252 graph(), mcgraph()->common(), 2253 graph()->NewNode(m->Word32Equal(), right, mcgraph()->Int32Constant(0)), 2254 BranchHint::kFalse); 2255 2256 // Check numerator for -1. (avoid minint / -1 case). 2257 Diamond n( 2258 graph(), mcgraph()->common(), 2259 graph()->NewNode(m->Word32Equal(), right, mcgraph()->Int32Constant(-1)), 2260 BranchHint::kFalse); 2261 2262 Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false); 2263 Node* neg = 2264 graph()->NewNode(m->Int32Sub(), mcgraph()->Int32Constant(0), left); 2265 2266 return n.Phi( 2267 MachineRepresentation::kWord32, neg, 2268 z.Phi(MachineRepresentation::kWord32, mcgraph()->Int32Constant(0), div)); 2269 } 2270 2271 Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) { 2272 CommonOperatorBuilder* c = mcgraph()->common(); 2273 MachineOperatorBuilder* m = mcgraph()->machine(); 2274 Node* const zero = mcgraph()->Int32Constant(0); 2275 2276 Int32Matcher mr(right); 2277 if (mr.HasValue()) { 2278 if (mr.Value() == 0 || mr.Value() == -1) { 2279 return zero; 2280 } 2281 return graph()->NewNode(m->Int32Mod(), left, right, Control()); 2282 } 2283 2284 // General case for signed integer modulus, with optimization for (unknown) 2285 // power of 2 right hand side. 2286 // 2287 // if 0 < right then 2288 // msk = right - 1 2289 // if right & msk != 0 then 2290 // left % right 2291 // else 2292 // if left < 0 then 2293 // -(-left & msk) 2294 // else 2295 // left & msk 2296 // else 2297 // if right < -1 then 2298 // left % right 2299 // else 2300 // zero 2301 // 2302 // Note: We do not use the Diamond helper class here, because it really hurts 2303 // readability with nested diamonds. 2304 Node* const minus_one = mcgraph()->Int32Constant(-1); 2305 2306 const Operator* const merge_op = c->Merge(2); 2307 const Operator* const phi_op = c->Phi(MachineRepresentation::kWord32, 2); 2308 2309 Node* check0 = graph()->NewNode(m->Int32LessThan(), zero, right); 2310 Node* branch0 = 2311 graph()->NewNode(c->Branch(BranchHint::kTrue), check0, graph()->start()); 2312 2313 Node* if_true0 = graph()->NewNode(c->IfTrue(), branch0); 2314 Node* true0; 2315 { 2316 Node* msk = graph()->NewNode(m->Int32Add(), right, minus_one); 2317 2318 Node* check1 = graph()->NewNode(m->Word32And(), right, msk); 2319 Node* branch1 = graph()->NewNode(c->Branch(), check1, if_true0); 2320 2321 Node* if_true1 = graph()->NewNode(c->IfTrue(), branch1); 2322 Node* true1 = graph()->NewNode(m->Int32Mod(), left, right, if_true1); 2323 2324 Node* if_false1 = graph()->NewNode(c->IfFalse(), branch1); 2325 Node* false1; 2326 { 2327 Node* check2 = graph()->NewNode(m->Int32LessThan(), left, zero); 2328 Node* branch2 = 2329 graph()->NewNode(c->Branch(BranchHint::kFalse), check2, if_false1); 2330 2331 Node* if_true2 = graph()->NewNode(c->IfTrue(), branch2); 2332 Node* true2 = graph()->NewNode( 2333 m->Int32Sub(), zero, 2334 graph()->NewNode(m->Word32And(), 2335 graph()->NewNode(m->Int32Sub(), zero, left), msk)); 2336 2337 Node* if_false2 = graph()->NewNode(c->IfFalse(), branch2); 2338 Node* false2 = graph()->NewNode(m->Word32And(), left, msk); 2339 2340 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2); 2341 false1 = graph()->NewNode(phi_op, true2, false2, if_false1); 2342 } 2343 2344 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1); 2345 true0 = graph()->NewNode(phi_op, true1, false1, if_true0); 2346 } 2347 2348 Node* if_false0 = graph()->NewNode(c->IfFalse(), branch0); 2349 Node* false0; 2350 { 2351 Node* check1 = graph()->NewNode(m->Int32LessThan(), right, minus_one); 2352 Node* branch1 = 2353 graph()->NewNode(c->Branch(BranchHint::kTrue), check1, if_false0); 2354 2355 Node* if_true1 = graph()->NewNode(c->IfTrue(), branch1); 2356 Node* true1 = graph()->NewNode(m->Int32Mod(), left, right, if_true1); 2357 2358 Node* if_false1 = graph()->NewNode(c->IfFalse(), branch1); 2359 Node* false1 = zero; 2360 2361 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1); 2362 false0 = graph()->NewNode(phi_op, true1, false1, if_false0); 2363 } 2364 2365 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0); 2366 return graph()->NewNode(phi_op, true0, false0, merge0); 2367 } 2368 2369 Node* WasmGraphBuilder::BuildI32AsmjsDivU(Node* left, Node* right) { 2370 MachineOperatorBuilder* m = mcgraph()->machine(); 2371 // asm.js semantics return 0 on divide or mod by zero. 2372 if (m->Uint32DivIsSafe()) { 2373 // The hardware instruction does the right thing (e.g. arm). 2374 return graph()->NewNode(m->Uint32Div(), left, right, graph()->start()); 2375 } 2376 2377 // Explicit check for x % 0. 2378 Diamond z( 2379 graph(), mcgraph()->common(), 2380 graph()->NewNode(m->Word32Equal(), right, mcgraph()->Int32Constant(0)), 2381 BranchHint::kFalse); 2382 2383 return z.Phi(MachineRepresentation::kWord32, mcgraph()->Int32Constant(0), 2384 graph()->NewNode(mcgraph()->machine()->Uint32Div(), left, right, 2385 z.if_false)); 2386 } 2387 2388 Node* WasmGraphBuilder::BuildI32AsmjsRemU(Node* left, Node* right) { 2389 MachineOperatorBuilder* m = mcgraph()->machine(); 2390 // asm.js semantics return 0 on divide or mod by zero. 2391 // Explicit check for x % 0. 2392 Diamond z( 2393 graph(), mcgraph()->common(), 2394 graph()->NewNode(m->Word32Equal(), right, mcgraph()->Int32Constant(0)), 2395 BranchHint::kFalse); 2396 2397 Node* rem = graph()->NewNode(mcgraph()->machine()->Uint32Mod(), left, right, 2398 z.if_false); 2399 return z.Phi(MachineRepresentation::kWord32, mcgraph()->Int32Constant(0), 2400 rem); 2401 } 2402 2403 Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right, 2404 wasm::WasmCodePosition position) { 2405 if (mcgraph()->machine()->Is32()) { 2406 return BuildDiv64Call(left, right, ExternalReference::wasm_int64_div(), 2407 MachineType::Int64(), wasm::kTrapDivByZero, position); 2408 } 2409 ZeroCheck64(wasm::kTrapDivByZero, right, position); 2410 Node* before = Control(); 2411 Node* denom_is_m1; 2412 Node* denom_is_not_m1; 2413 BranchExpectFalse(graph()->NewNode(mcgraph()->machine()->Word64Equal(), right, 2414 mcgraph()->Int64Constant(-1)), 2415 &denom_is_m1, &denom_is_not_m1); 2416 SetControl(denom_is_m1); 2417 TrapIfEq64(wasm::kTrapDivUnrepresentable, left, 2418 std::numeric_limits<int64_t>::min(), position); 2419 if (Control() != denom_is_m1) { 2420 SetControl(graph()->NewNode(mcgraph()->common()->Merge(2), denom_is_not_m1, 2421 Control())); 2422 } else { 2423 SetControl(before); 2424 } 2425 return graph()->NewNode(mcgraph()->machine()->Int64Div(), left, right, 2426 Control()); 2427 } 2428 2429 Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right, 2430 wasm::WasmCodePosition position) { 2431 if (mcgraph()->machine()->Is32()) { 2432 return BuildDiv64Call(left, right, ExternalReference::wasm_int64_mod(), 2433 MachineType::Int64(), wasm::kTrapRemByZero, position); 2434 } 2435 ZeroCheck64(wasm::kTrapRemByZero, right, position); 2436 Diamond d(mcgraph()->graph(), mcgraph()->common(), 2437 graph()->NewNode(mcgraph()->machine()->Word64Equal(), right, 2438 mcgraph()->Int64Constant(-1))); 2439 2440 d.Chain(Control()); 2441 2442 Node* rem = graph()->NewNode(mcgraph()->machine()->Int64Mod(), left, right, 2443 d.if_false); 2444 2445 return d.Phi(MachineRepresentation::kWord64, mcgraph()->Int64Constant(0), 2446 rem); 2447 } 2448 2449 Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right, 2450 wasm::WasmCodePosition position) { 2451 if (mcgraph()->machine()->Is32()) { 2452 return BuildDiv64Call(left, right, ExternalReference::wasm_uint64_div(), 2453 MachineType::Int64(), wasm::kTrapDivByZero, position); 2454 } 2455 return graph()->NewNode(mcgraph()->machine()->Uint64Div(), left, right, 2456 ZeroCheck64(wasm::kTrapDivByZero, right, position)); 2457 } 2458 Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right, 2459 wasm::WasmCodePosition position) { 2460 if (mcgraph()->machine()->Is32()) { 2461 return BuildDiv64Call(left, right, ExternalReference::wasm_uint64_mod(), 2462 MachineType::Int64(), wasm::kTrapRemByZero, position); 2463 } 2464 return graph()->NewNode(mcgraph()->machine()->Uint64Mod(), left, right, 2465 ZeroCheck64(wasm::kTrapRemByZero, right, position)); 2466 } 2467 2468 Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right, 2469 ExternalReference ref, 2470 MachineType result_type, 2471 wasm::TrapReason trap_zero, 2472 wasm::WasmCodePosition position) { 2473 Node* stack_slot = 2474 graph()->NewNode(mcgraph()->machine()->StackSlot(2 * sizeof(double))); 2475 2476 const Operator* store_op = mcgraph()->machine()->Store( 2477 StoreRepresentation(MachineRepresentation::kWord64, kNoWriteBarrier)); 2478 SetEffect(graph()->NewNode(store_op, stack_slot, mcgraph()->Int32Constant(0), 2479 left, Effect(), Control())); 2480 SetEffect(graph()->NewNode(store_op, stack_slot, 2481 mcgraph()->Int32Constant(sizeof(double)), right, 2482 Effect(), Control())); 2483 2484 MachineType sig_types[] = {MachineType::Int32(), MachineType::Pointer()}; 2485 MachineSignature sig(1, 1, sig_types); 2486 2487 Node* function = graph()->NewNode(mcgraph()->common()->ExternalConstant(ref)); 2488 Node* call = BuildCCall(&sig, function, stack_slot); 2489 2490 ZeroCheck32(trap_zero, call, position); 2491 TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position); 2492 return SetEffect(graph()->NewNode(mcgraph()->machine()->Load(result_type), 2493 stack_slot, mcgraph()->Int32Constant(0), 2494 Effect(), Control())); 2495 } 2496 2497 template <typename... Args> 2498 Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node* function, 2499 Args... args) { 2500 DCHECK_LE(sig->return_count(), 1); 2501 DCHECK_EQ(sizeof...(args), sig->parameter_count()); 2502 Node* const call_args[] = {function, args..., Effect(), Control()}; 2503 2504 auto call_descriptor = 2505 Linkage::GetSimplifiedCDescriptor(mcgraph()->zone(), sig); 2506 2507 const Operator* op = mcgraph()->common()->Call(call_descriptor); 2508 return SetEffect(graph()->NewNode(op, arraysize(call_args), call_args)); 2509 } 2510 2511 Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args, 2512 Node*** rets, 2513 wasm::WasmCodePosition position, 2514 Node* instance_node, 2515 UseRetpoline use_retpoline) { 2516 if (instance_node == nullptr) { 2517 DCHECK_NOT_NULL(instance_node_); 2518 instance_node = instance_node_.get(); 2519 } 2520 SetNeedsStackCheck(); 2521 const size_t params = sig->parameter_count(); 2522 const size_t extra = 3; // instance_node, effect, and control. 2523 const size_t count = 1 + params + extra; 2524 2525 // Reallocate the buffer to make space for extra inputs. 2526 args = Realloc(args, 1 + params, count); 2527 2528 // Make room for the instance_node parameter at index 1, just after code. 2529 memmove(&args[2], &args[1], params * sizeof(Node*)); 2530 args[1] = instance_node; 2531 2532 // Add effect and control inputs. 2533 args[params + 2] = Effect(); 2534 args[params + 3] = Control(); 2535 2536 auto call_descriptor = 2537 GetWasmCallDescriptor(mcgraph()->zone(), sig, use_retpoline); 2538 const Operator* op = mcgraph()->common()->Call(call_descriptor); 2539 Node* call = SetEffect(graph()->NewNode(op, static_cast<int>(count), args)); 2540 DCHECK(position == wasm::kNoCodePosition || position > 0); 2541 if (position > 0) SetSourcePosition(call, position); 2542 2543 size_t ret_count = sig->return_count(); 2544 if (ret_count == 0) return call; // No return value. 2545 2546 *rets = Buffer(ret_count); 2547 if (ret_count == 1) { 2548 // Only a single return value. 2549 (*rets)[0] = call; 2550 } else { 2551 // Create projections for all return values. 2552 for (size_t i = 0; i < ret_count; i++) { 2553 (*rets)[i] = graph()->NewNode(mcgraph()->common()->Projection(i), call, 2554 graph()->start()); 2555 } 2556 } 2557 return call; 2558 } 2559 2560 Node* WasmGraphBuilder::BuildImportWasmCall(wasm::FunctionSig* sig, Node** args, 2561 Node*** rets, 2562 wasm::WasmCodePosition position, 2563 int func_index) { 2564 // Load the instance from the imported_instances array at a known offset. 2565 Node* imported_instances = LOAD_INSTANCE_FIELD(ImportedFunctionInstances, 2566 MachineType::TaggedPointer()); 2567 Node* instance_node = LOAD_FIXED_ARRAY_SLOT(imported_instances, func_index); 2568 2569 // Load the target from the imported_targets array at a known offset. 2570 Node* imported_targets = 2571 LOAD_INSTANCE_FIELD(ImportedFunctionTargets, MachineType::Pointer()); 2572 Node* target_node = SetEffect(graph()->NewNode( 2573 mcgraph()->machine()->Load(MachineType::Pointer()), imported_targets, 2574 mcgraph()->Int32Constant(func_index * kPointerSize), Effect(), 2575 Control())); 2576 args[0] = target_node; 2577 return BuildWasmCall(sig, args, rets, position, instance_node, 2578 untrusted_code_mitigations_ ? kRetpoline : kNoRetpoline); 2579 } 2580 2581 Node* WasmGraphBuilder::BuildImportWasmCall(wasm::FunctionSig* sig, Node** args, 2582 Node*** rets, 2583 wasm::WasmCodePosition position, 2584 Node* func_index) { 2585 // Load the instance from the imported_instances array. 2586 Node* imported_instances = LOAD_INSTANCE_FIELD(ImportedFunctionInstances, 2587 MachineType::TaggedPointer()); 2588 // Access fixed array at {header_size - tag + func_index * kPointerSize}. 2589 Node* imported_instances_data = 2590 graph()->NewNode(mcgraph()->machine()->IntAdd(), imported_instances, 2591 mcgraph()->IntPtrConstant(FixedArrayOffsetMinusTag(0))); 2592 Node* func_index_times_pointersize = graph()->NewNode( 2593 mcgraph()->machine()->IntMul(), Uint32ToUintptr(func_index), 2594 mcgraph()->Int32Constant(kPointerSize)); 2595 Node* instance_node = SetEffect( 2596 graph()->NewNode(mcgraph()->machine()->Load(MachineType::TaggedPointer()), 2597 imported_instances_data, func_index_times_pointersize, 2598 Effect(), Control())); 2599 2600 // Load the target from the imported_targets array at the offset of 2601 // {func_index}. 2602 Node* imported_targets = 2603 LOAD_INSTANCE_FIELD(ImportedFunctionTargets, MachineType::Pointer()); 2604 Node* target_node = SetEffect(graph()->NewNode( 2605 mcgraph()->machine()->Load(MachineType::Pointer()), imported_targets, 2606 func_index_times_pointersize, Effect(), Control())); 2607 args[0] = target_node; 2608 return BuildWasmCall(sig, args, rets, position, instance_node, 2609 untrusted_code_mitigations_ ? kRetpoline : kNoRetpoline); 2610 } 2611 2612 Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args, Node*** rets, 2613 wasm::WasmCodePosition position) { 2614 DCHECK_NULL(args[0]); 2615 wasm::FunctionSig* sig = env_->module->functions[index].sig; 2616 2617 if (env_ && index < env_->module->num_imported_functions) { 2618 // Call to an imported function. 2619 return BuildImportWasmCall(sig, args, rets, position, index); 2620 } 2621 2622 // A direct call to a wasm function defined in this module. 2623 // Just encode the function index. This will be patched at instantiation. 2624 Address code = static_cast<Address>(index); 2625 args[0] = mcgraph()->RelocatableIntPtrConstant(code, RelocInfo::WASM_CALL); 2626 2627 return BuildWasmCall(sig, args, rets, position, nullptr, kNoRetpoline); 2628 } 2629 2630 Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args, 2631 Node*** rets, 2632 wasm::WasmCodePosition position) { 2633 DCHECK_NOT_NULL(args[0]); 2634 DCHECK_NOT_NULL(env_); 2635 2636 // Assume only one table for now. 2637 wasm::FunctionSig* sig = env_->module->signatures[sig_index]; 2638 2639 Node* ift_size = 2640 LOAD_INSTANCE_FIELD(IndirectFunctionTableSize, MachineType::Uint32()); 2641 2642 MachineOperatorBuilder* machine = mcgraph()->machine(); 2643 Node* key = args[0]; 2644 2645 // Bounds check against the table size. 2646 Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, ift_size); 2647 TrapIfFalse(wasm::kTrapFuncInvalid, in_bounds, position); 2648 2649 // Mask the key to prevent SSCA. 2650 if (untrusted_code_mitigations_) { 2651 // mask = ((key - size) & ~key) >> 31 2652 Node* neg_key = 2653 graph()->NewNode(machine->Word32Xor(), key, Int32Constant(-1)); 2654 Node* masked_diff = graph()->NewNode( 2655 machine->Word32And(), 2656 graph()->NewNode(machine->Int32Sub(), key, ift_size), neg_key); 2657 Node* mask = 2658 graph()->NewNode(machine->Word32Sar(), masked_diff, Int32Constant(31)); 2659 key = graph()->NewNode(machine->Word32And(), key, mask); 2660 } 2661 2662 // Load signature from the table and check. 2663 Node* ift_sig_ids = 2664 LOAD_INSTANCE_FIELD(IndirectFunctionTableSigIds, MachineType::Pointer()); 2665 2666 int32_t expected_sig_id = env_->module->signature_ids[sig_index]; 2667 Node* scaled_key = Uint32ToUintptr( 2668 graph()->NewNode(machine->Word32Shl(), key, Int32Constant(2))); 2669 2670 Node* loaded_sig = 2671 SetEffect(graph()->NewNode(machine->Load(MachineType::Int32()), 2672 ift_sig_ids, scaled_key, Effect(), Control())); 2673 Node* sig_match = graph()->NewNode(machine->WordEqual(), loaded_sig, 2674 Int32Constant(expected_sig_id)); 2675 2676 TrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position); 2677 2678 Node* ift_targets = 2679 LOAD_INSTANCE_FIELD(IndirectFunctionTableTargets, MachineType::Pointer()); 2680 Node* ift_instances = LOAD_INSTANCE_FIELD(IndirectFunctionTableInstances, 2681 MachineType::TaggedPointer()); 2682 2683 scaled_key = graph()->NewNode(machine->Word32Shl(), key, 2684 Int32Constant(kPointerSizeLog2)); 2685 2686 Node* target = 2687 SetEffect(graph()->NewNode(machine->Load(MachineType::Pointer()), 2688 ift_targets, scaled_key, Effect(), Control())); 2689 2690 auto access = AccessBuilder::ForFixedArrayElement(); 2691 Node* target_instance = SetEffect(graph()->NewNode( 2692 machine->Load(MachineType::TaggedPointer()), 2693 graph()->NewNode(machine->IntAdd(), ift_instances, scaled_key), 2694 Int32Constant(access.header_size - access.tag()), Effect(), Control())); 2695 2696 args[0] = target; 2697 2698 return BuildWasmCall(sig, args, rets, position, target_instance, 2699 untrusted_code_mitigations_ ? kRetpoline : kNoRetpoline); 2700 } 2701 2702 Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) { 2703 // Implement Rol by Ror since TurboFan does not have Rol opcode. 2704 // TODO(weiliang): support Word32Rol opcode in TurboFan. 2705 Int32Matcher m(right); 2706 if (m.HasValue()) { 2707 return Binop(wasm::kExprI32Ror, left, 2708 mcgraph()->Int32Constant(32 - m.Value())); 2709 } else { 2710 return Binop(wasm::kExprI32Ror, left, 2711 Binop(wasm::kExprI32Sub, mcgraph()->Int32Constant(32), right)); 2712 } 2713 } 2714 2715 Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) { 2716 // Implement Rol by Ror since TurboFan does not have Rol opcode. 2717 // TODO(weiliang): support Word64Rol opcode in TurboFan. 2718 Int64Matcher m(right); 2719 if (m.HasValue()) { 2720 return Binop(wasm::kExprI64Ror, left, 2721 mcgraph()->Int64Constant(64 - m.Value())); 2722 } else { 2723 return Binop(wasm::kExprI64Ror, left, 2724 Binop(wasm::kExprI64Sub, mcgraph()->Int64Constant(64), right)); 2725 } 2726 } 2727 2728 Node* WasmGraphBuilder::Invert(Node* node) { 2729 return Unop(wasm::kExprI32Eqz, node); 2730 } 2731 2732 bool CanCover(Node* value, IrOpcode::Value opcode) { 2733 if (value->opcode() != opcode) return false; 2734 bool first = true; 2735 for (Edge const edge : value->use_edges()) { 2736 if (NodeProperties::IsControlEdge(edge)) continue; 2737 if (NodeProperties::IsEffectEdge(edge)) continue; 2738 DCHECK(NodeProperties::IsValueEdge(edge)); 2739 if (!first) return false; 2740 first = false; 2741 } 2742 return true; 2743 } 2744 2745 Node* WasmGraphBuilder::BuildChangeInt32ToIntPtr(Node* value) { 2746 if (mcgraph()->machine()->Is64()) { 2747 value = graph()->NewNode(mcgraph()->machine()->ChangeInt32ToInt64(), value); 2748 } 2749 return value; 2750 } 2751 2752 Node* WasmGraphBuilder::BuildChangeInt32ToSmi(Node* value) { 2753 value = BuildChangeInt32ToIntPtr(value); 2754 return graph()->NewNode(mcgraph()->machine()->WordShl(), value, 2755 BuildSmiShiftBitsConstant()); 2756 } 2757 2758 Node* WasmGraphBuilder::BuildChangeUint31ToSmi(Node* value) { 2759 return graph()->NewNode(mcgraph()->machine()->WordShl(), 2760 Uint32ToUintptr(value), BuildSmiShiftBitsConstant()); 2761 } 2762 2763 Node* WasmGraphBuilder::BuildSmiShiftBitsConstant() { 2764 return mcgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize); 2765 } 2766 2767 Node* WasmGraphBuilder::BuildChangeSmiToInt32(Node* value) { 2768 value = graph()->NewNode(mcgraph()->machine()->WordSar(), value, 2769 BuildSmiShiftBitsConstant()); 2770 if (mcgraph()->machine()->Is64()) { 2771 value = 2772 graph()->NewNode(mcgraph()->machine()->TruncateInt64ToInt32(), value); 2773 } 2774 return value; 2775 } 2776 2777 void WasmGraphBuilder::InitInstanceCache( 2778 WasmInstanceCacheNodes* instance_cache) { 2779 DCHECK_NOT_NULL(instance_node_); 2780 2781 // Load the memory start. 2782 instance_cache->mem_start = SetEffect(graph()->NewNode( 2783 mcgraph()->machine()->Load(MachineType::UintPtr()), instance_node_.get(), 2784 mcgraph()->Int32Constant(WASM_INSTANCE_OBJECT_OFFSET(MemoryStart)), 2785 Effect(), Control())); 2786 2787 // Load the memory size. 2788 instance_cache->mem_size = SetEffect(graph()->NewNode( 2789 mcgraph()->machine()->Load(MachineType::UintPtr()), instance_node_.get(), 2790 mcgraph()->Int32Constant(WASM_INSTANCE_OBJECT_OFFSET(MemorySize)), 2791 Effect(), Control())); 2792 2793 if (untrusted_code_mitigations_) { 2794 // Load the memory mask. 2795 instance_cache->mem_mask = SetEffect(graph()->NewNode( 2796 mcgraph()->machine()->Load(MachineType::UintPtr()), 2797 instance_node_.get(), 2798 mcgraph()->Int32Constant(WASM_INSTANCE_OBJECT_OFFSET(MemoryMask)), 2799 Effect(), Control())); 2800 } else { 2801 // Explicitly set to nullptr to ensure a SEGV when we try to use it. 2802 instance_cache->mem_mask = nullptr; 2803 } 2804 } 2805 2806 void WasmGraphBuilder::PrepareInstanceCacheForLoop( 2807 WasmInstanceCacheNodes* instance_cache, Node* control) { 2808 #define INTRODUCE_PHI(field, rep) \ 2809 instance_cache->field = graph()->NewNode(mcgraph()->common()->Phi(rep, 1), \ 2810 instance_cache->field, control); 2811 2812 INTRODUCE_PHI(mem_start, MachineType::PointerRepresentation()); 2813 INTRODUCE_PHI(mem_size, MachineRepresentation::kWord32); 2814 if (untrusted_code_mitigations_) { 2815 INTRODUCE_PHI(mem_mask, MachineRepresentation::kWord32); 2816 } 2817 2818 #undef INTRODUCE_PHI 2819 } 2820 2821 void WasmGraphBuilder::NewInstanceCacheMerge(WasmInstanceCacheNodes* to, 2822 WasmInstanceCacheNodes* from, 2823 Node* merge) { 2824 #define INTRODUCE_PHI(field, rep) \ 2825 if (to->field != from->field) { \ 2826 Node* vals[] = {to->field, from->field, merge}; \ 2827 to->field = graph()->NewNode(mcgraph()->common()->Phi(rep, 2), 3, vals); \ 2828 } 2829 2830 INTRODUCE_PHI(mem_start, MachineType::PointerRepresentation()); 2831 INTRODUCE_PHI(mem_size, MachineRepresentation::kWord32); 2832 if (untrusted_code_mitigations_) { 2833 INTRODUCE_PHI(mem_mask, MachineRepresentation::kWord32); 2834 } 2835 2836 #undef INTRODUCE_PHI 2837 } 2838 2839 void WasmGraphBuilder::MergeInstanceCacheInto(WasmInstanceCacheNodes* to, 2840 WasmInstanceCacheNodes* from, 2841 Node* merge) { 2842 to->mem_size = CreateOrMergeIntoPhi(MachineType::PointerRepresentation(), 2843 merge, to->mem_size, from->mem_size); 2844 to->mem_start = CreateOrMergeIntoPhi(MachineType::PointerRepresentation(), 2845 merge, to->mem_start, from->mem_start); 2846 if (untrusted_code_mitigations_) { 2847 to->mem_mask = CreateOrMergeIntoPhi(MachineType::PointerRepresentation(), 2848 merge, to->mem_mask, from->mem_mask); 2849 } 2850 } 2851 2852 Node* WasmGraphBuilder::CreateOrMergeIntoPhi(MachineRepresentation rep, 2853 Node* merge, Node* tnode, 2854 Node* fnode) { 2855 if (IsPhiWithMerge(tnode, merge)) { 2856 AppendToPhi(tnode, fnode); 2857 } else if (tnode != fnode) { 2858 uint32_t count = merge->InputCount(); 2859 // + 1 for the merge node. 2860 Node** vals = Buffer(count + 1); 2861 for (uint32_t j = 0; j < count - 1; j++) vals[j] = tnode; 2862 vals[count - 1] = fnode; 2863 vals[count] = merge; 2864 return graph()->NewNode(mcgraph()->common()->Phi(rep, count), count + 1, 2865 vals); 2866 } 2867 return tnode; 2868 } 2869 2870 Node* WasmGraphBuilder::CreateOrMergeIntoEffectPhi(Node* merge, Node* tnode, 2871 Node* fnode) { 2872 if (IsPhiWithMerge(tnode, merge)) { 2873 AppendToPhi(tnode, fnode); 2874 } else if (tnode != fnode) { 2875 uint32_t count = merge->InputCount(); 2876 Node** effects = Buffer(count); 2877 for (uint32_t j = 0; j < count - 1; j++) { 2878 effects[j] = tnode; 2879 } 2880 effects[count - 1] = fnode; 2881 tnode = EffectPhi(count, effects, merge); 2882 } 2883 return tnode; 2884 } 2885 2886 void WasmGraphBuilder::GetGlobalBaseAndOffset(MachineType mem_type, 2887 const wasm::WasmGlobal& global, 2888 Node** base_node, 2889 Node** offset_node) { 2890 DCHECK_NOT_NULL(instance_node_); 2891 if (global.mutability && global.imported) { 2892 if (imported_mutable_globals_ == nullptr) { 2893 // Load imported_mutable_globals_ from the instance object at runtime. 2894 imported_mutable_globals_ = graph()->NewNode( 2895 mcgraph()->machine()->Load(MachineType::UintPtr()), 2896 instance_node_.get(), 2897 mcgraph()->Int32Constant( 2898 WASM_INSTANCE_OBJECT_OFFSET(ImportedMutableGlobals)), 2899 graph()->start(), graph()->start()); 2900 } 2901 *base_node = SetEffect(graph()->NewNode( 2902 mcgraph()->machine()->Load(MachineType::UintPtr()), 2903 imported_mutable_globals_.get(), 2904 mcgraph()->Int32Constant(global.index * sizeof(Address)), Effect(), 2905 Control())); 2906 *offset_node = mcgraph()->Int32Constant(0); 2907 } else { 2908 if (globals_start_ == nullptr) { 2909 // Load globals_start from the instance object at runtime. 2910 // TODO(wasm): we currently generate only one load of the {globals_start} 2911 // start per graph, which means it can be placed anywhere by the 2912 // scheduler. This is legal because the globals_start should never change. 2913 // However, in some cases (e.g. if the instance object is already in a 2914 // register), it is slightly more efficient to reload this value from the 2915 // instance object. Since this depends on register allocation, it is not 2916 // possible to express in the graph, and would essentially constitute a 2917 // "mem2reg" optimization in TurboFan. 2918 globals_start_ = graph()->NewNode( 2919 mcgraph()->machine()->Load(MachineType::UintPtr()), 2920 instance_node_.get(), 2921 mcgraph()->Int32Constant(WASM_INSTANCE_OBJECT_OFFSET(GlobalsStart)), 2922 graph()->start(), graph()->start()); 2923 } 2924 *base_node = globals_start_.get(); 2925 *offset_node = mcgraph()->Int32Constant(global.offset); 2926 2927 if (mem_type == MachineType::Simd128() && global.offset != 0) { 2928 // TODO(titzer,bbudge): code generation for SIMD memory offsets is broken. 2929 *base_node = graph()->NewNode(mcgraph()->machine()->IntAdd(), *base_node, 2930 *offset_node); 2931 *offset_node = mcgraph()->Int32Constant(0); 2932 } 2933 } 2934 } 2935 2936 Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { 2937 DCHECK_NOT_NULL(instance_cache_); 2938 Node* mem_start = instance_cache_->mem_start; 2939 DCHECK_NOT_NULL(mem_start); 2940 if (offset == 0) return mem_start; 2941 return graph()->NewNode(mcgraph()->machine()->IntAdd(), mem_start, 2942 mcgraph()->IntPtrConstant(offset)); 2943 } 2944 2945 Node* WasmGraphBuilder::CurrentMemoryPages() { 2946 // CurrentMemoryPages can not be called from asm.js. 2947 DCHECK_EQ(wasm::kWasmOrigin, env_->module->origin); 2948 DCHECK_NOT_NULL(instance_cache_); 2949 Node* mem_size = instance_cache_->mem_size; 2950 DCHECK_NOT_NULL(mem_size); 2951 Node* result = 2952 graph()->NewNode(mcgraph()->machine()->WordShr(), mem_size, 2953 mcgraph()->Int32Constant(wasm::kWasmPageSizeLog2)); 2954 if (mcgraph()->machine()->Is64()) { 2955 result = 2956 graph()->NewNode(mcgraph()->machine()->TruncateInt64ToInt32(), result); 2957 } 2958 return result; 2959 } 2960 2961 // Only call this function for code which is not reused across instantiations, 2962 // as we do not patch the embedded js_context. 2963 Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f, 2964 Node* js_context, 2965 Node** parameters, 2966 int parameter_count) { 2967 const Runtime::Function* fun = Runtime::FunctionForId(f); 2968 auto call_descriptor = Linkage::GetRuntimeCallDescriptor( 2969 mcgraph()->zone(), f, fun->nargs, Operator::kNoProperties, 2970 CallDescriptor::kNoFlags); 2971 // The CEntryStub is loaded from the instance_node so that generated code is 2972 // Isolate independent. At the moment this is only done for CEntryStub(1). 2973 DCHECK_EQ(1, fun->result_size); 2974 Node* centry_stub = 2975 LOAD_INSTANCE_FIELD(CEntryStub, MachineType::TaggedPointer()); 2976 // At the moment we only allow 4 parameters. If more parameters are needed, 2977 // increase this constant accordingly. 2978 static const int kMaxParams = 4; 2979 DCHECK_GE(kMaxParams, parameter_count); 2980 Node* inputs[kMaxParams + 6]; 2981 int count = 0; 2982 inputs[count++] = centry_stub; 2983 for (int i = 0; i < parameter_count; i++) { 2984 inputs[count++] = parameters[i]; 2985 } 2986 inputs[count++] = 2987 mcgraph()->ExternalConstant(ExternalReference::Create(f)); // ref 2988 inputs[count++] = mcgraph()->Int32Constant(fun->nargs); // arity 2989 inputs[count++] = js_context; // js_context 2990 inputs[count++] = Effect(); 2991 inputs[count++] = Control(); 2992 2993 return SetEffect(mcgraph()->graph()->NewNode( 2994 mcgraph()->common()->Call(call_descriptor), count, inputs)); 2995 } 2996 2997 Node* WasmGraphBuilder::BuildCallToRuntime(Runtime::FunctionId f, 2998 Node** parameters, 2999 int parameter_count) { 3000 return BuildCallToRuntimeWithContext(f, NoContextConstant(), parameters, 3001 parameter_count); 3002 } 3003 3004 Node* WasmGraphBuilder::GetGlobal(uint32_t index) { 3005 MachineType mem_type = 3006 wasm::ValueTypes::MachineTypeFor(env_->module->globals[index].type); 3007 Node* base = nullptr; 3008 Node* offset = nullptr; 3009 GetGlobalBaseAndOffset(mem_type, env_->module->globals[index], &base, 3010 &offset); 3011 Node* load = SetEffect(graph()->NewNode(mcgraph()->machine()->Load(mem_type), 3012 base, offset, Effect(), Control())); 3013 #if defined(V8_TARGET_BIG_ENDIAN) 3014 load = BuildChangeEndiannessLoad(load, mem_type, 3015 env_->module->globals[index].type); 3016 #endif 3017 return load; 3018 } 3019 3020 Node* WasmGraphBuilder::SetGlobal(uint32_t index, Node* val) { 3021 MachineType mem_type = 3022 wasm::ValueTypes::MachineTypeFor(env_->module->globals[index].type); 3023 Node* base = nullptr; 3024 Node* offset = nullptr; 3025 GetGlobalBaseAndOffset(mem_type, env_->module->globals[index], &base, 3026 &offset); 3027 const Operator* op = mcgraph()->machine()->Store( 3028 StoreRepresentation(mem_type.representation(), kNoWriteBarrier)); 3029 #if defined(V8_TARGET_BIG_ENDIAN) 3030 val = BuildChangeEndiannessStore(val, mem_type.representation(), 3031 env_->module->globals[index].type); 3032 #endif 3033 return SetEffect( 3034 graph()->NewNode(op, base, offset, val, Effect(), Control())); 3035 } 3036 3037 Node* WasmGraphBuilder::CheckBoundsAndAlignment( 3038 uint8_t access_size, Node* index, uint32_t offset, 3039 wasm::WasmCodePosition position) { 3040 // Atomic operations access the memory, need to be bound checked till 3041 // TrapHandlers are enabled on atomic operations 3042 index = 3043 BoundsCheckMem(access_size, index, offset, position, kNeedsBoundsCheck); 3044 Node* effective_address = 3045 graph()->NewNode(mcgraph()->machine()->IntAdd(), MemBuffer(offset), 3046 Uint32ToUintptr(index)); 3047 // Unlike regular memory accesses, unaligned memory accesses for atomic 3048 // operations should trap 3049 // Access sizes are in powers of two, calculate mod without using division 3050 Node* cond = 3051 graph()->NewNode(mcgraph()->machine()->WordAnd(), effective_address, 3052 IntPtrConstant(access_size - 1)); 3053 TrapIfFalse(wasm::kTrapUnalignedAccess, 3054 graph()->NewNode(mcgraph()->machine()->Word32Equal(), cond, 3055 mcgraph()->Int32Constant(0)), 3056 position); 3057 return index; 3058 } 3059 3060 Node* WasmGraphBuilder::BoundsCheckMem(uint8_t access_size, Node* index, 3061 uint32_t offset, 3062 wasm::WasmCodePosition position, 3063 EnforceBoundsCheck enforce_check) { 3064 DCHECK_LE(1, access_size); 3065 index = Uint32ToUintptr(index); 3066 if (FLAG_wasm_no_bounds_checks) return index; 3067 3068 if (use_trap_handler() && enforce_check == kCanOmitBoundsCheck) { 3069 return index; 3070 } 3071 3072 const bool statically_oob = access_size > env_->max_memory_size || 3073 offset > env_->max_memory_size - access_size; 3074 if (statically_oob) { 3075 // The access will be out of bounds, even for the largest memory. 3076 TrapIfEq32(wasm::kTrapMemOutOfBounds, Int32Constant(0), 0, position); 3077 return mcgraph()->IntPtrConstant(0); 3078 } 3079 uint64_t end_offset = uint64_t{offset} + access_size - 1u; 3080 Node* end_offset_node = IntPtrConstant(end_offset); 3081 3082 // The accessed memory is [index + offset, index + end_offset]. 3083 // Check that the last read byte (at {index + end_offset}) is in bounds. 3084 // 1) Check that {end_offset < mem_size}. This also ensures that we can safely 3085 // compute {effective_size} as {mem_size - end_offset)}. 3086 // {effective_size} is >= 1 if condition 1) holds. 3087 // 2) Check that {index + end_offset < mem_size} by 3088 // - computing {effective_size} as {mem_size - end_offset} and 3089 // - checking that {index < effective_size}. 3090 3091 auto m = mcgraph()->machine(); 3092 Node* mem_size = instance_cache_->mem_size; 3093 if (end_offset >= env_->min_memory_size) { 3094 // The end offset is larger than the smallest memory. 3095 // Dynamically check the end offset against the dynamic memory size. 3096 Node* cond = graph()->NewNode(m->UintLessThan(), end_offset_node, mem_size); 3097 TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); 3098 } else { 3099 // The end offset is smaller than the smallest memory, so only one check is 3100 // required. Check to see if the index is also a constant. 3101 UintPtrMatcher match(index); 3102 if (match.HasValue()) { 3103 uintptr_t index_val = match.Value(); 3104 if (index_val < env_->min_memory_size - end_offset) { 3105 // The input index is a constant and everything is statically within 3106 // bounds of the smallest possible memory. 3107 return index; 3108 } 3109 } 3110 } 3111 3112 // This produces a positive number, since {end_offset < min_size <= mem_size}. 3113 Node* effective_size = 3114 graph()->NewNode(m->IntSub(), mem_size, end_offset_node); 3115 3116 // Introduce the actual bounds check. 3117 Node* cond = graph()->NewNode(m->UintLessThan(), index, effective_size); 3118 TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); 3119 3120 if (untrusted_code_mitigations_) { 3121 // In the fallthrough case, condition the index with the memory mask. 3122 Node* mem_mask = instance_cache_->mem_mask; 3123 DCHECK_NOT_NULL(mem_mask); 3124 index = graph()->NewNode(m->WordAnd(), index, mem_mask); 3125 } 3126 return index; 3127 } 3128 3129 const Operator* WasmGraphBuilder::GetSafeLoadOperator(int offset, 3130 wasm::ValueType type) { 3131 int alignment = offset % (wasm::ValueTypes::ElementSizeInBytes(type)); 3132 MachineType mach_type = wasm::ValueTypes::MachineTypeFor(type); 3133 if (alignment == 0 || mcgraph()->machine()->UnalignedLoadSupported( 3134 wasm::ValueTypes::MachineRepresentationFor(type))) { 3135 return mcgraph()->machine()->Load(mach_type); 3136 } 3137 return mcgraph()->machine()->UnalignedLoad(mach_type); 3138 } 3139 3140 const Operator* WasmGraphBuilder::GetSafeStoreOperator(int offset, 3141 wasm::ValueType type) { 3142 int alignment = offset % (wasm::ValueTypes::ElementSizeInBytes(type)); 3143 MachineRepresentation rep = wasm::ValueTypes::MachineRepresentationFor(type); 3144 if (alignment == 0 || mcgraph()->machine()->UnalignedStoreSupported(rep)) { 3145 StoreRepresentation store_rep(rep, WriteBarrierKind::kNoWriteBarrier); 3146 return mcgraph()->machine()->Store(store_rep); 3147 } 3148 UnalignedStoreRepresentation store_rep(rep); 3149 return mcgraph()->machine()->UnalignedStore(store_rep); 3150 } 3151 3152 Node* WasmGraphBuilder::TraceMemoryOperation(bool is_store, 3153 MachineRepresentation rep, 3154 Node* index, uint32_t offset, 3155 wasm::WasmCodePosition position) { 3156 int kAlign = 4; // Ensure that the LSB is 0, such that this looks like a Smi. 3157 Node* info = graph()->NewNode( 3158 mcgraph()->machine()->StackSlot(sizeof(wasm::MemoryTracingInfo), kAlign)); 3159 3160 Node* address = graph()->NewNode(mcgraph()->machine()->Int32Add(), 3161 Int32Constant(offset), index); 3162 auto store = [&](int offset, MachineRepresentation rep, Node* data) { 3163 SetEffect(graph()->NewNode( 3164 mcgraph()->machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), 3165 info, mcgraph()->Int32Constant(offset), data, Effect(), Control())); 3166 }; 3167 // Store address, is_store, and mem_rep. 3168 store(offsetof(wasm::MemoryTracingInfo, address), 3169 MachineRepresentation::kWord32, address); 3170 store(offsetof(wasm::MemoryTracingInfo, is_store), 3171 MachineRepresentation::kWord8, 3172 mcgraph()->Int32Constant(is_store ? 1 : 0)); 3173 store(offsetof(wasm::MemoryTracingInfo, mem_rep), 3174 MachineRepresentation::kWord8, 3175 mcgraph()->Int32Constant(static_cast<int>(rep))); 3176 3177 Node* call = BuildCallToRuntime(Runtime::kWasmTraceMemory, &info, 1); 3178 SetSourcePosition(call, position); 3179 return call; 3180 } 3181 3182 Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype, 3183 Node* index, uint32_t offset, 3184 uint32_t alignment, 3185 wasm::WasmCodePosition position) { 3186 Node* load; 3187 3188 // Wasm semantics throw on OOB. Introduce explicit bounds check and 3189 // conditioning when not using the trap handler. 3190 index = BoundsCheckMem(wasm::ValueTypes::MemSize(memtype), index, offset, 3191 position, kCanOmitBoundsCheck); 3192 3193 if (memtype.representation() == MachineRepresentation::kWord8 || 3194 mcgraph()->machine()->UnalignedLoadSupported(memtype.representation())) { 3195 if (use_trap_handler()) { 3196 load = graph()->NewNode(mcgraph()->machine()->ProtectedLoad(memtype), 3197 MemBuffer(offset), index, Effect(), Control()); 3198 SetSourcePosition(load, position); 3199 } else { 3200 load = graph()->NewNode(mcgraph()->machine()->Load(memtype), 3201 MemBuffer(offset), index, Effect(), Control()); 3202 } 3203 } else { 3204 // TODO(eholk): Support unaligned loads with trap handlers. 3205 DCHECK(!use_trap_handler()); 3206 load = graph()->NewNode(mcgraph()->machine()->UnalignedLoad(memtype), 3207 MemBuffer(offset), index, Effect(), Control()); 3208 } 3209 3210 SetEffect(load); 3211 3212 #if defined(V8_TARGET_BIG_ENDIAN) 3213 load = BuildChangeEndiannessLoad(load, memtype, type); 3214 #endif 3215 3216 if (type == wasm::kWasmI64 && 3217 ElementSizeInBytes(memtype.representation()) < 8) { 3218 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. 3219 if (memtype.IsSigned()) { 3220 // sign extend 3221 load = graph()->NewNode(mcgraph()->machine()->ChangeInt32ToInt64(), load); 3222 } else { 3223 // zero extend 3224 load = 3225 graph()->NewNode(mcgraph()->machine()->ChangeUint32ToUint64(), load); 3226 } 3227 } 3228 3229 if (FLAG_wasm_trace_memory) { 3230 TraceMemoryOperation(false, memtype.representation(), index, offset, 3231 position); 3232 } 3233 3234 return load; 3235 } 3236 3237 Node* WasmGraphBuilder::StoreMem(MachineRepresentation mem_rep, Node* index, 3238 uint32_t offset, uint32_t alignment, Node* val, 3239 wasm::WasmCodePosition position, 3240 wasm::ValueType type) { 3241 Node* store; 3242 3243 index = BoundsCheckMem(i::ElementSizeInBytes(mem_rep), index, offset, 3244 position, kCanOmitBoundsCheck); 3245 3246 #if defined(V8_TARGET_BIG_ENDIAN) 3247 val = BuildChangeEndiannessStore(val, mem_rep, type); 3248 #endif 3249 3250 if (mem_rep == MachineRepresentation::kWord8 || 3251 mcgraph()->machine()->UnalignedStoreSupported(mem_rep)) { 3252 if (use_trap_handler()) { 3253 store = 3254 graph()->NewNode(mcgraph()->machine()->ProtectedStore(mem_rep), 3255 MemBuffer(offset), index, val, Effect(), Control()); 3256 SetSourcePosition(store, position); 3257 } else { 3258 StoreRepresentation rep(mem_rep, kNoWriteBarrier); 3259 store = 3260 graph()->NewNode(mcgraph()->machine()->Store(rep), MemBuffer(offset), 3261 index, val, Effect(), Control()); 3262 } 3263 } else { 3264 // TODO(eholk): Support unaligned stores with trap handlers. 3265 DCHECK(!use_trap_handler()); 3266 UnalignedStoreRepresentation rep(mem_rep); 3267 store = 3268 graph()->NewNode(mcgraph()->machine()->UnalignedStore(rep), 3269 MemBuffer(offset), index, val, Effect(), Control()); 3270 } 3271 3272 SetEffect(store); 3273 3274 if (FLAG_wasm_trace_memory) { 3275 TraceMemoryOperation(true, mem_rep, index, offset, position); 3276 } 3277 3278 return store; 3279 } 3280 3281 namespace { 3282 Node* GetAsmJsOOBValue(MachineRepresentation rep, MachineGraph* mcgraph) { 3283 switch (rep) { 3284 case MachineRepresentation::kWord8: 3285 case MachineRepresentation::kWord16: 3286 case MachineRepresentation::kWord32: 3287 return mcgraph->Int32Constant(0); 3288 case MachineRepresentation::kWord64: 3289 return mcgraph->Int64Constant(0); 3290 case MachineRepresentation::kFloat32: 3291 return mcgraph->Float32Constant(std::numeric_limits<float>::quiet_NaN()); 3292 case MachineRepresentation::kFloat64: 3293 return mcgraph->Float64Constant(std::numeric_limits<double>::quiet_NaN()); 3294 default: 3295 UNREACHABLE(); 3296 } 3297 } 3298 } // namespace 3299 3300 Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { 3301 DCHECK_NOT_NULL(instance_cache_); 3302 Node* mem_start = instance_cache_->mem_start; 3303 Node* mem_size = instance_cache_->mem_size; 3304 DCHECK_NOT_NULL(mem_start); 3305 DCHECK_NOT_NULL(mem_size); 3306 3307 // Asm.js semantics are defined in terms of typed arrays, hence OOB 3308 // reads return {undefined} coerced to the result type (0 for integers, NaN 3309 // for float and double). 3310 // Note that we check against the memory size ignoring the size of the 3311 // stored value, which is conservative if misaligned. Technically, asm.js 3312 // should never have misaligned accesses. 3313 index = Uint32ToUintptr(index); 3314 Diamond bounds_check( 3315 graph(), mcgraph()->common(), 3316 graph()->NewNode(mcgraph()->machine()->UintLessThan(), index, mem_size), 3317 BranchHint::kTrue); 3318 bounds_check.Chain(Control()); 3319 3320 if (untrusted_code_mitigations_) { 3321 // Condition the index with the memory mask. 3322 Node* mem_mask = instance_cache_->mem_mask; 3323 DCHECK_NOT_NULL(mem_mask); 3324 index = graph()->NewNode(mcgraph()->machine()->WordAnd(), index, mem_mask); 3325 } 3326 3327 Node* load = graph()->NewNode(mcgraph()->machine()->Load(type), mem_start, 3328 index, Effect(), bounds_check.if_true); 3329 SetEffect(bounds_check.EffectPhi(load, Effect())); 3330 SetControl(bounds_check.merge); 3331 return bounds_check.Phi(type.representation(), load, 3332 GetAsmJsOOBValue(type.representation(), mcgraph())); 3333 } 3334 3335 Node* WasmGraphBuilder::Uint32ToUintptr(Node* node) { 3336 if (mcgraph()->machine()->Is32()) return node; 3337 // Fold instances of ChangeUint32ToUint64(IntConstant) directly. 3338 Uint32Matcher matcher(node); 3339 if (matcher.HasValue()) { 3340 uintptr_t value = matcher.Value(); 3341 return mcgraph()->IntPtrConstant(bit_cast<intptr_t>(value)); 3342 } 3343 return graph()->NewNode(mcgraph()->machine()->ChangeUint32ToUint64(), node); 3344 } 3345 3346 Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index, 3347 Node* val) { 3348 DCHECK_NOT_NULL(instance_cache_); 3349 Node* mem_start = instance_cache_->mem_start; 3350 Node* mem_size = instance_cache_->mem_size; 3351 DCHECK_NOT_NULL(mem_start); 3352 DCHECK_NOT_NULL(mem_size); 3353 3354 // Asm.js semantics are to ignore OOB writes. 3355 // Note that we check against the memory size ignoring the size of the 3356 // stored value, which is conservative if misaligned. Technically, asm.js 3357 // should never have misaligned accesses. 3358 Diamond bounds_check( 3359 graph(), mcgraph()->common(), 3360 graph()->NewNode(mcgraph()->machine()->Uint32LessThan(), index, mem_size), 3361 BranchHint::kTrue); 3362 bounds_check.Chain(Control()); 3363 3364 if (untrusted_code_mitigations_) { 3365 // Condition the index with the memory mask. 3366 Node* mem_mask = instance_cache_->mem_mask; 3367 DCHECK_NOT_NULL(mem_mask); 3368 index = 3369 graph()->NewNode(mcgraph()->machine()->Word32And(), index, mem_mask); 3370 } 3371 3372 index = Uint32ToUintptr(index); 3373 const Operator* store_op = mcgraph()->machine()->Store(StoreRepresentation( 3374 type.representation(), WriteBarrierKind::kNoWriteBarrier)); 3375 Node* store = graph()->NewNode(store_op, mem_start, index, val, Effect(), 3376 bounds_check.if_true); 3377 SetEffect(bounds_check.EffectPhi(store, Effect())); 3378 SetControl(bounds_check.merge); 3379 return val; 3380 } 3381 3382 void WasmGraphBuilder::PrintDebugName(Node* node) { 3383 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); 3384 } 3385 3386 Graph* WasmGraphBuilder::graph() { return mcgraph()->graph(); } 3387 3388 namespace { 3389 Signature<MachineRepresentation>* CreateMachineSignature( 3390 Zone* zone, wasm::FunctionSig* sig) { 3391 Signature<MachineRepresentation>::Builder builder(zone, sig->return_count(), 3392 sig->parameter_count()); 3393 for (auto ret : sig->returns()) { 3394 builder.AddReturn(wasm::ValueTypes::MachineRepresentationFor(ret)); 3395 } 3396 3397 for (auto param : sig->parameters()) { 3398 builder.AddParam(wasm::ValueTypes::MachineRepresentationFor(param)); 3399 } 3400 return builder.Build(); 3401 } 3402 } // namespace 3403 3404 void WasmGraphBuilder::LowerInt64() { 3405 if (mcgraph()->machine()->Is64()) return; 3406 Int64Lowering r(mcgraph()->graph(), mcgraph()->machine(), mcgraph()->common(), 3407 mcgraph()->zone(), 3408 CreateMachineSignature(mcgraph()->zone(), sig_)); 3409 r.LowerGraph(); 3410 } 3411 3412 void WasmGraphBuilder::SimdScalarLoweringForTesting() { 3413 SimdScalarLowering(mcgraph(), CreateMachineSignature(mcgraph()->zone(), sig_)) 3414 .LowerGraph(); 3415 } 3416 3417 void WasmGraphBuilder::SetSourcePosition(Node* node, 3418 wasm::WasmCodePosition position) { 3419 DCHECK_NE(position, wasm::kNoCodePosition); 3420 if (source_position_table_) 3421 source_position_table_->SetSourcePosition(node, SourcePosition(position)); 3422 } 3423 3424 Node* WasmGraphBuilder::S128Zero() { 3425 has_simd_ = true; 3426 return graph()->NewNode(mcgraph()->machine()->S128Zero()); 3427 } 3428 3429 Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) { 3430 has_simd_ = true; 3431 switch (opcode) { 3432 case wasm::kExprF32x4Splat: 3433 return graph()->NewNode(mcgraph()->machine()->F32x4Splat(), inputs[0]); 3434 case wasm::kExprF32x4SConvertI32x4: 3435 return graph()->NewNode(mcgraph()->machine()->F32x4SConvertI32x4(), 3436 inputs[0]); 3437 case wasm::kExprF32x4UConvertI32x4: 3438 return graph()->NewNode(mcgraph()->machine()->F32x4UConvertI32x4(), 3439 inputs[0]); 3440 case wasm::kExprF32x4Abs: 3441 return graph()->NewNode(mcgraph()->machine()->F32x4Abs(), inputs[0]); 3442 case wasm::kExprF32x4Neg: 3443 return graph()->NewNode(mcgraph()->machine()->F32x4Neg(), inputs[0]); 3444 case wasm::kExprF32x4RecipApprox: 3445 return graph()->NewNode(mcgraph()->machine()->F32x4RecipApprox(), 3446 inputs[0]); 3447 case wasm::kExprF32x4RecipSqrtApprox: 3448 return graph()->NewNode(mcgraph()->machine()->F32x4RecipSqrtApprox(), 3449 inputs[0]); 3450 case wasm::kExprF32x4Add: 3451 return graph()->NewNode(mcgraph()->machine()->F32x4Add(), inputs[0], 3452 inputs[1]); 3453 case wasm::kExprF32x4AddHoriz: 3454 return graph()->NewNode(mcgraph()->machine()->F32x4AddHoriz(), inputs[0], 3455 inputs[1]); 3456 case wasm::kExprF32x4Sub: 3457 return graph()->NewNode(mcgraph()->machine()->F32x4Sub(), inputs[0], 3458 inputs[1]); 3459 case wasm::kExprF32x4Mul: 3460 return graph()->NewNode(mcgraph()->machine()->F32x4Mul(), inputs[0], 3461 inputs[1]); 3462 case wasm::kExprF32x4Min: 3463 return graph()->NewNode(mcgraph()->machine()->F32x4Min(), inputs[0], 3464 inputs[1]); 3465 case wasm::kExprF32x4Max: 3466 return graph()->NewNode(mcgraph()->machine()->F32x4Max(), inputs[0], 3467 inputs[1]); 3468 case wasm::kExprF32x4Eq: 3469 return graph()->NewNode(mcgraph()->machine()->F32x4Eq(), inputs[0], 3470 inputs[1]); 3471 case wasm::kExprF32x4Ne: 3472 return graph()->NewNode(mcgraph()->machine()->F32x4Ne(), inputs[0], 3473 inputs[1]); 3474 case wasm::kExprF32x4Lt: 3475 return graph()->NewNode(mcgraph()->machine()->F32x4Lt(), inputs[0], 3476 inputs[1]); 3477 case wasm::kExprF32x4Le: 3478 return graph()->NewNode(mcgraph()->machine()->F32x4Le(), inputs[0], 3479 inputs[1]); 3480 case wasm::kExprF32x4Gt: 3481 return graph()->NewNode(mcgraph()->machine()->F32x4Lt(), inputs[1], 3482 inputs[0]); 3483 case wasm::kExprF32x4Ge: 3484 return graph()->NewNode(mcgraph()->machine()->F32x4Le(), inputs[1], 3485 inputs[0]); 3486 case wasm::kExprI32x4Splat: 3487 return graph()->NewNode(mcgraph()->machine()->I32x4Splat(), inputs[0]); 3488 case wasm::kExprI32x4SConvertF32x4: 3489 return graph()->NewNode(mcgraph()->machine()->I32x4SConvertF32x4(), 3490 inputs[0]); 3491 case wasm::kExprI32x4UConvertF32x4: 3492 return graph()->NewNode(mcgraph()->machine()->I32x4UConvertF32x4(), 3493 inputs[0]); 3494 case wasm::kExprI32x4SConvertI16x8Low: 3495 return graph()->NewNode(mcgraph()->machine()->I32x4SConvertI16x8Low(), 3496 inputs[0]); 3497 case wasm::kExprI32x4SConvertI16x8High: 3498 return graph()->NewNode(mcgraph()->machine()->I32x4SConvertI16x8High(), 3499 inputs[0]); 3500 case wasm::kExprI32x4Neg: 3501 return graph()->NewNode(mcgraph()->machine()->I32x4Neg(), inputs[0]); 3502 case wasm::kExprI32x4Add: 3503 return graph()->NewNode(mcgraph()->machine()->I32x4Add(), inputs[0], 3504 inputs[1]); 3505 case wasm::kExprI32x4AddHoriz: 3506 return graph()->NewNode(mcgraph()->machine()->I32x4AddHoriz(), inputs[0], 3507 inputs[1]); 3508 case wasm::kExprI32x4Sub: 3509 return graph()->NewNode(mcgraph()->machine()->I32x4Sub(), inputs[0], 3510 inputs[1]); 3511 case wasm::kExprI32x4Mul: 3512 return graph()->NewNode(mcgraph()->machine()->I32x4Mul(), inputs[0], 3513 inputs[1]); 3514 case wasm::kExprI32x4MinS: 3515 return graph()->NewNode(mcgraph()->machine()->I32x4MinS(), inputs[0], 3516 inputs[1]); 3517 case wasm::kExprI32x4MaxS: 3518 return graph()->NewNode(mcgraph()->machine()->I32x4MaxS(), inputs[0], 3519 inputs[1]); 3520 case wasm::kExprI32x4Eq: 3521 return graph()->NewNode(mcgraph()->machine()->I32x4Eq(), inputs[0], 3522 inputs[1]); 3523 case wasm::kExprI32x4Ne: 3524 return graph()->NewNode(mcgraph()->machine()->I32x4Ne(), inputs[0], 3525 inputs[1]); 3526 case wasm::kExprI32x4LtS: 3527 return graph()->NewNode(mcgraph()->machine()->I32x4GtS(), inputs[1], 3528 inputs[0]); 3529 case wasm::kExprI32x4LeS: 3530 return graph()->NewNode(mcgraph()->machine()->I32x4GeS(), inputs[1], 3531 inputs[0]); 3532 case wasm::kExprI32x4GtS: 3533 return graph()->NewNode(mcgraph()->machine()->I32x4GtS(), inputs[0], 3534 inputs[1]); 3535 case wasm::kExprI32x4GeS: 3536 return graph()->NewNode(mcgraph()->machine()->I32x4GeS(), inputs[0], 3537 inputs[1]); 3538 case wasm::kExprI32x4UConvertI16x8Low: 3539 return graph()->NewNode(mcgraph()->machine()->I32x4UConvertI16x8Low(), 3540 inputs[0]); 3541 case wasm::kExprI32x4UConvertI16x8High: 3542 return graph()->NewNode(mcgraph()->machine()->I32x4UConvertI16x8High(), 3543 inputs[0]); 3544 case wasm::kExprI32x4MinU: 3545 return graph()->NewNode(mcgraph()->machine()->I32x4MinU(), inputs[0], 3546 inputs[1]); 3547 case wasm::kExprI32x4MaxU: 3548 return graph()->NewNode(mcgraph()->machine()->I32x4MaxU(), inputs[0], 3549 inputs[1]); 3550 case wasm::kExprI32x4LtU: 3551 return graph()->NewNode(mcgraph()->machine()->I32x4GtU(), inputs[1], 3552 inputs[0]); 3553 case wasm::kExprI32x4LeU: 3554 return graph()->NewNode(mcgraph()->machine()->I32x4GeU(), inputs[1], 3555 inputs[0]); 3556 case wasm::kExprI32x4GtU: 3557 return graph()->NewNode(mcgraph()->machine()->I32x4GtU(), inputs[0], 3558 inputs[1]); 3559 case wasm::kExprI32x4GeU: 3560 return graph()->NewNode(mcgraph()->machine()->I32x4GeU(), inputs[0], 3561 inputs[1]); 3562 case wasm::kExprI16x8Splat: 3563 return graph()->NewNode(mcgraph()->machine()->I16x8Splat(), inputs[0]); 3564 case wasm::kExprI16x8SConvertI8x16Low: 3565 return graph()->NewNode(mcgraph()->machine()->I16x8SConvertI8x16Low(), 3566 inputs[0]); 3567 case wasm::kExprI16x8SConvertI8x16High: 3568 return graph()->NewNode(mcgraph()->machine()->I16x8SConvertI8x16High(), 3569 inputs[0]); 3570 case wasm::kExprI16x8Neg: 3571 return graph()->NewNode(mcgraph()->machine()->I16x8Neg(), inputs[0]); 3572 case wasm::kExprI16x8SConvertI32x4: 3573 return graph()->NewNode(mcgraph()->machine()->I16x8SConvertI32x4(), 3574 inputs[0], inputs[1]); 3575 case wasm::kExprI16x8Add: 3576 return graph()->NewNode(mcgraph()->machine()->I16x8Add(), inputs[0], 3577 inputs[1]); 3578 case wasm::kExprI16x8AddSaturateS: 3579 return graph()->NewNode(mcgraph()->machine()->I16x8AddSaturateS(), 3580 inputs[0], inputs[1]); 3581 case wasm::kExprI16x8AddHoriz: 3582 return graph()->NewNode(mcgraph()->machine()->I16x8AddHoriz(), inputs[0], 3583 inputs[1]); 3584 case wasm::kExprI16x8Sub: 3585 return graph()->NewNode(mcgraph()->machine()->I16x8Sub(), inputs[0], 3586 inputs[1]); 3587 case wasm::kExprI16x8SubSaturateS: 3588 return graph()->NewNode(mcgraph()->machine()->I16x8SubSaturateS(), 3589 inputs[0], inputs[1]); 3590 case wasm::kExprI16x8Mul: 3591 return graph()->NewNode(mcgraph()->machine()->I16x8Mul(), inputs[0], 3592 inputs[1]); 3593 case wasm::kExprI16x8MinS: 3594 return graph()->NewNode(mcgraph()->machine()->I16x8MinS(), inputs[0], 3595 inputs[1]); 3596 case wasm::kExprI16x8MaxS: 3597 return graph()->NewNode(mcgraph()->machine()->I16x8MaxS(), inputs[0], 3598 inputs[1]); 3599 case wasm::kExprI16x8Eq: 3600 return graph()->NewNode(mcgraph()->machine()->I16x8Eq(), inputs[0], 3601 inputs[1]); 3602 case wasm::kExprI16x8Ne: 3603 return graph()->NewNode(mcgraph()->machine()->I16x8Ne(), inputs[0], 3604 inputs[1]); 3605 case wasm::kExprI16x8LtS: 3606 return graph()->NewNode(mcgraph()->machine()->I16x8GtS(), inputs[1], 3607 inputs[0]); 3608 case wasm::kExprI16x8LeS: 3609 return graph()->NewNode(mcgraph()->machine()->I16x8GeS(), inputs[1], 3610 inputs[0]); 3611 case wasm::kExprI16x8GtS: 3612 return graph()->NewNode(mcgraph()->machine()->I16x8GtS(), inputs[0], 3613 inputs[1]); 3614 case wasm::kExprI16x8GeS: 3615 return graph()->NewNode(mcgraph()->machine()->I16x8GeS(), inputs[0], 3616 inputs[1]); 3617 case wasm::kExprI16x8UConvertI8x16Low: 3618 return graph()->NewNode(mcgraph()->machine()->I16x8UConvertI8x16Low(), 3619 inputs[0]); 3620 case wasm::kExprI16x8UConvertI8x16High: 3621 return graph()->NewNode(mcgraph()->machine()->I16x8UConvertI8x16High(), 3622 inputs[0]); 3623 case wasm::kExprI16x8UConvertI32x4: 3624 return graph()->NewNode(mcgraph()->machine()->I16x8UConvertI32x4(), 3625 inputs[0], inputs[1]); 3626 case wasm::kExprI16x8AddSaturateU: 3627 return graph()->NewNode(mcgraph()->machine()->I16x8AddSaturateU(), 3628 inputs[0], inputs[1]); 3629 case wasm::kExprI16x8SubSaturateU: 3630 return graph()->NewNode(mcgraph()->machine()->I16x8SubSaturateU(), 3631 inputs[0], inputs[1]); 3632 case wasm::kExprI16x8MinU: 3633 return graph()->NewNode(mcgraph()->machine()->I16x8MinU(), inputs[0], 3634 inputs[1]); 3635 case wasm::kExprI16x8MaxU: 3636 return graph()->NewNode(mcgraph()->machine()->I16x8MaxU(), inputs[0], 3637 inputs[1]); 3638 case wasm::kExprI16x8LtU: 3639 return graph()->NewNode(mcgraph()->machine()->I16x8GtU(), inputs[1], 3640 inputs[0]); 3641 case wasm::kExprI16x8LeU: 3642 return graph()->NewNode(mcgraph()->machine()->I16x8GeU(), inputs[1], 3643 inputs[0]); 3644 case wasm::kExprI16x8GtU: 3645 return graph()->NewNode(mcgraph()->machine()->I16x8GtU(), inputs[0], 3646 inputs[1]); 3647 case wasm::kExprI16x8GeU: 3648 return graph()->NewNode(mcgraph()->machine()->I16x8GeU(), inputs[0], 3649 inputs[1]); 3650 case wasm::kExprI8x16Splat: 3651 return graph()->NewNode(mcgraph()->machine()->I8x16Splat(), inputs[0]); 3652 case wasm::kExprI8x16Neg: 3653 return graph()->NewNode(mcgraph()->machine()->I8x16Neg(), inputs[0]); 3654 case wasm::kExprI8x16SConvertI16x8: 3655 return graph()->NewNode(mcgraph()->machine()->I8x16SConvertI16x8(), 3656 inputs[0], inputs[1]); 3657 case wasm::kExprI8x16Add: 3658 return graph()->NewNode(mcgraph()->machine()->I8x16Add(), inputs[0], 3659 inputs[1]); 3660 case wasm::kExprI8x16AddSaturateS: 3661 return graph()->NewNode(mcgraph()->machine()->I8x16AddSaturateS(), 3662 inputs[0], inputs[1]); 3663 case wasm::kExprI8x16Sub: 3664 return graph()->NewNode(mcgraph()->machine()->I8x16Sub(), inputs[0], 3665 inputs[1]); 3666 case wasm::kExprI8x16SubSaturateS: 3667 return graph()->NewNode(mcgraph()->machine()->I8x16SubSaturateS(), 3668 inputs[0], inputs[1]); 3669 case wasm::kExprI8x16Mul: 3670 return graph()->NewNode(mcgraph()->machine()->I8x16Mul(), inputs[0], 3671 inputs[1]); 3672 case wasm::kExprI8x16MinS: 3673 return graph()->NewNode(mcgraph()->machine()->I8x16MinS(), inputs[0], 3674 inputs[1]); 3675 case wasm::kExprI8x16MaxS: 3676 return graph()->NewNode(mcgraph()->machine()->I8x16MaxS(), inputs[0], 3677 inputs[1]); 3678 case wasm::kExprI8x16Eq: 3679 return graph()->NewNode(mcgraph()->machine()->I8x16Eq(), inputs[0], 3680 inputs[1]); 3681 case wasm::kExprI8x16Ne: 3682 return graph()->NewNode(mcgraph()->machine()->I8x16Ne(), inputs[0], 3683 inputs[1]); 3684 case wasm::kExprI8x16LtS: 3685 return graph()->NewNode(mcgraph()->machine()->I8x16GtS(), inputs[1], 3686 inputs[0]); 3687 case wasm::kExprI8x16LeS: 3688 return graph()->NewNode(mcgraph()->machine()->I8x16GeS(), inputs[1], 3689 inputs[0]); 3690 case wasm::kExprI8x16GtS: 3691 return graph()->NewNode(mcgraph()->machine()->I8x16GtS(), inputs[0], 3692 inputs[1]); 3693 case wasm::kExprI8x16GeS: 3694 return graph()->NewNode(mcgraph()->machine()->I8x16GeS(), inputs[0], 3695 inputs[1]); 3696 case wasm::kExprI8x16UConvertI16x8: 3697 return graph()->NewNode(mcgraph()->machine()->I8x16UConvertI16x8(), 3698 inputs[0], inputs[1]); 3699 case wasm::kExprI8x16AddSaturateU: 3700 return graph()->NewNode(mcgraph()->machine()->I8x16AddSaturateU(), 3701 inputs[0], inputs[1]); 3702 case wasm::kExprI8x16SubSaturateU: 3703 return graph()->NewNode(mcgraph()->machine()->I8x16SubSaturateU(), 3704 inputs[0], inputs[1]); 3705 case wasm::kExprI8x16MinU: 3706 return graph()->NewNode(mcgraph()->machine()->I8x16MinU(), inputs[0], 3707 inputs[1]); 3708 case wasm::kExprI8x16MaxU: 3709 return graph()->NewNode(mcgraph()->machine()->I8x16MaxU(), inputs[0], 3710 inputs[1]); 3711 case wasm::kExprI8x16LtU: 3712 return graph()->NewNode(mcgraph()->machine()->I8x16GtU(), inputs[1], 3713 inputs[0]); 3714 case wasm::kExprI8x16LeU: 3715 return graph()->NewNode(mcgraph()->machine()->I8x16GeU(), inputs[1], 3716 inputs[0]); 3717 case wasm::kExprI8x16GtU: 3718 return graph()->NewNode(mcgraph()->machine()->I8x16GtU(), inputs[0], 3719 inputs[1]); 3720 case wasm::kExprI8x16GeU: 3721 return graph()->NewNode(mcgraph()->machine()->I8x16GeU(), inputs[0], 3722 inputs[1]); 3723 case wasm::kExprS128And: 3724 return graph()->NewNode(mcgraph()->machine()->S128And(), inputs[0], 3725 inputs[1]); 3726 case wasm::kExprS128Or: 3727 return graph()->NewNode(mcgraph()->machine()->S128Or(), inputs[0], 3728 inputs[1]); 3729 case wasm::kExprS128Xor: 3730 return graph()->NewNode(mcgraph()->machine()->S128Xor(), inputs[0], 3731 inputs[1]); 3732 case wasm::kExprS128Not: 3733 return graph()->NewNode(mcgraph()->machine()->S128Not(), inputs[0]); 3734 case wasm::kExprS128Select: 3735 return graph()->NewNode(mcgraph()->machine()->S128Select(), inputs[0], 3736 inputs[1], inputs[2]); 3737 case wasm::kExprS1x4AnyTrue: 3738 return graph()->NewNode(mcgraph()->machine()->S1x4AnyTrue(), inputs[0]); 3739 case wasm::kExprS1x4AllTrue: 3740 return graph()->NewNode(mcgraph()->machine()->S1x4AllTrue(), inputs[0]); 3741 case wasm::kExprS1x8AnyTrue: 3742 return graph()->NewNode(mcgraph()->machine()->S1x8AnyTrue(), inputs[0]); 3743 case wasm::kExprS1x8AllTrue: 3744 return graph()->NewNode(mcgraph()->machine()->S1x8AllTrue(), inputs[0]); 3745 case wasm::kExprS1x16AnyTrue: 3746 return graph()->NewNode(mcgraph()->machine()->S1x16AnyTrue(), inputs[0]); 3747 case wasm::kExprS1x16AllTrue: 3748 return graph()->NewNode(mcgraph()->machine()->S1x16AllTrue(), inputs[0]); 3749 default: 3750 FATAL_UNSUPPORTED_OPCODE(opcode); 3751 } 3752 } 3753 3754 Node* WasmGraphBuilder::SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane, 3755 Node* const* inputs) { 3756 has_simd_ = true; 3757 switch (opcode) { 3758 case wasm::kExprF32x4ExtractLane: 3759 return graph()->NewNode(mcgraph()->machine()->F32x4ExtractLane(lane), 3760 inputs[0]); 3761 case wasm::kExprF32x4ReplaceLane: 3762 return graph()->NewNode(mcgraph()->machine()->F32x4ReplaceLane(lane), 3763 inputs[0], inputs[1]); 3764 case wasm::kExprI32x4ExtractLane: 3765 return graph()->NewNode(mcgraph()->machine()->I32x4ExtractLane(lane), 3766 inputs[0]); 3767 case wasm::kExprI32x4ReplaceLane: 3768 return graph()->NewNode(mcgraph()->machine()->I32x4ReplaceLane(lane), 3769 inputs[0], inputs[1]); 3770 case wasm::kExprI16x8ExtractLane: 3771 return graph()->NewNode(mcgraph()->machine()->I16x8ExtractLane(lane), 3772 inputs[0]); 3773 case wasm::kExprI16x8ReplaceLane: 3774 return graph()->NewNode(mcgraph()->machine()->I16x8ReplaceLane(lane), 3775 inputs[0], inputs[1]); 3776 case wasm::kExprI8x16ExtractLane: 3777 return graph()->NewNode(mcgraph()->machine()->I8x16ExtractLane(lane), 3778 inputs[0]); 3779 case wasm::kExprI8x16ReplaceLane: 3780 return graph()->NewNode(mcgraph()->machine()->I8x16ReplaceLane(lane), 3781 inputs[0], inputs[1]); 3782 default: 3783 FATAL_UNSUPPORTED_OPCODE(opcode); 3784 } 3785 } 3786 3787 Node* WasmGraphBuilder::SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift, 3788 Node* const* inputs) { 3789 has_simd_ = true; 3790 switch (opcode) { 3791 case wasm::kExprI32x4Shl: 3792 return graph()->NewNode(mcgraph()->machine()->I32x4Shl(shift), inputs[0]); 3793 case wasm::kExprI32x4ShrS: 3794 return graph()->NewNode(mcgraph()->machine()->I32x4ShrS(shift), 3795 inputs[0]); 3796 case wasm::kExprI32x4ShrU: 3797 return graph()->NewNode(mcgraph()->machine()->I32x4ShrU(shift), 3798 inputs[0]); 3799 case wasm::kExprI16x8Shl: 3800 return graph()->NewNode(mcgraph()->machine()->I16x8Shl(shift), inputs[0]); 3801 case wasm::kExprI16x8ShrS: 3802 return graph()->NewNode(mcgraph()->machine()->I16x8ShrS(shift), 3803 inputs[0]); 3804 case wasm::kExprI16x8ShrU: 3805 return graph()->NewNode(mcgraph()->machine()->I16x8ShrU(shift), 3806 inputs[0]); 3807 case wasm::kExprI8x16Shl: 3808 return graph()->NewNode(mcgraph()->machine()->I8x16Shl(shift), inputs[0]); 3809 case wasm::kExprI8x16ShrS: 3810 return graph()->NewNode(mcgraph()->machine()->I8x16ShrS(shift), 3811 inputs[0]); 3812 case wasm::kExprI8x16ShrU: 3813 return graph()->NewNode(mcgraph()->machine()->I8x16ShrU(shift), 3814 inputs[0]); 3815 default: 3816 FATAL_UNSUPPORTED_OPCODE(opcode); 3817 } 3818 } 3819 3820 Node* WasmGraphBuilder::Simd8x16ShuffleOp(const uint8_t shuffle[16], 3821 Node* const* inputs) { 3822 has_simd_ = true; 3823 return graph()->NewNode(mcgraph()->machine()->S8x16Shuffle(shuffle), 3824 inputs[0], inputs[1]); 3825 } 3826 3827 #define ATOMIC_BINOP_LIST(V) \ 3828 V(I32AtomicAdd, Add, Uint32, Word32) \ 3829 V(I64AtomicAdd, Add, Uint64, Word64) \ 3830 V(I32AtomicAdd8U, Add, Uint8, Word32) \ 3831 V(I32AtomicAdd16U, Add, Uint16, Word32) \ 3832 V(I64AtomicAdd8U, Add, Uint8, Word64) \ 3833 V(I64AtomicAdd16U, Add, Uint16, Word64) \ 3834 V(I64AtomicAdd32U, Add, Uint32, Word64) \ 3835 V(I32AtomicSub, Sub, Uint32, Word32) \ 3836 V(I64AtomicSub, Sub, Uint64, Word64) \ 3837 V(I32AtomicSub8U, Sub, Uint8, Word32) \ 3838 V(I32AtomicSub16U, Sub, Uint16, Word32) \ 3839 V(I64AtomicSub8U, Sub, Uint8, Word64) \ 3840 V(I64AtomicSub16U, Sub, Uint16, Word64) \ 3841 V(I64AtomicSub32U, Sub, Uint32, Word64) \ 3842 V(I32AtomicAnd, And, Uint32, Word32) \ 3843 V(I64AtomicAnd, And, Uint64, Word64) \ 3844 V(I32AtomicAnd8U, And, Uint8, Word32) \ 3845 V(I64AtomicAnd16U, And, Uint16, Word64) \ 3846 V(I32AtomicAnd16U, And, Uint16, Word32) \ 3847 V(I64AtomicAnd8U, And, Uint8, Word64) \ 3848 V(I64AtomicAnd32U, And, Uint32, Word64) \ 3849 V(I32AtomicOr, Or, Uint32, Word32) \ 3850 V(I64AtomicOr, Or, Uint64, Word64) \ 3851 V(I32AtomicOr8U, Or, Uint8, Word32) \ 3852 V(I32AtomicOr16U, Or, Uint16, Word32) \ 3853 V(I64AtomicOr8U, Or, Uint8, Word64) \ 3854 V(I64AtomicOr16U, Or, Uint16, Word64) \ 3855 V(I64AtomicOr32U, Or, Uint32, Word64) \ 3856 V(I32AtomicXor, Xor, Uint32, Word32) \ 3857 V(I64AtomicXor, Xor, Uint64, Word64) \ 3858 V(I32AtomicXor8U, Xor, Uint8, Word32) \ 3859 V(I32AtomicXor16U, Xor, Uint16, Word32) \ 3860 V(I64AtomicXor8U, Xor, Uint8, Word64) \ 3861 V(I64AtomicXor16U, Xor, Uint16, Word64) \ 3862 V(I64AtomicXor32U, Xor, Uint32, Word64) \ 3863 V(I32AtomicExchange, Exchange, Uint32, Word32) \ 3864 V(I64AtomicExchange, Exchange, Uint64, Word64) \ 3865 V(I32AtomicExchange8U, Exchange, Uint8, Word32) \ 3866 V(I32AtomicExchange16U, Exchange, Uint16, Word32) \ 3867 V(I64AtomicExchange8U, Exchange, Uint8, Word64) \ 3868 V(I64AtomicExchange16U, Exchange, Uint16, Word64) \ 3869 V(I64AtomicExchange32U, Exchange, Uint32, Word64) 3870 3871 #define ATOMIC_CMP_EXCHG_LIST(V) \ 3872 V(I32AtomicCompareExchange, Uint32, Word32) \ 3873 V(I64AtomicCompareExchange, Uint64, Word64) \ 3874 V(I32AtomicCompareExchange8U, Uint8, Word32) \ 3875 V(I32AtomicCompareExchange16U, Uint16, Word32) \ 3876 V(I64AtomicCompareExchange8U, Uint8, Word64) \ 3877 V(I64AtomicCompareExchange16U, Uint16, Word64) \ 3878 V(I64AtomicCompareExchange32U, Uint32, Word64) 3879 3880 #define ATOMIC_LOAD_LIST(V) \ 3881 V(I32AtomicLoad, Uint32, Word32) \ 3882 V(I64AtomicLoad, Uint64, Word64) \ 3883 V(I32AtomicLoad8U, Uint8, Word32) \ 3884 V(I32AtomicLoad16U, Uint16, Word32) \ 3885 V(I64AtomicLoad8U, Uint8, Word64) \ 3886 V(I64AtomicLoad16U, Uint16, Word64) \ 3887 V(I64AtomicLoad32U, Uint32, Word64) 3888 3889 #define ATOMIC_STORE_LIST(V) \ 3890 V(I32AtomicStore, Uint32, kWord32, Word32) \ 3891 V(I64AtomicStore, Uint64, kWord64, Word64) \ 3892 V(I32AtomicStore8U, Uint8, kWord8, Word32) \ 3893 V(I32AtomicStore16U, Uint16, kWord16, Word32) \ 3894 V(I64AtomicStore8U, Uint8, kWord8, Word64) \ 3895 V(I64AtomicStore16U, Uint16, kWord16, Word64) \ 3896 V(I64AtomicStore32U, Uint32, kWord32, Word64) 3897 3898 Node* WasmGraphBuilder::AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs, 3899 uint32_t alignment, uint32_t offset, 3900 wasm::WasmCodePosition position) { 3901 Node* node; 3902 switch (opcode) { 3903 #define BUILD_ATOMIC_BINOP(Name, Operation, Type, Prefix) \ 3904 case wasm::kExpr##Name: { \ 3905 Node* index = CheckBoundsAndAlignment( \ 3906 wasm::ValueTypes::MemSize(MachineType::Type()), inputs[0], offset, \ 3907 position); \ 3908 node = graph()->NewNode( \ 3909 mcgraph()->machine()->Prefix##Atomic##Operation(MachineType::Type()), \ 3910 MemBuffer(offset), index, inputs[1], Effect(), Control()); \ 3911 break; \ 3912 } 3913 ATOMIC_BINOP_LIST(BUILD_ATOMIC_BINOP) 3914 #undef BUILD_ATOMIC_BINOP 3915 3916 #define BUILD_ATOMIC_CMP_EXCHG(Name, Type, Prefix) \ 3917 case wasm::kExpr##Name: { \ 3918 Node* index = CheckBoundsAndAlignment( \ 3919 wasm::ValueTypes::MemSize(MachineType::Type()), inputs[0], offset, \ 3920 position); \ 3921 node = graph()->NewNode( \ 3922 mcgraph()->machine()->Prefix##AtomicCompareExchange( \ 3923 MachineType::Type()), \ 3924 MemBuffer(offset), index, inputs[1], inputs[2], Effect(), Control()); \ 3925 break; \ 3926 } 3927 ATOMIC_CMP_EXCHG_LIST(BUILD_ATOMIC_CMP_EXCHG) 3928 #undef BUILD_ATOMIC_CMP_EXCHG 3929 3930 #define BUILD_ATOMIC_LOAD_OP(Name, Type, Prefix) \ 3931 case wasm::kExpr##Name: { \ 3932 Node* index = CheckBoundsAndAlignment( \ 3933 wasm::ValueTypes::MemSize(MachineType::Type()), inputs[0], offset, \ 3934 position); \ 3935 node = graph()->NewNode( \ 3936 mcgraph()->machine()->Prefix##AtomicLoad(MachineType::Type()), \ 3937 MemBuffer(offset), index, Effect(), Control()); \ 3938 break; \ 3939 } 3940 ATOMIC_LOAD_LIST(BUILD_ATOMIC_LOAD_OP) 3941 #undef BUILD_ATOMIC_LOAD_OP 3942 3943 #define BUILD_ATOMIC_STORE_OP(Name, Type, Rep, Prefix) \ 3944 case wasm::kExpr##Name: { \ 3945 Node* index = CheckBoundsAndAlignment( \ 3946 wasm::ValueTypes::MemSize(MachineType::Type()), inputs[0], offset, \ 3947 position); \ 3948 node = graph()->NewNode( \ 3949 mcgraph()->machine()->Prefix##AtomicStore(MachineRepresentation::Rep), \ 3950 MemBuffer(offset), index, inputs[1], Effect(), Control()); \ 3951 break; \ 3952 } 3953 ATOMIC_STORE_LIST(BUILD_ATOMIC_STORE_OP) 3954 #undef BUILD_ATOMIC_STORE_OP 3955 default: 3956 FATAL_UNSUPPORTED_OPCODE(opcode); 3957 } 3958 return SetEffect(node); 3959 } 3960 3961 #undef ATOMIC_BINOP_LIST 3962 #undef ATOMIC_CMP_EXCHG_LIST 3963 #undef ATOMIC_LOAD_LIST 3964 #undef ATOMIC_STORE_LIST 3965 3966 class WasmDecorator final : public GraphDecorator { 3967 public: 3968 explicit WasmDecorator(NodeOriginTable* origins, wasm::Decoder* decoder) 3969 : origins_(origins), decoder_(decoder) {} 3970 3971 void Decorate(Node* node) final { 3972 origins_->SetNodeOrigin( 3973 node, NodeOrigin("wasm graph creation", "n/a", 3974 NodeOrigin::kWasmBytecode, decoder_->position())); 3975 } 3976 3977 private: 3978 compiler::NodeOriginTable* origins_; 3979 wasm::Decoder* decoder_; 3980 }; 3981 3982 void WasmGraphBuilder::AddBytecodePositionDecorator( 3983 NodeOriginTable* node_origins, wasm::Decoder* decoder) { 3984 DCHECK_NULL(decorator_); 3985 decorator_ = new (graph()->zone()) WasmDecorator(node_origins, decoder); 3986 graph()->AddDecorator(decorator_); 3987 } 3988 3989 void WasmGraphBuilder::RemoveBytecodePositionDecorator() { 3990 DCHECK_NOT_NULL(decorator_); 3991 graph()->RemoveDecorator(decorator_); 3992 decorator_ = nullptr; 3993 } 3994 3995 namespace { 3996 bool must_record_function_compilation(Isolate* isolate) { 3997 return isolate->logger()->is_listening_to_code_events() || 3998 isolate->is_profiling(); 3999 } 4000 4001 PRINTF_FORMAT(4, 5) 4002 void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, 4003 Isolate* isolate, Handle<Code> code, 4004 const char* format, ...) { 4005 DCHECK(must_record_function_compilation(isolate)); 4006 4007 ScopedVector<char> buffer(128); 4008 va_list arguments; 4009 va_start(arguments, format); 4010 int len = VSNPrintF(buffer, format, arguments); 4011 CHECK_LT(0, len); 4012 va_end(arguments); 4013 Handle<String> name_str = 4014 isolate->factory()->NewStringFromAsciiChecked(buffer.start()); 4015 PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *name_str)); 4016 } 4017 4018 class WasmWrapperGraphBuilder : public WasmGraphBuilder { 4019 public: 4020 WasmWrapperGraphBuilder(Zone* zone, wasm::ModuleEnv* env, JSGraph* jsgraph, 4021 wasm::FunctionSig* sig, 4022 compiler::SourcePositionTable* spt, 4023 StubCallMode stub_mode) 4024 : WasmGraphBuilder(env, zone, jsgraph, sig, spt), 4025 isolate_(jsgraph->isolate()), 4026 jsgraph_(jsgraph), 4027 stub_mode_(stub_mode) {} 4028 4029 Node* BuildAllocateHeapNumberWithValue(Node* value, Node* control) { 4030 MachineOperatorBuilder* machine = mcgraph()->machine(); 4031 CommonOperatorBuilder* common = mcgraph()->common(); 4032 Node* target = (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) 4033 ? mcgraph()->RelocatableIntPtrConstant( 4034 wasm::WasmCode::kWasmAllocateHeapNumber, 4035 RelocInfo::WASM_STUB_CALL) 4036 : jsgraph()->HeapConstant( 4037 BUILTIN_CODE(isolate_, AllocateHeapNumber)); 4038 if (!allocate_heap_number_operator_.is_set()) { 4039 auto call_descriptor = Linkage::GetStubCallDescriptor( 4040 mcgraph()->zone(), AllocateHeapNumberDescriptor(), 0, 4041 CallDescriptor::kNoFlags, Operator::kNoThrow, stub_mode_); 4042 allocate_heap_number_operator_.set(common->Call(call_descriptor)); 4043 } 4044 Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(), 4045 target, Effect(), control); 4046 SetEffect( 4047 graph()->NewNode(machine->Store(StoreRepresentation( 4048 MachineRepresentation::kFloat64, kNoWriteBarrier)), 4049 heap_number, BuildHeapNumberValueIndexConstant(), 4050 value, heap_number, control)); 4051 return heap_number; 4052 } 4053 4054 Node* BuildChangeSmiToFloat64(Node* value) { 4055 return graph()->NewNode(mcgraph()->machine()->ChangeInt32ToFloat64(), 4056 BuildChangeSmiToInt32(value)); 4057 } 4058 4059 Node* BuildTestHeapObject(Node* value) { 4060 return graph()->NewNode(mcgraph()->machine()->WordAnd(), value, 4061 mcgraph()->IntPtrConstant(kHeapObjectTag)); 4062 } 4063 4064 Node* BuildLoadHeapNumberValue(Node* value) { 4065 return SetEffect(graph()->NewNode( 4066 mcgraph()->machine()->Load(MachineType::Float64()), value, 4067 BuildHeapNumberValueIndexConstant(), Effect(), Control())); 4068 } 4069 4070 Node* BuildHeapNumberValueIndexConstant() { 4071 return mcgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag); 4072 } 4073 4074 Node* BuildChangeInt32ToTagged(Node* value) { 4075 MachineOperatorBuilder* machine = mcgraph()->machine(); 4076 CommonOperatorBuilder* common = mcgraph()->common(); 4077 4078 if (SmiValuesAre32Bits()) { 4079 return BuildChangeInt32ToSmi(value); 4080 } 4081 DCHECK(SmiValuesAre31Bits()); 4082 4083 Node* effect = Effect(); 4084 Node* control = Control(); 4085 Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value, 4086 graph()->start()); 4087 4088 Node* ovf = graph()->NewNode(common->Projection(1), add, graph()->start()); 4089 Node* branch = 4090 graph()->NewNode(common->Branch(BranchHint::kFalse), ovf, control); 4091 4092 Node* if_true = graph()->NewNode(common->IfTrue(), branch); 4093 Node* vtrue = BuildAllocateHeapNumberWithValue( 4094 graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true); 4095 Node* etrue = Effect(); 4096 4097 Node* if_false = graph()->NewNode(common->IfFalse(), branch); 4098 Node* vfalse = graph()->NewNode(common->Projection(0), add, if_false); 4099 vfalse = BuildChangeInt32ToIntPtr(vfalse); 4100 4101 Node* merge = 4102 SetControl(graph()->NewNode(common->Merge(2), if_true, if_false)); 4103 SetEffect(graph()->NewNode(common->EffectPhi(2), etrue, effect, merge)); 4104 return graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), 4105 vtrue, vfalse, merge); 4106 } 4107 4108 Node* BuildChangeFloat64ToTagged(Node* value) { 4109 MachineOperatorBuilder* machine = mcgraph()->machine(); 4110 CommonOperatorBuilder* common = mcgraph()->common(); 4111 4112 // Check several conditions: 4113 // i32? 4114 // true: zero? 4115 // true: negative? 4116 // true: box 4117 // false: potentially Smi 4118 // false: potentially Smi 4119 // false: box 4120 // For potential Smi values, depending on whether Smis are 31 or 32 bit, we 4121 // still need to check whether the value fits in a Smi. 4122 4123 Node* effect = Effect(); 4124 Node* control = Control(); 4125 Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value); 4126 Node* check_i32 = graph()->NewNode( 4127 machine->Float64Equal(), value, 4128 graph()->NewNode(machine->ChangeInt32ToFloat64(), value32)); 4129 Node* branch_i32 = graph()->NewNode(common->Branch(), check_i32, control); 4130 4131 Node* if_i32 = graph()->NewNode(common->IfTrue(), branch_i32); 4132 Node* if_not_i32 = graph()->NewNode(common->IfFalse(), branch_i32); 4133 4134 // We only need to check for -0 if the {value} can potentially contain -0. 4135 Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32, 4136 mcgraph()->Int32Constant(0)); 4137 Node* branch_zero = graph()->NewNode(common->Branch(BranchHint::kFalse), 4138 check_zero, if_i32); 4139 4140 Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero); 4141 Node* if_not_zero = graph()->NewNode(common->IfFalse(), branch_zero); 4142 4143 // In case of 0, we need to check the high bits for the IEEE -0 pattern. 4144 Node* check_negative = graph()->NewNode( 4145 machine->Int32LessThan(), 4146 graph()->NewNode(machine->Float64ExtractHighWord32(), value), 4147 mcgraph()->Int32Constant(0)); 4148 Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse), 4149 check_negative, if_zero); 4150 4151 Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative); 4152 Node* if_not_negative = 4153 graph()->NewNode(common->IfFalse(), branch_negative); 4154 4155 // We need to create a box for negative 0. 4156 Node* if_smi = 4157 graph()->NewNode(common->Merge(2), if_not_zero, if_not_negative); 4158 Node* if_box = graph()->NewNode(common->Merge(2), if_not_i32, if_negative); 4159 4160 // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 4161 // 32-bit machines we need to deal with potential overflow and fallback to 4162 // boxing. 4163 Node* vsmi; 4164 if (SmiValuesAre32Bits()) { 4165 vsmi = BuildChangeInt32ToSmi(value32); 4166 } else { 4167 DCHECK(SmiValuesAre31Bits()); 4168 Node* smi_tag = graph()->NewNode(machine->Int32AddWithOverflow(), value32, 4169 value32, if_smi); 4170 4171 Node* check_ovf = 4172 graph()->NewNode(common->Projection(1), smi_tag, if_smi); 4173 Node* branch_ovf = graph()->NewNode(common->Branch(BranchHint::kFalse), 4174 check_ovf, if_smi); 4175 4176 Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf); 4177 if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box); 4178 4179 if_smi = graph()->NewNode(common->IfFalse(), branch_ovf); 4180 vsmi = graph()->NewNode(common->Projection(0), smi_tag, if_smi); 4181 vsmi = BuildChangeInt32ToIntPtr(vsmi); 4182 } 4183 4184 // Allocate the box for the {value}. 4185 Node* vbox = BuildAllocateHeapNumberWithValue(value, if_box); 4186 Node* ebox = Effect(); 4187 4188 Node* merge = 4189 SetControl(graph()->NewNode(common->Merge(2), if_smi, if_box)); 4190 SetEffect(graph()->NewNode(common->EffectPhi(2), effect, ebox, merge)); 4191 return graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), 4192 vsmi, vbox, merge); 4193 } 4194 4195 int AddArgumentNodes(Node** args, int pos, int param_count, 4196 wasm::FunctionSig* sig) { 4197 // Convert wasm numbers to JS values. 4198 for (int i = 0; i < param_count; ++i) { 4199 Node* param = 4200 Param(i + 1); // Start from index 1 to drop the instance_node. 4201 args[pos++] = ToJS(param, sig->GetParam(i)); 4202 } 4203 return pos; 4204 } 4205 4206 Node* BuildJavaScriptToNumber(Node* node, Node* js_context) { 4207 auto call_descriptor = Linkage::GetStubCallDescriptor( 4208 mcgraph()->zone(), TypeConversionDescriptor{}, 0, 4209 CallDescriptor::kNoFlags, Operator::kNoProperties, stub_mode_); 4210 Node* stub_code = 4211 (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) 4212 ? mcgraph()->RelocatableIntPtrConstant( 4213 wasm::WasmCode::kWasmToNumber, RelocInfo::WASM_STUB_CALL) 4214 : jsgraph()->HeapConstant(BUILTIN_CODE(isolate_, ToNumber)); 4215 4216 Node* result = SetEffect( 4217 graph()->NewNode(mcgraph()->common()->Call(call_descriptor), stub_code, 4218 node, js_context, Effect(), Control())); 4219 4220 SetSourcePosition(result, 1); 4221 4222 return result; 4223 } 4224 4225 Node* BuildChangeTaggedToFloat64(Node* value) { 4226 MachineOperatorBuilder* machine = mcgraph()->machine(); 4227 CommonOperatorBuilder* common = mcgraph()->common(); 4228 4229 // Implement the following decision tree: 4230 // heap object? 4231 // true: undefined? 4232 // true: f64 const 4233 // false: load heap number value 4234 // false: smi to float64 4235 4236 Node* check_heap_object = BuildTestHeapObject(value); 4237 Diamond is_heap_object(graph(), common, check_heap_object, 4238 BranchHint::kFalse); 4239 is_heap_object.Chain(Control()); 4240 4241 SetControl(is_heap_object.if_true); 4242 Node* orig_effect = Effect(); 4243 4244 Node* undefined_node = 4245 LOAD_INSTANCE_FIELD(UndefinedValue, MachineType::TaggedPointer()); 4246 Node* check_undefined = 4247 graph()->NewNode(machine->WordEqual(), value, undefined_node); 4248 Node* effect_tagged = Effect(); 4249 4250 Diamond is_undefined(graph(), common, check_undefined, BranchHint::kFalse); 4251 is_undefined.Nest(is_heap_object, true); 4252 4253 SetControl(is_undefined.if_false); 4254 Node* vheap_number = BuildLoadHeapNumberValue(value); 4255 Node* effect_undefined = Effect(); 4256 4257 SetControl(is_undefined.merge); 4258 Node* vundefined = 4259 mcgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN()); 4260 Node* vtagged = is_undefined.Phi(MachineRepresentation::kFloat64, 4261 vundefined, vheap_number); 4262 4263 effect_tagged = is_undefined.EffectPhi(effect_tagged, effect_undefined); 4264 4265 // If input is Smi: just convert to float64. 4266 Node* vfrom_smi = BuildChangeSmiToFloat64(value); 4267 4268 SetControl(is_heap_object.merge); 4269 SetEffect(is_heap_object.EffectPhi(effect_tagged, orig_effect)); 4270 return is_heap_object.Phi(MachineRepresentation::kFloat64, vtagged, 4271 vfrom_smi); 4272 } 4273 4274 Node* ToJS(Node* node, wasm::ValueType type) { 4275 switch (type) { 4276 case wasm::kWasmI32: 4277 return BuildChangeInt32ToTagged(node); 4278 case wasm::kWasmS128: 4279 case wasm::kWasmI64: 4280 UNREACHABLE(); 4281 case wasm::kWasmF32: 4282 node = graph()->NewNode(mcgraph()->machine()->ChangeFloat32ToFloat64(), 4283 node); 4284 return BuildChangeFloat64ToTagged(node); 4285 case wasm::kWasmF64: 4286 return BuildChangeFloat64ToTagged(node); 4287 case wasm::kWasmAnyRef: 4288 return node; 4289 default: 4290 UNREACHABLE(); 4291 } 4292 } 4293 4294 Node* FromJS(Node* node, Node* js_context, wasm::ValueType type) { 4295 DCHECK_NE(wasm::kWasmStmt, type); 4296 4297 // The parameter is of type AnyRef, we take it as is. 4298 if (type == wasm::kWasmAnyRef) { 4299 return node; 4300 } 4301 4302 // Do a JavaScript ToNumber. 4303 Node* num = BuildJavaScriptToNumber(node, js_context); 4304 4305 // Change representation. 4306 num = BuildChangeTaggedToFloat64(num); 4307 4308 switch (type) { 4309 case wasm::kWasmI32: { 4310 num = graph()->NewNode(mcgraph()->machine()->TruncateFloat64ToWord32(), 4311 num); 4312 break; 4313 } 4314 case wasm::kWasmS128: 4315 case wasm::kWasmI64: 4316 UNREACHABLE(); 4317 case wasm::kWasmF32: 4318 num = graph()->NewNode(mcgraph()->machine()->TruncateFloat64ToFloat32(), 4319 num); 4320 break; 4321 case wasm::kWasmF64: 4322 break; 4323 default: 4324 UNREACHABLE(); 4325 } 4326 return num; 4327 } 4328 4329 void BuildModifyThreadInWasmFlag(bool new_value) { 4330 if (!trap_handler::IsTrapHandlerEnabled()) return; 4331 Node* thread_in_wasm_flag_address_address = 4332 graph()->NewNode(mcgraph()->common()->ExternalConstant( 4333 ExternalReference::wasm_thread_in_wasm_flag_address_address( 4334 isolate_))); 4335 Node* thread_in_wasm_flag_address = SetEffect(graph()->NewNode( 4336 mcgraph()->machine()->Load(LoadRepresentation(MachineType::Pointer())), 4337 thread_in_wasm_flag_address_address, mcgraph()->Int32Constant(0), 4338 Effect(), Control())); 4339 SetEffect(graph()->NewNode( 4340 mcgraph()->machine()->Store(StoreRepresentation( 4341 MachineRepresentation::kWord32, kNoWriteBarrier)), 4342 thread_in_wasm_flag_address, mcgraph()->Int32Constant(0), 4343 mcgraph()->Int32Constant(new_value ? 1 : 0), Effect(), Control())); 4344 } 4345 4346 Node* BuildLoadFunctionDataFromExportedFunction(Node* closure) { 4347 Node* shared = SetEffect(graph()->NewNode( 4348 jsgraph()->machine()->Load(MachineType::AnyTagged()), closure, 4349 jsgraph()->Int32Constant(JSFunction::kSharedFunctionInfoOffset - 4350 kHeapObjectTag), 4351 Effect(), Control())); 4352 return SetEffect(graph()->NewNode( 4353 jsgraph()->machine()->Load(MachineType::AnyTagged()), shared, 4354 jsgraph()->Int32Constant(SharedFunctionInfo::kFunctionDataOffset - 4355 kHeapObjectTag), 4356 Effect(), Control())); 4357 } 4358 4359 Node* BuildLoadInstanceFromExportedFunctionData(Node* function_data) { 4360 return SetEffect(graph()->NewNode( 4361 jsgraph()->machine()->Load(MachineType::AnyTagged()), function_data, 4362 jsgraph()->Int32Constant(WasmExportedFunctionData::kInstanceOffset - 4363 kHeapObjectTag), 4364 Effect(), Control())); 4365 } 4366 4367 Node* BuildLoadFunctionIndexFromExportedFunctionData(Node* function_data) { 4368 Node* function_index_smi = SetEffect(graph()->NewNode( 4369 jsgraph()->machine()->Load(MachineType::AnyTagged()), function_data, 4370 jsgraph()->Int32Constant( 4371 WasmExportedFunctionData::kFunctionIndexOffset - kHeapObjectTag), 4372 Effect(), Control())); 4373 Node* function_index = BuildChangeSmiToInt32(function_index_smi); 4374 return function_index; 4375 } 4376 4377 Node* BuildLoadJumpTableOffsetFromExportedFunctionData(Node* function_data) { 4378 Node* jump_table_offset_smi = SetEffect(graph()->NewNode( 4379 jsgraph()->machine()->Load(MachineType::AnyTagged()), function_data, 4380 jsgraph()->Int32Constant( 4381 WasmExportedFunctionData::kJumpTableOffsetOffset - kHeapObjectTag), 4382 Effect(), Control())); 4383 Node* jump_table_offset = BuildChangeSmiToInt32(jump_table_offset_smi); 4384 return jump_table_offset; 4385 } 4386 4387 void BuildJSToWasmWrapper(bool is_import) { 4388 const int wasm_count = static_cast<int>(sig_->parameter_count()); 4389 4390 // Build the start and the JS parameter nodes. 4391 SetEffect(SetControl(Start(wasm_count + 5))); 4392 4393 // Create the js_closure and js_context parameters. 4394 Node* js_closure = 4395 graph()->NewNode(jsgraph()->common()->Parameter( 4396 Linkage::kJSCallClosureParamIndex, "%closure"), 4397 graph()->start()); 4398 Node* js_context = graph()->NewNode( 4399 mcgraph()->common()->Parameter( 4400 Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"), 4401 graph()->start()); 4402 4403 // Create the instance_node node to pass as parameter. It is loaded from 4404 // an actual reference to an instance or a placeholder reference, 4405 // called {WasmExportedFunction} via the {WasmExportedFunctionData} 4406 // structure. 4407 Node* function_data = BuildLoadFunctionDataFromExportedFunction(js_closure); 4408 instance_node_.set( 4409 BuildLoadInstanceFromExportedFunctionData(function_data)); 4410 4411 if (!wasm::IsJSCompatibleSignature(sig_)) { 4412 // Throw a TypeError. Use the js_context of the calling javascript 4413 // function (passed as a parameter), such that the generated code is 4414 // js_context independent. 4415 BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, js_context, 4416 nullptr, 0); 4417 Return(jsgraph()->SmiConstant(0)); 4418 return; 4419 } 4420 4421 const int args_count = wasm_count + 1; // +1 for wasm_code. 4422 Node** args = Buffer(args_count); 4423 Node** rets; 4424 4425 // Convert JS parameters to wasm numbers. 4426 for (int i = 0; i < wasm_count; ++i) { 4427 Node* param = Param(i + 1); 4428 Node* wasm_param = FromJS(param, js_context, sig_->GetParam(i)); 4429 args[i + 1] = wasm_param; 4430 } 4431 4432 // Set the ThreadInWasm flag before we do the actual call. 4433 BuildModifyThreadInWasmFlag(true); 4434 4435 if (is_import) { 4436 // Call to an imported function. 4437 // Load function index from {WasmExportedFunctionData}. 4438 Node* function_index = 4439 BuildLoadFunctionIndexFromExportedFunctionData(function_data); 4440 BuildImportWasmCall(sig_, args, &rets, wasm::kNoCodePosition, 4441 function_index); 4442 } else { 4443 // Call to a wasm function defined in this module. 4444 // The call target is the jump table slot for that function. 4445 Node* jump_table_start = 4446 LOAD_INSTANCE_FIELD(JumpTableStart, MachineType::Pointer()); 4447 Node* jump_table_offset = 4448 BuildLoadJumpTableOffsetFromExportedFunctionData(function_data); 4449 Node* jump_table_slot = graph()->NewNode( 4450 mcgraph()->machine()->IntAdd(), jump_table_start, jump_table_offset); 4451 args[0] = jump_table_slot; 4452 4453 BuildWasmCall(sig_, args, &rets, wasm::kNoCodePosition, nullptr, 4454 kNoRetpoline); 4455 } 4456 4457 // Clear the ThreadInWasm flag. 4458 BuildModifyThreadInWasmFlag(false); 4459 4460 Node* jsval = sig_->return_count() == 0 ? jsgraph()->UndefinedConstant() 4461 : ToJS(rets[0], sig_->GetReturn()); 4462 Return(jsval); 4463 } 4464 4465 bool BuildWasmToJSWrapper(Handle<JSReceiver> target, int index) { 4466 DCHECK(target->IsCallable()); 4467 4468 int wasm_count = static_cast<int>(sig_->parameter_count()); 4469 4470 // Build the start and the parameter nodes. 4471 SetEffect(SetControl(Start(wasm_count + 3))); 4472 4473 // Create the instance_node from the passed parameter. 4474 instance_node_.set(Param(wasm::kWasmInstanceParameterIndex)); 4475 4476 Node* callables_node = LOAD_INSTANCE_FIELD(ImportedFunctionCallables, 4477 MachineType::TaggedPointer()); 4478 Node* callable_node = LOAD_FIXED_ARRAY_SLOT(callables_node, index); 4479 Node* undefined_node = 4480 LOAD_INSTANCE_FIELD(UndefinedValue, MachineType::TaggedPointer()); 4481 Node* native_context = 4482 LOAD_INSTANCE_FIELD(NativeContext, MachineType::TaggedPointer()); 4483 4484 if (!wasm::IsJSCompatibleSignature(sig_)) { 4485 // Throw a TypeError. 4486 BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, 4487 native_context, nullptr, 0); 4488 // We don't need to return a value here, as the runtime call will not 4489 // return anyway (the c entry stub will trigger stack unwinding). 4490 ReturnVoid(); 4491 return false; 4492 } 4493 4494 CallDescriptor* call_descriptor; 4495 Node** args = Buffer(wasm_count + 9); 4496 Node* call = nullptr; 4497 4498 BuildModifyThreadInWasmFlag(false); 4499 4500 if (target->IsJSFunction()) { 4501 Handle<JSFunction> function = Handle<JSFunction>::cast(target); 4502 FieldAccess field_access = AccessBuilder::ForJSFunctionContext(); 4503 Node* function_context = SetEffect(graph()->NewNode( 4504 mcgraph()->machine()->Load(MachineType::TaggedPointer()), 4505 callable_node, 4506 mcgraph()->Int32Constant(field_access.offset - field_access.tag()), 4507 Effect(), Control())); 4508 4509 if (!IsClassConstructor(function->shared()->kind())) { 4510 if (function->shared()->internal_formal_parameter_count() == 4511 wasm_count) { 4512 int pos = 0; 4513 args[pos++] = callable_node; // target callable. 4514 // Receiver. 4515 if (is_sloppy(function->shared()->language_mode()) && 4516 !function->shared()->native()) { 4517 Node* global_proxy = LOAD_FIXED_ARRAY_SLOT( 4518 native_context, Context::GLOBAL_PROXY_INDEX); 4519 args[pos++] = global_proxy; 4520 } else { 4521 args[pos++] = undefined_node; 4522 } 4523 4524 call_descriptor = Linkage::GetJSCallDescriptor( 4525 graph()->zone(), false, wasm_count + 1, CallDescriptor::kNoFlags); 4526 4527 // Convert wasm numbers to JS values. 4528 pos = AddArgumentNodes(args, pos, wasm_count, sig_); 4529 4530 args[pos++] = undefined_node; // new target 4531 args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count 4532 args[pos++] = function_context; 4533 args[pos++] = Effect(); 4534 args[pos++] = Control(); 4535 4536 call = graph()->NewNode(mcgraph()->common()->Call(call_descriptor), 4537 pos, args); 4538 } else if (function->shared()->internal_formal_parameter_count() >= 0) { 4539 int pos = 0; 4540 args[pos++] = mcgraph()->RelocatableIntPtrConstant( 4541 wasm::WasmCode::kWasmArgumentsAdaptor, RelocInfo::WASM_STUB_CALL); 4542 args[pos++] = callable_node; // target callable 4543 args[pos++] = undefined_node; // new target 4544 args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count 4545 args[pos++] = mcgraph()->Int32Constant( 4546 function->shared()->internal_formal_parameter_count()); 4547 // Receiver. 4548 if (is_sloppy(function->shared()->language_mode()) && 4549 !function->shared()->native()) { 4550 Node* global_proxy = LOAD_FIXED_ARRAY_SLOT( 4551 native_context, Context::GLOBAL_PROXY_INDEX); 4552 args[pos++] = global_proxy; 4553 } else { 4554 args[pos++] = undefined_node; 4555 } 4556 4557 call_descriptor = Linkage::GetStubCallDescriptor( 4558 mcgraph()->zone(), ArgumentAdaptorDescriptor{}, 1 + wasm_count, 4559 CallDescriptor::kNoFlags, Operator::kNoProperties, 4560 StubCallMode::kCallWasmRuntimeStub); 4561 4562 // Convert wasm numbers to JS values. 4563 pos = AddArgumentNodes(args, pos, wasm_count, sig_); 4564 args[pos++] = function_context; 4565 args[pos++] = Effect(); 4566 args[pos++] = Control(); 4567 call = graph()->NewNode(mcgraph()->common()->Call(call_descriptor), 4568 pos, args); 4569 } 4570 } 4571 } 4572 4573 // We cannot call the target directly, we have to use the Call builtin. 4574 if (!call) { 4575 int pos = 0; 4576 args[pos++] = mcgraph()->RelocatableIntPtrConstant( 4577 wasm::WasmCode::kWasmCallJavaScript, RelocInfo::WASM_STUB_CALL); 4578 args[pos++] = callable_node; 4579 args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count 4580 args[pos++] = undefined_node; // receiver 4581 4582 call_descriptor = Linkage::GetStubCallDescriptor( 4583 graph()->zone(), CallTrampolineDescriptor{}, wasm_count + 1, 4584 CallDescriptor::kNoFlags, Operator::kNoProperties, 4585 StubCallMode::kCallWasmRuntimeStub); 4586 4587 // Convert wasm numbers to JS values. 4588 pos = AddArgumentNodes(args, pos, wasm_count, sig_); 4589 4590 // The native_context is sufficient here, because all kind of callables 4591 // which depend on the context provide their own context. The context here 4592 // is only needed if the target is a constructor to throw a TypeError, if 4593 // the target is a native function, or if the target is a callable 4594 // JSObject, which can only be constructed by the runtime. 4595 args[pos++] = native_context; 4596 args[pos++] = Effect(); 4597 args[pos++] = Control(); 4598 4599 call = graph()->NewNode(mcgraph()->common()->Call(call_descriptor), pos, 4600 args); 4601 } 4602 4603 SetEffect(call); 4604 SetSourcePosition(call, 0); 4605 4606 // Convert the return value back. 4607 Node* val = sig_->return_count() == 0 4608 ? mcgraph()->Int32Constant(0) 4609 : FromJS(call, native_context, sig_->GetReturn()); 4610 4611 BuildModifyThreadInWasmFlag(true); 4612 4613 Return(val); 4614 return true; 4615 } 4616 4617 void BuildWasmInterpreterEntry(uint32_t func_index) { 4618 int param_count = static_cast<int>(sig_->parameter_count()); 4619 4620 // Build the start and the parameter nodes. 4621 SetEffect(SetControl(Start(param_count + 3))); 4622 4623 // Create the instance_node from the passed parameter. 4624 instance_node_.set(Param(wasm::kWasmInstanceParameterIndex)); 4625 4626 // Compute size for the argument buffer. 4627 int args_size_bytes = 0; 4628 for (wasm::ValueType type : sig_->parameters()) { 4629 args_size_bytes += wasm::ValueTypes::ElementSizeInBytes(type); 4630 } 4631 4632 // The return value is also passed via this buffer: 4633 DCHECK_GE(wasm::kV8MaxWasmFunctionReturns, sig_->return_count()); 4634 // TODO(wasm): Handle multi-value returns. 4635 DCHECK_EQ(1, wasm::kV8MaxWasmFunctionReturns); 4636 int return_size_bytes = 4637 sig_->return_count() == 0 4638 ? 0 4639 : wasm::ValueTypes::ElementSizeInBytes(sig_->GetReturn()); 4640 4641 // Get a stack slot for the arguments. 4642 Node* arg_buffer = 4643 args_size_bytes == 0 && return_size_bytes == 0 4644 ? mcgraph()->IntPtrConstant(0) 4645 : graph()->NewNode(mcgraph()->machine()->StackSlot( 4646 std::max(args_size_bytes, return_size_bytes), 8)); 4647 4648 // Now store all our arguments to the buffer. 4649 int offset = 0; 4650 4651 for (int i = 0; i < param_count; ++i) { 4652 wasm::ValueType type = sig_->GetParam(i); 4653 // Start from the parameter with index 1 to drop the instance_node. 4654 SetEffect(graph()->NewNode(GetSafeStoreOperator(offset, type), arg_buffer, 4655 Int32Constant(offset), Param(i + 1), Effect(), 4656 Control())); 4657 offset += wasm::ValueTypes::ElementSizeInBytes(type); 4658 } 4659 DCHECK_EQ(args_size_bytes, offset); 4660 4661 // We are passing the raw arg_buffer here. To the GC and other parts, it 4662 // looks like a Smi (lowest bit not set). In the runtime function however, 4663 // don't call Smi::value on it, but just cast it to a byte pointer. 4664 Node* parameters[] = { 4665 jsgraph()->SmiConstant(func_index), arg_buffer, 4666 }; 4667 BuildCallToRuntime(Runtime::kWasmRunInterpreter, parameters, 4668 arraysize(parameters)); 4669 4670 // Read back the return value. 4671 if (sig_->return_count() == 0) { 4672 Return(Int32Constant(0)); 4673 } else { 4674 // TODO(wasm): Implement multi-return. 4675 DCHECK_EQ(1, sig_->return_count()); 4676 MachineType load_rep = 4677 wasm::ValueTypes::MachineTypeFor(sig_->GetReturn()); 4678 Node* val = SetEffect( 4679 graph()->NewNode(mcgraph()->machine()->Load(load_rep), arg_buffer, 4680 Int32Constant(0), Effect(), Control())); 4681 Return(val); 4682 } 4683 4684 if (ContainsInt64(sig_)) LowerInt64(); 4685 } 4686 4687 void BuildCWasmEntry() { 4688 // Build the start and the JS parameter nodes. 4689 SetEffect(SetControl(Start(CWasmEntryParameters::kNumParameters + 5))); 4690 4691 // Create parameter nodes (offset by 1 for the receiver parameter). 4692 Node* foreign_code_obj = Param(CWasmEntryParameters::kCodeObject + 1); 4693 MachineOperatorBuilder* machine = mcgraph()->machine(); 4694 Node* code_obj = graph()->NewNode( 4695 machine->Load(MachineType::Pointer()), foreign_code_obj, 4696 Int32Constant(Foreign::kForeignAddressOffset - kHeapObjectTag), 4697 Effect(), Control()); 4698 Node* instance_node = Param(CWasmEntryParameters::kWasmInstance + 1); 4699 Node* arg_buffer = Param(CWasmEntryParameters::kArgumentsBuffer + 1); 4700 4701 int wasm_arg_count = static_cast<int>(sig_->parameter_count()); 4702 int arg_count = wasm_arg_count + 4; // code, instance_node, control, effect 4703 Node** args = Buffer(arg_count); 4704 4705 int pos = 0; 4706 args[pos++] = code_obj; 4707 args[pos++] = instance_node; 4708 4709 int offset = 0; 4710 for (wasm::ValueType type : sig_->parameters()) { 4711 Node* arg_load = SetEffect( 4712 graph()->NewNode(GetSafeLoadOperator(offset, type), arg_buffer, 4713 Int32Constant(offset), Effect(), Control())); 4714 args[pos++] = arg_load; 4715 offset += wasm::ValueTypes::ElementSizeInBytes(type); 4716 } 4717 4718 args[pos++] = Effect(); 4719 args[pos++] = Control(); 4720 DCHECK_EQ(arg_count, pos); 4721 4722 // Call the wasm code. 4723 auto call_descriptor = GetWasmCallDescriptor(mcgraph()->zone(), sig_); 4724 4725 Node* call = SetEffect(graph()->NewNode( 4726 mcgraph()->common()->Call(call_descriptor), arg_count, args)); 4727 4728 // Store the return value. 4729 DCHECK_GE(1, sig_->return_count()); 4730 if (sig_->return_count() == 1) { 4731 StoreRepresentation store_rep( 4732 wasm::ValueTypes::MachineRepresentationFor(sig_->GetReturn()), 4733 kNoWriteBarrier); 4734 SetEffect(graph()->NewNode(mcgraph()->machine()->Store(store_rep), 4735 arg_buffer, Int32Constant(0), call, Effect(), 4736 Control())); 4737 } 4738 Return(jsgraph()->SmiConstant(0)); 4739 4740 if (mcgraph()->machine()->Is32() && ContainsInt64(sig_)) { 4741 MachineRepresentation sig_reps[] = { 4742 MachineRepresentation::kWord32, // return value 4743 MachineRepresentation::kTagged, // receiver 4744 MachineRepresentation::kTagged, // arg0 (code) 4745 MachineRepresentation::kTagged // arg1 (buffer) 4746 }; 4747 Signature<MachineRepresentation> c_entry_sig(1, 2, sig_reps); 4748 Int64Lowering r(mcgraph()->graph(), mcgraph()->machine(), 4749 mcgraph()->common(), mcgraph()->zone(), &c_entry_sig); 4750 r.LowerGraph(); 4751 } 4752 } 4753 4754 JSGraph* jsgraph() { return jsgraph_; } 4755 4756 private: 4757 Isolate* const isolate_; 4758 JSGraph* jsgraph_; 4759 StubCallMode stub_mode_; 4760 SetOncePointer<const Operator> allocate_heap_number_operator_; 4761 }; 4762 } // namespace 4763 4764 MaybeHandle<Code> CompileJSToWasmWrapper( 4765 Isolate* isolate, const wasm::NativeModule* native_module, 4766 wasm::FunctionSig* sig, bool is_import, 4767 wasm::UseTrapHandler use_trap_handler) { 4768 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), 4769 "CompileJSToWasmWrapper"); 4770 const wasm::WasmModule* module = native_module->module(); 4771 4772 //---------------------------------------------------------------------------- 4773 // Create the Graph. 4774 //---------------------------------------------------------------------------- 4775 Zone zone(isolate->allocator(), ZONE_NAME); 4776 Graph graph(&zone); 4777 CommonOperatorBuilder common(&zone); 4778 MachineOperatorBuilder machine( 4779 &zone, MachineType::PointerRepresentation(), 4780 InstructionSelector::SupportedMachineOperatorFlags(), 4781 InstructionSelector::AlignmentRequirements()); 4782 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); 4783 4784 Node* control = nullptr; 4785 Node* effect = nullptr; 4786 4787 wasm::ModuleEnv env(module, use_trap_handler, wasm::kRuntimeExceptionSupport); 4788 WasmWrapperGraphBuilder builder(&zone, &env, &jsgraph, sig, nullptr, 4789 StubCallMode::kCallOnHeapBuiltin); 4790 builder.set_control_ptr(&control); 4791 builder.set_effect_ptr(&effect); 4792 builder.BuildJSToWasmWrapper(is_import); 4793 4794 //---------------------------------------------------------------------------- 4795 // Run the compilation pipeline. 4796 //---------------------------------------------------------------------------- 4797 #ifdef DEBUG 4798 EmbeddedVector<char, 32> func_name; 4799 static unsigned id = 0; 4800 func_name.Truncate(SNPrintF(func_name, "js-to-wasm#%d", id++)); 4801 #else 4802 Vector<const char> func_name = CStrVector("js-to-wasm"); 4803 #endif 4804 4805 OptimizedCompilationInfo info(func_name, &zone, Code::JS_TO_WASM_FUNCTION); 4806 4807 if (info.trace_turbo_graph_enabled()) { // Simple textual RPO. 4808 StdoutStream{} << "-- Graph after change lowering -- " << std::endl 4809 << AsRPO(graph); 4810 } 4811 4812 // Schedule and compile to machine code. 4813 int params = static_cast<int>(sig->parameter_count()); 4814 CallDescriptor* incoming = Linkage::GetJSCallDescriptor( 4815 &zone, false, params + 1, CallDescriptor::kNoFlags); 4816 4817 MaybeHandle<Code> maybe_code = Pipeline::GenerateCodeForTesting( 4818 &info, isolate, incoming, &graph, WasmAssemblerOptions()); 4819 Handle<Code> code; 4820 if (!maybe_code.ToHandle(&code)) { 4821 return maybe_code; 4822 } 4823 #ifdef ENABLE_DISASSEMBLER 4824 if (FLAG_print_opt_code) { 4825 CodeTracer::Scope tracing_scope(isolate->GetCodeTracer()); 4826 OFStream os(tracing_scope.file()); 4827 code->Disassemble(func_name.start(), os); 4828 } 4829 #endif 4830 4831 if (must_record_function_compilation(isolate)) { 4832 RecordFunctionCompilation(CodeEventListener::STUB_TAG, isolate, code, 4833 "%.*s", func_name.length(), func_name.start()); 4834 } 4835 4836 return code; 4837 } 4838 4839 MaybeHandle<Code> CompileWasmToJSWrapper( 4840 Isolate* isolate, Handle<JSReceiver> target, wasm::FunctionSig* sig, 4841 uint32_t index, wasm::ModuleOrigin origin, 4842 wasm::UseTrapHandler use_trap_handler) { 4843 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), 4844 "CompileWasmToJSWrapper"); 4845 //---------------------------------------------------------------------------- 4846 // Create the Graph 4847 //---------------------------------------------------------------------------- 4848 Zone zone(isolate->allocator(), ZONE_NAME); 4849 Graph graph(&zone); 4850 CommonOperatorBuilder common(&zone); 4851 MachineOperatorBuilder machine( 4852 &zone, MachineType::PointerRepresentation(), 4853 InstructionSelector::SupportedMachineOperatorFlags(), 4854 InstructionSelector::AlignmentRequirements()); 4855 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); 4856 4857 Node* control = nullptr; 4858 Node* effect = nullptr; 4859 4860 SourcePositionTable* source_position_table = 4861 origin == wasm::kAsmJsOrigin ? new (&zone) SourcePositionTable(&graph) 4862 : nullptr; 4863 4864 wasm::ModuleEnv env(nullptr, use_trap_handler, 4865 wasm::kRuntimeExceptionSupport); 4866 4867 WasmWrapperGraphBuilder builder(&zone, &env, &jsgraph, sig, 4868 source_position_table, 4869 StubCallMode::kCallWasmRuntimeStub); 4870 builder.set_control_ptr(&control); 4871 builder.set_effect_ptr(&effect); 4872 builder.BuildWasmToJSWrapper(target, index); 4873 4874 #ifdef DEBUG 4875 EmbeddedVector<char, 32> func_name; 4876 static unsigned id = 0; 4877 func_name.Truncate(SNPrintF(func_name, "wasm-to-js#%d", id++)); 4878 #else 4879 Vector<const char> func_name = CStrVector("wasm-to-js"); 4880 #endif 4881 4882 OptimizedCompilationInfo info(func_name, &zone, Code::WASM_TO_JS_FUNCTION); 4883 4884 if (info.trace_turbo_graph_enabled()) { // Simple textual RPO. 4885 StdoutStream{} << "-- Graph after change lowering -- " << std::endl 4886 << AsRPO(graph); 4887 } 4888 4889 // Schedule and compile to machine code. 4890 CallDescriptor* incoming = GetWasmCallDescriptor(&zone, sig); 4891 if (machine.Is32()) { 4892 incoming = GetI32WasmCallDescriptor(&zone, incoming); 4893 } 4894 MaybeHandle<Code> maybe_code = Pipeline::GenerateCodeForTesting( 4895 &info, isolate, incoming, &graph, AssemblerOptions::Default(isolate), 4896 nullptr, source_position_table); 4897 Handle<Code> code; 4898 if (!maybe_code.ToHandle(&code)) { 4899 return maybe_code; 4900 } 4901 #ifdef ENABLE_DISASSEMBLER 4902 if (FLAG_print_opt_code) { 4903 CodeTracer::Scope tracing_scope(isolate->GetCodeTracer()); 4904 OFStream os(tracing_scope.file()); 4905 code->Disassemble(func_name.start(), os); 4906 } 4907 #endif 4908 4909 if (must_record_function_compilation(isolate)) { 4910 RecordFunctionCompilation(CodeEventListener::STUB_TAG, isolate, code, 4911 "%.*s", func_name.length(), func_name.start()); 4912 } 4913 4914 return code; 4915 } 4916 4917 MaybeHandle<Code> CompileWasmInterpreterEntry(Isolate* isolate, 4918 uint32_t func_index, 4919 wasm::FunctionSig* sig) { 4920 //---------------------------------------------------------------------------- 4921 // Create the Graph 4922 //---------------------------------------------------------------------------- 4923 Zone zone(isolate->allocator(), ZONE_NAME); 4924 Graph graph(&zone); 4925 CommonOperatorBuilder common(&zone); 4926 MachineOperatorBuilder machine( 4927 &zone, MachineType::PointerRepresentation(), 4928 InstructionSelector::SupportedMachineOperatorFlags(), 4929 InstructionSelector::AlignmentRequirements()); 4930 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); 4931 4932 Node* control = nullptr; 4933 Node* effect = nullptr; 4934 4935 WasmWrapperGraphBuilder builder(&zone, nullptr, &jsgraph, sig, nullptr, 4936 StubCallMode::kCallWasmRuntimeStub); 4937 builder.set_control_ptr(&control); 4938 builder.set_effect_ptr(&effect); 4939 builder.BuildWasmInterpreterEntry(func_index); 4940 4941 // Schedule and compile to machine code. 4942 CallDescriptor* incoming = GetWasmCallDescriptor(&zone, sig); 4943 if (machine.Is32()) { 4944 incoming = GetI32WasmCallDescriptor(&zone, incoming); 4945 } 4946 #ifdef DEBUG 4947 EmbeddedVector<char, 32> func_name; 4948 func_name.Truncate( 4949 SNPrintF(func_name, "wasm-interpreter-entry#%d", func_index)); 4950 #else 4951 Vector<const char> func_name = CStrVector("wasm-interpreter-entry"); 4952 #endif 4953 4954 OptimizedCompilationInfo info(func_name, &zone, Code::WASM_INTERPRETER_ENTRY); 4955 4956 if (info.trace_turbo_graph_enabled()) { // Simple textual RPO. 4957 StdoutStream{} << "-- Wasm interpreter entry graph -- " << std::endl 4958 << AsRPO(graph); 4959 } 4960 4961 MaybeHandle<Code> maybe_code = Pipeline::GenerateCodeForTesting( 4962 &info, isolate, incoming, &graph, AssemblerOptions::Default(isolate), 4963 nullptr); 4964 Handle<Code> code; 4965 if (!maybe_code.ToHandle(&code)) { 4966 return maybe_code; 4967 } 4968 #ifdef ENABLE_DISASSEMBLER 4969 if (FLAG_print_opt_code) { 4970 CodeTracer::Scope tracing_scope(isolate->GetCodeTracer()); 4971 OFStream os(tracing_scope.file()); 4972 code->Disassemble(func_name.start(), os); 4973 } 4974 #endif 4975 4976 if (must_record_function_compilation(isolate)) { 4977 RecordFunctionCompilation(CodeEventListener::STUB_TAG, isolate, code, 4978 "%.*s", func_name.length(), func_name.start()); 4979 } 4980 4981 return maybe_code; 4982 } 4983 4984 MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) { 4985 Zone zone(isolate->allocator(), ZONE_NAME); 4986 Graph graph(&zone); 4987 CommonOperatorBuilder common(&zone); 4988 MachineOperatorBuilder machine( 4989 &zone, MachineType::PointerRepresentation(), 4990 InstructionSelector::SupportedMachineOperatorFlags(), 4991 InstructionSelector::AlignmentRequirements()); 4992 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); 4993 4994 Node* control = nullptr; 4995 Node* effect = nullptr; 4996 4997 WasmWrapperGraphBuilder builder(&zone, nullptr, &jsgraph, sig, nullptr, 4998 StubCallMode::kCallOnHeapBuiltin); 4999 builder.set_control_ptr(&control); 5000 builder.set_effect_ptr(&effect); 5001 builder.BuildCWasmEntry(); 5002 5003 // Schedule and compile to machine code. 5004 CallDescriptor* incoming = Linkage::GetJSCallDescriptor( 5005 &zone, false, CWasmEntryParameters::kNumParameters + 1, 5006 CallDescriptor::kNoFlags); 5007 5008 // Build a name in the form "c-wasm-entry:<params>:<returns>". 5009 static constexpr size_t kMaxNameLen = 128; 5010 char debug_name[kMaxNameLen] = "c-wasm-entry:"; 5011 size_t name_len = strlen(debug_name); 5012 auto append_name_char = [&](char c) { 5013 if (name_len + 1 < kMaxNameLen) debug_name[name_len++] = c; 5014 }; 5015 for (wasm::ValueType t : sig->parameters()) { 5016 append_name_char(wasm::ValueTypes::ShortNameOf(t)); 5017 } 5018 append_name_char(':'); 5019 for (wasm::ValueType t : sig->returns()) { 5020 append_name_char(wasm::ValueTypes::ShortNameOf(t)); 5021 } 5022 debug_name[name_len] = '\0'; 5023 Vector<const char> debug_name_vec(debug_name, name_len); 5024 5025 OptimizedCompilationInfo info(debug_name_vec, &zone, Code::C_WASM_ENTRY); 5026 5027 if (info.trace_turbo_graph_enabled()) { // Simple textual RPO. 5028 StdoutStream{} << "-- C Wasm entry graph -- " << std::endl << AsRPO(graph); 5029 } 5030 5031 MaybeHandle<Code> maybe_code = Pipeline::GenerateCodeForTesting( 5032 &info, isolate, incoming, &graph, AssemblerOptions::Default(isolate)); 5033 Handle<Code> code; 5034 if (!maybe_code.ToHandle(&code)) { 5035 return maybe_code; 5036 } 5037 #ifdef ENABLE_DISASSEMBLER 5038 if (FLAG_print_opt_code) { 5039 CodeTracer::Scope tracing_scope(isolate->GetCodeTracer()); 5040 OFStream os(tracing_scope.file()); 5041 code->Disassemble(debug_name, os); 5042 } 5043 #endif 5044 5045 return code; 5046 } 5047 5048 TurbofanWasmCompilationUnit::TurbofanWasmCompilationUnit( 5049 wasm::WasmCompilationUnit* wasm_unit) 5050 : wasm_unit_(wasm_unit) {} 5051 5052 // Clears unique_ptrs, but (part of) the type is forward declared in the header. 5053 TurbofanWasmCompilationUnit::~TurbofanWasmCompilationUnit() = default; 5054 5055 SourcePositionTable* TurbofanWasmCompilationUnit::BuildGraphForWasmFunction( 5056 wasm::WasmFeatures* detected, double* decode_ms, MachineGraph* mcgraph, 5057 NodeOriginTable* node_origins) { 5058 base::ElapsedTimer decode_timer; 5059 if (FLAG_trace_wasm_decode_time) { 5060 decode_timer.Start(); 5061 } 5062 5063 // Create a TF graph during decoding. 5064 SourcePositionTable* source_position_table = 5065 new (mcgraph->zone()) SourcePositionTable(mcgraph->graph()); 5066 WasmGraphBuilder builder(wasm_unit_->env_, mcgraph->zone(), mcgraph, 5067 wasm_unit_->func_body_.sig, source_position_table); 5068 graph_construction_result_ = wasm::BuildTFGraph( 5069 wasm_unit_->wasm_engine_->allocator(), 5070 wasm_unit_->native_module_->enabled_features(), wasm_unit_->env_->module, 5071 &builder, detected, wasm_unit_->func_body_, node_origins); 5072 if (graph_construction_result_.failed()) { 5073 if (FLAG_trace_wasm_compiler) { 5074 StdoutStream{} << "Compilation failed: " 5075 << graph_construction_result_.error_msg() << std::endl; 5076 } 5077 return nullptr; 5078 } 5079 5080 builder.LowerInt64(); 5081 5082 if (builder.has_simd() && 5083 (!CpuFeatures::SupportsWasmSimd128() || wasm_unit_->env_->lower_simd)) { 5084 SimdScalarLowering( 5085 mcgraph, 5086 CreateMachineSignature(mcgraph->zone(), wasm_unit_->func_body_.sig)) 5087 .LowerGraph(); 5088 } 5089 5090 if (wasm_unit_->func_index_ >= FLAG_trace_wasm_ast_start && 5091 wasm_unit_->func_index_ < FLAG_trace_wasm_ast_end) { 5092 PrintRawWasmCode(wasm_unit_->wasm_engine_->allocator(), 5093 wasm_unit_->func_body_, wasm_unit_->env_->module, 5094 wasm::kPrintLocals); 5095 } 5096 if (FLAG_trace_wasm_decode_time) { 5097 *decode_ms = decode_timer.Elapsed().InMillisecondsF(); 5098 } 5099 return source_position_table; 5100 } 5101 5102 namespace { 5103 Vector<const char> GetDebugName(Zone* zone, wasm::WasmName name, int index) { 5104 if (!name.is_empty()) { 5105 return name; 5106 } 5107 #ifdef DEBUG 5108 constexpr int kBufferLength = 15; 5109 5110 EmbeddedVector<char, kBufferLength> name_vector; 5111 int name_len = SNPrintF(name_vector, "wasm#%d", index); 5112 DCHECK(name_len > 0 && name_len < name_vector.length()); 5113 5114 char* index_name = zone->NewArray<char>(name_len); 5115 memcpy(index_name, name_vector.start(), name_len); 5116 return Vector<const char>(index_name, name_len); 5117 #else 5118 return {}; 5119 #endif 5120 } 5121 5122 } // namespace 5123 5124 void TurbofanWasmCompilationUnit::ExecuteCompilation( 5125 wasm::WasmFeatures* detected) { 5126 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), 5127 "ExecuteTurbofanCompilation"); 5128 double decode_ms = 0; 5129 size_t node_count = 0; 5130 5131 // Scope for the {graph_zone}. 5132 { 5133 Zone graph_zone(wasm_unit_->wasm_engine_->allocator(), ZONE_NAME); 5134 MachineGraph* mcgraph = new (&graph_zone) 5135 MachineGraph(new (&graph_zone) Graph(&graph_zone), 5136 new (&graph_zone) CommonOperatorBuilder(&graph_zone), 5137 new (&graph_zone) MachineOperatorBuilder( 5138 &graph_zone, MachineType::PointerRepresentation(), 5139 InstructionSelector::SupportedMachineOperatorFlags(), 5140 InstructionSelector::AlignmentRequirements())); 5141 5142 Zone compilation_zone(wasm_unit_->wasm_engine_->allocator(), ZONE_NAME); 5143 5144 OptimizedCompilationInfo info( 5145 GetDebugName(&compilation_zone, wasm_unit_->func_name_, 5146 wasm_unit_->func_index_), 5147 &compilation_zone, Code::WASM_FUNCTION); 5148 if (wasm_unit_->env_->runtime_exception_support) { 5149 info.SetWasmRuntimeExceptionSupport(); 5150 } 5151 5152 NodeOriginTable* node_origins = info.trace_turbo_json_enabled() 5153 ? new (&graph_zone) 5154 NodeOriginTable(mcgraph->graph()) 5155 : nullptr; 5156 SourcePositionTable* source_positions = 5157 BuildGraphForWasmFunction(detected, &decode_ms, mcgraph, node_origins); 5158 5159 if (graph_construction_result_.failed()) { 5160 ok_ = false; 5161 return; 5162 } 5163 5164 if (node_origins) { 5165 node_origins->AddDecorator(); 5166 } 5167 5168 base::ElapsedTimer pipeline_timer; 5169 if (FLAG_trace_wasm_decode_time) { 5170 node_count = mcgraph->graph()->NodeCount(); 5171 pipeline_timer.Start(); 5172 } 5173 5174 // Run the compiler pipeline to generate machine code. 5175 auto call_descriptor = 5176 GetWasmCallDescriptor(&compilation_zone, wasm_unit_->func_body_.sig); 5177 if (mcgraph->machine()->Is32()) { 5178 call_descriptor = 5179 GetI32WasmCallDescriptor(&compilation_zone, call_descriptor); 5180 } 5181 5182 std::unique_ptr<OptimizedCompilationJob> job( 5183 Pipeline::NewWasmCompilationJob( 5184 &info, wasm_unit_->wasm_engine_, mcgraph, call_descriptor, 5185 source_positions, node_origins, wasm_unit_->func_body_, 5186 const_cast<wasm::WasmModule*>(wasm_unit_->env_->module), 5187 wasm_unit_->native_module_, wasm_unit_->func_index_, 5188 wasm_unit_->env_->module->origin)); 5189 ok_ = job->ExecuteJob() == CompilationJob::SUCCEEDED; 5190 // TODO(bradnelson): Improve histogram handling of size_t. 5191 wasm_unit_->counters_->wasm_compile_function_peak_memory_bytes()->AddSample( 5192 static_cast<int>(mcgraph->graph()->zone()->allocation_size())); 5193 5194 if (FLAG_trace_wasm_decode_time) { 5195 double pipeline_ms = pipeline_timer.Elapsed().InMillisecondsF(); 5196 PrintF( 5197 "wasm-compilation phase 1 ok: %u bytes, %0.3f ms decode, %zu nodes, " 5198 "%0.3f ms pipeline\n", 5199 static_cast<unsigned>(wasm_unit_->func_body_.end - 5200 wasm_unit_->func_body_.start), 5201 decode_ms, node_count, pipeline_ms); 5202 } 5203 if (ok_) wasm_code_ = info.wasm_code(); 5204 } 5205 if (ok_) wasm_unit_->native_module()->PublishCode(wasm_code_); 5206 } 5207 5208 wasm::WasmCode* TurbofanWasmCompilationUnit::FinishCompilation( 5209 wasm::ErrorThrower* thrower) { 5210 if (!ok_) { 5211 if (graph_construction_result_.failed()) { 5212 // Add the function as another context for the exception. 5213 EmbeddedVector<char, 128> message; 5214 if (wasm_unit_->func_name_.start() == nullptr) { 5215 SNPrintF(message, "Compiling wasm function #%d failed", 5216 wasm_unit_->func_index_); 5217 } else { 5218 wasm::TruncatedUserString<> trunc_name(wasm_unit_->func_name_); 5219 SNPrintF(message, "Compiling wasm function #%d:%.*s failed", 5220 wasm_unit_->func_index_, trunc_name.length(), 5221 trunc_name.start()); 5222 } 5223 thrower->CompileFailed(message.start(), graph_construction_result_); 5224 } 5225 5226 return nullptr; 5227 } 5228 return wasm_code_; 5229 } 5230 5231 namespace { 5232 // Helper for allocating either an GP or FP reg, or the next stack slot. 5233 class LinkageLocationAllocator { 5234 public: 5235 template <size_t kNumGpRegs, size_t kNumFpRegs> 5236 constexpr LinkageLocationAllocator(const Register (&gp)[kNumGpRegs], 5237 const DoubleRegister (&fp)[kNumFpRegs]) 5238 : allocator_(wasm::LinkageAllocator(gp, fp)) {} 5239 5240 LinkageLocation Next(MachineRepresentation rep) { 5241 MachineType type = MachineType::TypeForRepresentation(rep); 5242 if (IsFloatingPoint(rep)) { 5243 if (allocator_.CanAllocateFP(rep)) { 5244 int reg_code = allocator_.NextFpReg(rep); 5245 return LinkageLocation::ForRegister(reg_code, type); 5246 } 5247 } else if (allocator_.CanAllocateGP()) { 5248 int reg_code = allocator_.NextGpReg(); 5249 return LinkageLocation::ForRegister(reg_code, type); 5250 } 5251 // Cannot use register; use stack slot. 5252 int index = -1 - allocator_.NextStackSlot(rep); 5253 return LinkageLocation::ForCallerFrameSlot(index, type); 5254 } 5255 5256 void SetStackOffset(int offset) { allocator_.SetStackOffset(offset); } 5257 int NumStackSlots() const { return allocator_.NumStackSlots(); } 5258 5259 private: 5260 wasm::LinkageAllocator allocator_; 5261 }; 5262 } // namespace 5263 5264 // General code uses the above configuration data. 5265 CallDescriptor* GetWasmCallDescriptor( 5266 Zone* zone, wasm::FunctionSig* fsig, 5267 WasmGraphBuilder::UseRetpoline use_retpoline) { 5268 // The '+ 1' here is to accomodate the instance object as first parameter. 5269 LocationSignature::Builder locations(zone, fsig->return_count(), 5270 fsig->parameter_count() + 1); 5271 5272 // Add register and/or stack parameter(s). 5273 LinkageLocationAllocator params(wasm::kGpParamRegisters, 5274 wasm::kFpParamRegisters); 5275 5276 // The instance object. 5277 locations.AddParam(params.Next(MachineRepresentation::kTaggedPointer)); 5278 5279 const int parameter_count = static_cast<int>(fsig->parameter_count()); 5280 for (int i = 0; i < parameter_count; i++) { 5281 MachineRepresentation param = 5282 wasm::ValueTypes::MachineRepresentationFor(fsig->GetParam(i)); 5283 auto l = params.Next(param); 5284 locations.AddParam(l); 5285 } 5286 5287 // Add return location(s). 5288 LinkageLocationAllocator rets(wasm::kGpReturnRegisters, 5289 wasm::kFpReturnRegisters); 5290 5291 int parameter_slots = params.NumStackSlots(); 5292 if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2); 5293 5294 rets.SetStackOffset(parameter_slots); 5295 5296 const int return_count = static_cast<int>(locations.return_count_); 5297 for (int i = 0; i < return_count; i++) { 5298 MachineRepresentation ret = 5299 wasm::ValueTypes::MachineRepresentationFor(fsig->GetReturn(i)); 5300 auto l = rets.Next(ret); 5301 locations.AddReturn(l); 5302 } 5303 5304 const RegList kCalleeSaveRegisters = 0; 5305 const RegList kCalleeSaveFPRegisters = 0; 5306 5307 // The target for wasm calls is always a code object. 5308 MachineType target_type = MachineType::Pointer(); 5309 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type); 5310 5311 CallDescriptor::Kind kind = CallDescriptor::kCallWasmFunction; 5312 5313 CallDescriptor::Flags flags = 5314 use_retpoline ? CallDescriptor::kRetpoline : CallDescriptor::kNoFlags; 5315 return new (zone) CallDescriptor( // -- 5316 kind, // kind 5317 target_type, // target MachineType 5318 target_loc, // target location 5319 locations.Build(), // location_sig 5320 parameter_slots, // stack_parameter_count 5321 compiler::Operator::kNoProperties, // properties 5322 kCalleeSaveRegisters, // callee-saved registers 5323 kCalleeSaveFPRegisters, // callee-saved fp regs 5324 flags, // flags 5325 "wasm-call", // debug name 5326 0, // allocatable registers 5327 rets.NumStackSlots() - parameter_slots); // stack_return_count 5328 } 5329 5330 namespace { 5331 CallDescriptor* ReplaceTypeInCallDescriptorWith( 5332 Zone* zone, CallDescriptor* call_descriptor, size_t num_replacements, 5333 MachineType input_type, MachineRepresentation output_type) { 5334 size_t parameter_count = call_descriptor->ParameterCount(); 5335 size_t return_count = call_descriptor->ReturnCount(); 5336 for (size_t i = 0; i < call_descriptor->ParameterCount(); i++) { 5337 if (call_descriptor->GetParameterType(i) == input_type) { 5338 parameter_count += num_replacements - 1; 5339 } 5340 } 5341 for (size_t i = 0; i < call_descriptor->ReturnCount(); i++) { 5342 if (call_descriptor->GetReturnType(i) == input_type) { 5343 return_count += num_replacements - 1; 5344 } 5345 } 5346 if (parameter_count == call_descriptor->ParameterCount() && 5347 return_count == call_descriptor->ReturnCount()) { 5348 return call_descriptor; 5349 } 5350 5351 LocationSignature::Builder locations(zone, return_count, parameter_count); 5352 5353 LinkageLocationAllocator params(wasm::kGpParamRegisters, 5354 wasm::kFpParamRegisters); 5355 for (size_t i = 0; i < call_descriptor->ParameterCount(); i++) { 5356 if (call_descriptor->GetParameterType(i) == input_type) { 5357 for (size_t j = 0; j < num_replacements; j++) { 5358 locations.AddParam(params.Next(output_type)); 5359 } 5360 } else { 5361 locations.AddParam( 5362 params.Next(call_descriptor->GetParameterType(i).representation())); 5363 } 5364 } 5365 5366 LinkageLocationAllocator rets(wasm::kGpReturnRegisters, 5367 wasm::kFpReturnRegisters); 5368 rets.SetStackOffset(params.NumStackSlots()); 5369 for (size_t i = 0; i < call_descriptor->ReturnCount(); i++) { 5370 if (call_descriptor->GetReturnType(i) == input_type) { 5371 for (size_t j = 0; j < num_replacements; j++) { 5372 locations.AddReturn(rets.Next(output_type)); 5373 } 5374 } else { 5375 locations.AddReturn( 5376 rets.Next(call_descriptor->GetReturnType(i).representation())); 5377 } 5378 } 5379 5380 return new (zone) CallDescriptor( // -- 5381 call_descriptor->kind(), // kind 5382 call_descriptor->GetInputType(0), // target MachineType 5383 call_descriptor->GetInputLocation(0), // target location 5384 locations.Build(), // location_sig 5385 params.NumStackSlots(), // stack_parameter_count 5386 call_descriptor->properties(), // properties 5387 call_descriptor->CalleeSavedRegisters(), // callee-saved registers 5388 call_descriptor->CalleeSavedFPRegisters(), // callee-saved fp regs 5389 call_descriptor->flags(), // flags 5390 call_descriptor->debug_name(), // debug name 5391 call_descriptor->AllocatableRegisters(), // allocatable registers 5392 rets.NumStackSlots() - params.NumStackSlots()); // stack_return_count 5393 } 5394 } // namespace 5395 5396 CallDescriptor* GetI32WasmCallDescriptor(Zone* zone, 5397 CallDescriptor* call_descriptor) { 5398 return ReplaceTypeInCallDescriptorWith(zone, call_descriptor, 2, 5399 MachineType::Int64(), 5400 MachineRepresentation::kWord32); 5401 } 5402 5403 CallDescriptor* GetI32WasmCallDescriptorForSimd( 5404 Zone* zone, CallDescriptor* call_descriptor) { 5405 return ReplaceTypeInCallDescriptorWith(zone, call_descriptor, 4, 5406 MachineType::Simd128(), 5407 MachineRepresentation::kWord32); 5408 } 5409 5410 AssemblerOptions WasmAssemblerOptions() { 5411 AssemblerOptions options; 5412 options.record_reloc_info_for_serialization = true; 5413 options.enable_root_array_delta_access = false; 5414 return options; 5415 } 5416 5417 #undef WASM_64 5418 #undef FATAL_UNSUPPORTED_OPCODE 5419 #undef WASM_INSTANCE_OBJECT_OFFSET 5420 #undef LOAD_INSTANCE_FIELD 5421 #undef LOAD_FIXED_ARRAY_SLOT 5422 5423 } // namespace compiler 5424 } // namespace internal 5425 } // namespace v8 5426