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