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