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/effect-control-linearizer.h" 6 7 #include "src/code-factory.h" 8 #include "src/compiler/access-builder.h" 9 #include "src/compiler/compiler-source-position-table.h" 10 #include "src/compiler/js-graph.h" 11 #include "src/compiler/linkage.h" 12 #include "src/compiler/node-matchers.h" 13 #include "src/compiler/node-origin-table.h" 14 #include "src/compiler/node-properties.h" 15 #include "src/compiler/node.h" 16 #include "src/compiler/schedule.h" 17 #include "src/heap/factory-inl.h" 18 19 namespace v8 { 20 namespace internal { 21 namespace compiler { 22 23 EffectControlLinearizer::EffectControlLinearizer( 24 JSGraph* js_graph, Schedule* schedule, Zone* temp_zone, 25 SourcePositionTable* source_positions, NodeOriginTable* node_origins, 26 MaskArrayIndexEnable mask_array_index) 27 : js_graph_(js_graph), 28 schedule_(schedule), 29 temp_zone_(temp_zone), 30 mask_array_index_(mask_array_index), 31 source_positions_(source_positions), 32 node_origins_(node_origins), 33 graph_assembler_(js_graph, nullptr, nullptr, temp_zone), 34 frame_state_zapper_(nullptr) {} 35 36 Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); } 37 CommonOperatorBuilder* EffectControlLinearizer::common() const { 38 return js_graph_->common(); 39 } 40 SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const { 41 return js_graph_->simplified(); 42 } 43 MachineOperatorBuilder* EffectControlLinearizer::machine() const { 44 return js_graph_->machine(); 45 } 46 47 namespace { 48 49 struct BlockEffectControlData { 50 Node* current_effect = nullptr; // New effect. 51 Node* current_control = nullptr; // New control. 52 Node* current_frame_state = nullptr; // New frame state. 53 }; 54 55 class BlockEffectControlMap { 56 public: 57 explicit BlockEffectControlMap(Zone* temp_zone) : map_(temp_zone) {} 58 59 BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) { 60 return map_[std::make_pair(from->rpo_number(), to->rpo_number())]; 61 } 62 63 const BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) const { 64 return map_.at(std::make_pair(from->rpo_number(), to->rpo_number())); 65 } 66 67 private: 68 typedef std::pair<int32_t, int32_t> Key; 69 typedef ZoneMap<Key, BlockEffectControlData> Map; 70 71 Map map_; 72 }; 73 74 // Effect phis that need to be updated after the first pass. 75 struct PendingEffectPhi { 76 Node* effect_phi; 77 BasicBlock* block; 78 79 PendingEffectPhi(Node* effect_phi, BasicBlock* block) 80 : effect_phi(effect_phi), block(block) {} 81 }; 82 83 void ConnectUnreachableToEnd(Node* effect, Node* control, JSGraph* jsgraph) { 84 Graph* graph = jsgraph->graph(); 85 CommonOperatorBuilder* common = jsgraph->common(); 86 if (effect->opcode() == IrOpcode::kDead) return; 87 if (effect->opcode() != IrOpcode::kUnreachable) { 88 effect = graph->NewNode(common->Unreachable(), effect, control); 89 } 90 Node* throw_node = graph->NewNode(common->Throw(), effect, control); 91 NodeProperties::MergeControlToEnd(graph, common, throw_node); 92 } 93 94 void UpdateEffectPhi(Node* node, BasicBlock* block, 95 BlockEffectControlMap* block_effects, JSGraph* jsgraph) { 96 // Update all inputs to an effect phi with the effects from the given 97 // block->effect map. 98 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); 99 DCHECK_EQ(static_cast<size_t>(node->op()->EffectInputCount()), 100 block->PredecessorCount()); 101 for (int i = 0; i < node->op()->EffectInputCount(); i++) { 102 Node* input = node->InputAt(i); 103 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); 104 const BlockEffectControlData& block_effect = 105 block_effects->For(predecessor, block); 106 Node* effect = block_effect.current_effect; 107 if (input != effect) { 108 node->ReplaceInput(i, effect); 109 } 110 } 111 } 112 113 void UpdateBlockControl(BasicBlock* block, 114 BlockEffectControlMap* block_effects) { 115 Node* control = block->NodeAt(0); 116 DCHECK(NodeProperties::IsControl(control)); 117 118 // Do not rewire the end node. 119 if (control->opcode() == IrOpcode::kEnd) return; 120 121 // Update all inputs to the given control node with the correct control. 122 DCHECK(control->opcode() == IrOpcode::kMerge || 123 static_cast<size_t>(control->op()->ControlInputCount()) == 124 block->PredecessorCount()); 125 if (static_cast<size_t>(control->op()->ControlInputCount()) != 126 block->PredecessorCount()) { 127 return; // We already re-wired the control inputs of this node. 128 } 129 for (int i = 0; i < control->op()->ControlInputCount(); i++) { 130 Node* input = NodeProperties::GetControlInput(control, i); 131 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); 132 const BlockEffectControlData& block_effect = 133 block_effects->For(predecessor, block); 134 if (input != block_effect.current_control) { 135 NodeProperties::ReplaceControlInput(control, block_effect.current_control, 136 i); 137 } 138 } 139 } 140 141 bool HasIncomingBackEdges(BasicBlock* block) { 142 for (BasicBlock* pred : block->predecessors()) { 143 if (pred->rpo_number() >= block->rpo_number()) { 144 return true; 145 } 146 } 147 return false; 148 } 149 150 void RemoveRenameNode(Node* node) { 151 DCHECK(IrOpcode::kFinishRegion == node->opcode() || 152 IrOpcode::kBeginRegion == node->opcode() || 153 IrOpcode::kTypeGuard == node->opcode()); 154 // Update the value/context uses to the value input of the finish node and 155 // the effect uses to the effect input. 156 for (Edge edge : node->use_edges()) { 157 DCHECK(!edge.from()->IsDead()); 158 if (NodeProperties::IsEffectEdge(edge)) { 159 edge.UpdateTo(NodeProperties::GetEffectInput(node)); 160 } else { 161 DCHECK(!NodeProperties::IsControlEdge(edge)); 162 DCHECK(!NodeProperties::IsFrameStateEdge(edge)); 163 edge.UpdateTo(node->InputAt(0)); 164 } 165 } 166 node->Kill(); 167 } 168 169 void TryCloneBranch(Node* node, BasicBlock* block, Zone* temp_zone, 170 Graph* graph, CommonOperatorBuilder* common, 171 BlockEffectControlMap* block_effects, 172 SourcePositionTable* source_positions, 173 NodeOriginTable* node_origins) { 174 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); 175 176 // This optimization is a special case of (super)block cloning. It takes an 177 // input graph as shown below and clones the Branch node for every predecessor 178 // to the Merge, essentially removing the Merge completely. This avoids 179 // materializing the bit for the Phi and may offer potential for further 180 // branch folding optimizations (i.e. because one or more inputs to the Phi is 181 // a constant). Note that there may be more Phi nodes hanging off the Merge, 182 // but we can only a certain subset of them currently (actually only Phi and 183 // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control 184 // input). 185 186 // Control1 ... ControlN 187 // ^ ^ 188 // | | Cond1 ... CondN 189 // +----+ +----+ ^ ^ 190 // | | | | 191 // | | +----+ | 192 // Merge<--+ | +------------+ 193 // ^ \|/ 194 // | Phi 195 // | | 196 // Branch----+ 197 // ^ 198 // | 199 // +-----+-----+ 200 // | | 201 // IfTrue IfFalse 202 // ^ ^ 203 // | | 204 205 // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this: 206 207 // Control1 Cond1 ... ControlN CondN 208 // ^ ^ ^ ^ 209 // \ / \ / 210 // Branch ... Branch 211 // ^ ^ 212 // | | 213 // +---+---+ +---+----+ 214 // | | | | 215 // IfTrue IfFalse ... IfTrue IfFalse 216 // ^ ^ ^ ^ 217 // | | | | 218 // +--+ +-------------+ | 219 // | | +--------------+ +--+ 220 // | | | | 221 // Merge Merge 222 // ^ ^ 223 // | | 224 225 SourcePositionTable::Scope scope(source_positions, 226 source_positions->GetSourcePosition(node)); 227 NodeOriginTable::Scope origin_scope(node_origins, "clone branch", node); 228 Node* branch = node; 229 Node* cond = NodeProperties::GetValueInput(branch, 0); 230 if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return; 231 Node* merge = NodeProperties::GetControlInput(branch); 232 if (merge->opcode() != IrOpcode::kMerge || 233 NodeProperties::GetControlInput(cond) != merge) { 234 return; 235 } 236 // Grab the IfTrue/IfFalse projections of the Branch. 237 BranchMatcher matcher(branch); 238 // Check/collect other Phi/EffectPhi nodes hanging off the Merge. 239 NodeVector phis(temp_zone); 240 for (Node* const use : merge->uses()) { 241 if (use == branch || use == cond) continue; 242 // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the 243 // Merge. Ideally, we would just clone the nodes (and everything that 244 // depends on it to some distant join point), but that requires knowledge 245 // about dominance/post-dominance. 246 if (!NodeProperties::IsPhi(use)) return; 247 for (Edge edge : use->use_edges()) { 248 // Right now we can only handle Phi/EffectPhi nodes whose uses are 249 // directly control-dependend on either the IfTrue or the IfFalse 250 // successor, because we know exactly how to update those uses. 251 if (edge.from()->op()->ControlInputCount() != 1) return; 252 Node* control = NodeProperties::GetControlInput(edge.from()); 253 if (NodeProperties::IsPhi(edge.from())) { 254 control = NodeProperties::GetControlInput(control, edge.index()); 255 } 256 if (control != matcher.IfTrue() && control != matcher.IfFalse()) return; 257 } 258 phis.push_back(use); 259 } 260 BranchHint const hint = BranchHintOf(branch->op()); 261 int const input_count = merge->op()->ControlInputCount(); 262 DCHECK_LE(1, input_count); 263 Node** const inputs = graph->zone()->NewArray<Node*>(2 * input_count); 264 Node** const merge_true_inputs = &inputs[0]; 265 Node** const merge_false_inputs = &inputs[input_count]; 266 for (int index = 0; index < input_count; ++index) { 267 Node* cond1 = NodeProperties::GetValueInput(cond, index); 268 Node* control1 = NodeProperties::GetControlInput(merge, index); 269 Node* branch1 = graph->NewNode(common->Branch(hint), cond1, control1); 270 merge_true_inputs[index] = graph->NewNode(common->IfTrue(), branch1); 271 merge_false_inputs[index] = graph->NewNode(common->IfFalse(), branch1); 272 } 273 Node* const merge_true = matcher.IfTrue(); 274 Node* const merge_false = matcher.IfFalse(); 275 merge_true->TrimInputCount(0); 276 merge_false->TrimInputCount(0); 277 for (int i = 0; i < input_count; ++i) { 278 merge_true->AppendInput(graph->zone(), merge_true_inputs[i]); 279 merge_false->AppendInput(graph->zone(), merge_false_inputs[i]); 280 } 281 DCHECK_EQ(2u, block->SuccessorCount()); 282 NodeProperties::ChangeOp(matcher.IfTrue(), common->Merge(input_count)); 283 NodeProperties::ChangeOp(matcher.IfFalse(), common->Merge(input_count)); 284 int const true_index = 285 block->SuccessorAt(0)->NodeAt(0) == matcher.IfTrue() ? 0 : 1; 286 BlockEffectControlData* true_block_data = 287 &block_effects->For(block, block->SuccessorAt(true_index)); 288 BlockEffectControlData* false_block_data = 289 &block_effects->For(block, block->SuccessorAt(true_index ^ 1)); 290 for (Node* const phi : phis) { 291 for (int index = 0; index < input_count; ++index) { 292 inputs[index] = phi->InputAt(index); 293 } 294 inputs[input_count] = merge_true; 295 Node* phi_true = graph->NewNode(phi->op(), input_count + 1, inputs); 296 inputs[input_count] = merge_false; 297 Node* phi_false = graph->NewNode(phi->op(), input_count + 1, inputs); 298 if (phi->UseCount() == 0) { 299 DCHECK_EQ(phi->opcode(), IrOpcode::kEffectPhi); 300 } else { 301 for (Edge edge : phi->use_edges()) { 302 Node* control = NodeProperties::GetControlInput(edge.from()); 303 if (NodeProperties::IsPhi(edge.from())) { 304 control = NodeProperties::GetControlInput(control, edge.index()); 305 } 306 DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse()); 307 edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false); 308 } 309 } 310 if (phi->opcode() == IrOpcode::kEffectPhi) { 311 true_block_data->current_effect = phi_true; 312 false_block_data->current_effect = phi_false; 313 } 314 phi->Kill(); 315 } 316 // Fix up IfTrue and IfFalse and kill all dead nodes. 317 if (branch == block->control_input()) { 318 true_block_data->current_control = merge_true; 319 false_block_data->current_control = merge_false; 320 } 321 branch->Kill(); 322 cond->Kill(); 323 merge->Kill(); 324 } 325 326 } // namespace 327 328 void EffectControlLinearizer::Run() { 329 BlockEffectControlMap block_effects(temp_zone()); 330 ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone()); 331 ZoneVector<BasicBlock*> pending_block_controls(temp_zone()); 332 NodeVector inputs_buffer(temp_zone()); 333 334 for (BasicBlock* block : *(schedule()->rpo_order())) { 335 size_t instr = 0; 336 337 // The control node should be the first. 338 Node* control = block->NodeAt(instr); 339 DCHECK(NodeProperties::IsControl(control)); 340 // Update the control inputs. 341 if (HasIncomingBackEdges(block)) { 342 // If there are back edges, we need to update later because we have not 343 // computed the control yet. This should only happen for loops. 344 DCHECK_EQ(IrOpcode::kLoop, control->opcode()); 345 pending_block_controls.push_back(block); 346 } else { 347 // If there are no back edges, we can update now. 348 UpdateBlockControl(block, &block_effects); 349 } 350 instr++; 351 352 // Iterate over the phis and update the effect phis. 353 Node* effect_phi = nullptr; 354 Node* terminate = nullptr; 355 for (; instr < block->NodeCount(); instr++) { 356 Node* node = block->NodeAt(instr); 357 // Only go through the phis and effect phis. 358 if (node->opcode() == IrOpcode::kEffectPhi) { 359 // There should be at most one effect phi in a block. 360 DCHECK_NULL(effect_phi); 361 // IfException blocks should not have effect phis. 362 DCHECK_NE(IrOpcode::kIfException, control->opcode()); 363 effect_phi = node; 364 } else if (node->opcode() == IrOpcode::kPhi) { 365 // Just skip phis. 366 } else if (node->opcode() == IrOpcode::kTerminate) { 367 DCHECK_NULL(terminate); 368 terminate = node; 369 } else { 370 break; 371 } 372 } 373 374 if (effect_phi) { 375 // Make sure we update the inputs to the incoming blocks' effects. 376 if (HasIncomingBackEdges(block)) { 377 // In case of loops, we do not update the effect phi immediately 378 // because the back predecessor has not been handled yet. We just 379 // record the effect phi for later processing. 380 pending_effect_phis.push_back(PendingEffectPhi(effect_phi, block)); 381 } else { 382 UpdateEffectPhi(effect_phi, block, &block_effects, jsgraph()); 383 } 384 } 385 386 Node* effect = effect_phi; 387 if (effect == nullptr) { 388 // There was no effect phi. 389 390 // Since a loop should have at least a StackCheck, only loops in 391 // unreachable code can have no effect phi. 392 DCHECK_IMPLIES( 393 HasIncomingBackEdges(block), 394 block_effects.For(block->PredecessorAt(0), block) 395 .current_effect->opcode() == IrOpcode::kUnreachable); 396 if (block == schedule()->start()) { 397 // Start block => effect is start. 398 DCHECK_EQ(graph()->start(), control); 399 effect = graph()->start(); 400 } else if (control->opcode() == IrOpcode::kEnd) { 401 // End block is just a dummy, no effect needed. 402 DCHECK_EQ(BasicBlock::kNone, block->control()); 403 DCHECK_EQ(1u, block->size()); 404 effect = nullptr; 405 } else { 406 // If all the predecessors have the same effect, we can use it as our 407 // current effect. 408 for (size_t i = 0; i < block->PredecessorCount(); ++i) { 409 const BlockEffectControlData& data = 410 block_effects.For(block->PredecessorAt(i), block); 411 if (!effect) effect = data.current_effect; 412 if (data.current_effect != effect) { 413 effect = nullptr; 414 break; 415 } 416 } 417 if (effect == nullptr) { 418 DCHECK_NE(IrOpcode::kIfException, control->opcode()); 419 // The input blocks do not have the same effect. We have 420 // to create an effect phi node. 421 inputs_buffer.clear(); 422 inputs_buffer.resize(block->PredecessorCount(), jsgraph()->Dead()); 423 inputs_buffer.push_back(control); 424 effect = graph()->NewNode( 425 common()->EffectPhi(static_cast<int>(block->PredecessorCount())), 426 static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front())); 427 // For loops, we update the effect phi node later to break cycles. 428 if (control->opcode() == IrOpcode::kLoop) { 429 pending_effect_phis.push_back(PendingEffectPhi(effect, block)); 430 } else { 431 UpdateEffectPhi(effect, block, &block_effects, jsgraph()); 432 } 433 } else if (control->opcode() == IrOpcode::kIfException) { 434 // The IfException is connected into the effect chain, so we need 435 // to update the effect here. 436 NodeProperties::ReplaceEffectInput(control, effect); 437 effect = control; 438 } 439 } 440 } 441 442 // Fixup the Terminate node. 443 if (terminate != nullptr) { 444 NodeProperties::ReplaceEffectInput(terminate, effect); 445 } 446 447 // The frame state at block entry is determined by the frame states leaving 448 // all predecessors. In case there is no frame state dominating this block, 449 // we can rely on a checkpoint being present before the next deoptimization. 450 // TODO(mstarzinger): Eventually we will need to go hunt for a frame state 451 // once deoptimizing nodes roam freely through the schedule. 452 Node* frame_state = nullptr; 453 if (block != schedule()->start()) { 454 // If all the predecessors have the same effect, we can use it 455 // as our current effect. 456 frame_state = 457 block_effects.For(block->PredecessorAt(0), block).current_frame_state; 458 for (size_t i = 1; i < block->PredecessorCount(); i++) { 459 if (block_effects.For(block->PredecessorAt(i), block) 460 .current_frame_state != frame_state) { 461 frame_state = nullptr; 462 frame_state_zapper_ = graph()->end(); 463 break; 464 } 465 } 466 } 467 468 // Process the ordinary instructions. 469 for (; instr < block->NodeCount(); instr++) { 470 Node* node = block->NodeAt(instr); 471 ProcessNode(node, &frame_state, &effect, &control); 472 } 473 474 switch (block->control()) { 475 case BasicBlock::kGoto: 476 case BasicBlock::kNone: 477 break; 478 479 case BasicBlock::kCall: 480 case BasicBlock::kTailCall: 481 case BasicBlock::kSwitch: 482 case BasicBlock::kReturn: 483 case BasicBlock::kDeoptimize: 484 case BasicBlock::kThrow: 485 ProcessNode(block->control_input(), &frame_state, &effect, &control); 486 break; 487 488 case BasicBlock::kBranch: 489 ProcessNode(block->control_input(), &frame_state, &effect, &control); 490 TryCloneBranch(block->control_input(), block, temp_zone(), graph(), 491 common(), &block_effects, source_positions_, 492 node_origins_); 493 break; 494 } 495 496 // Store the effect, control and frame state for later use. 497 for (BasicBlock* successor : block->successors()) { 498 BlockEffectControlData* data = &block_effects.For(block, successor); 499 if (data->current_effect == nullptr) { 500 data->current_effect = effect; 501 } 502 if (data->current_control == nullptr) { 503 data->current_control = control; 504 } 505 data->current_frame_state = frame_state; 506 } 507 } 508 509 for (BasicBlock* pending_block_control : pending_block_controls) { 510 UpdateBlockControl(pending_block_control, &block_effects); 511 } 512 // Update the incoming edges of the effect phis that could not be processed 513 // during the first pass (because they could have incoming back edges). 514 for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) { 515 UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, 516 &block_effects, jsgraph()); 517 } 518 } 519 520 void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state, 521 Node** effect, Node** control) { 522 SourcePositionTable::Scope scope(source_positions_, 523 source_positions_->GetSourcePosition(node)); 524 NodeOriginTable::Scope origin_scope(node_origins_, "process node", node); 525 526 // If the node needs to be wired into the effect/control chain, do this 527 // here. Pass current frame state for lowering to eager deoptimization. 528 if (TryWireInStateEffect(node, *frame_state, effect, control)) { 529 return; 530 } 531 532 // If the node has a visible effect, then there must be a checkpoint in the 533 // effect chain before we are allowed to place another eager deoptimization 534 // point. We zap the frame state to ensure this invariant is maintained. 535 if (region_observability_ == RegionObservability::kObservable && 536 !node->op()->HasProperty(Operator::kNoWrite)) { 537 *frame_state = nullptr; 538 frame_state_zapper_ = node; 539 } 540 541 // Remove the end markers of 'atomic' allocation region because the 542 // region should be wired-in now. 543 if (node->opcode() == IrOpcode::kFinishRegion) { 544 // Reset the current region observability. 545 region_observability_ = RegionObservability::kObservable; 546 // Update the value uses to the value input of the finish node and 547 // the effect uses to the effect input. 548 return RemoveRenameNode(node); 549 } 550 if (node->opcode() == IrOpcode::kBeginRegion) { 551 // Determine the observability for this region and use that for all 552 // nodes inside the region (i.e. ignore the absence of kNoWrite on 553 // StoreField and other operators). 554 DCHECK_NE(RegionObservability::kNotObservable, region_observability_); 555 region_observability_ = RegionObservabilityOf(node->op()); 556 // Update the value uses to the value input of the finish node and 557 // the effect uses to the effect input. 558 return RemoveRenameNode(node); 559 } 560 if (node->opcode() == IrOpcode::kTypeGuard) { 561 return RemoveRenameNode(node); 562 } 563 564 // Special treatment for checkpoint nodes. 565 if (node->opcode() == IrOpcode::kCheckpoint) { 566 // Unlink the check point; effect uses will be updated to the incoming 567 // effect that is passed. The frame state is preserved for lowering. 568 DCHECK_EQ(RegionObservability::kObservable, region_observability_); 569 *frame_state = NodeProperties::GetFrameStateInput(node); 570 return; 571 } 572 573 // The IfSuccess nodes should always start a basic block (and basic block 574 // start nodes are not handled in the ProcessNode method). 575 DCHECK_NE(IrOpcode::kIfSuccess, node->opcode()); 576 577 // If the node takes an effect, replace with the current one. 578 if (node->op()->EffectInputCount() > 0) { 579 DCHECK_EQ(1, node->op()->EffectInputCount()); 580 Node* input_effect = NodeProperties::GetEffectInput(node); 581 582 if (input_effect != *effect) { 583 NodeProperties::ReplaceEffectInput(node, *effect); 584 } 585 586 // If the node produces an effect, update our current effect. (However, 587 // ignore new effect chains started with ValueEffect.) 588 if (node->op()->EffectOutputCount() > 0) { 589 DCHECK_EQ(1, node->op()->EffectOutputCount()); 590 *effect = node; 591 } 592 } else { 593 // New effect chain is only started with a Start or ValueEffect node. 594 DCHECK(node->op()->EffectOutputCount() == 0 || 595 node->opcode() == IrOpcode::kStart); 596 } 597 598 // Rewire control inputs. 599 for (int i = 0; i < node->op()->ControlInputCount(); i++) { 600 NodeProperties::ReplaceControlInput(node, *control, i); 601 } 602 // Update the current control. 603 if (node->op()->ControlOutputCount() > 0) { 604 *control = node; 605 } 606 607 // Break the effect chain on {Unreachable} and reconnect to the graph end. 608 // Mark the following code for deletion by connecting to the {Dead} node. 609 if (node->opcode() == IrOpcode::kUnreachable) { 610 ConnectUnreachableToEnd(*effect, *control, jsgraph()); 611 *effect = *control = jsgraph()->Dead(); 612 } 613 } 614 615 bool EffectControlLinearizer::TryWireInStateEffect(Node* node, 616 Node* frame_state, 617 Node** effect, 618 Node** control) { 619 gasm()->Reset(*effect, *control); 620 Node* result = nullptr; 621 switch (node->opcode()) { 622 case IrOpcode::kChangeBitToTagged: 623 result = LowerChangeBitToTagged(node); 624 break; 625 case IrOpcode::kChangeInt31ToTaggedSigned: 626 result = LowerChangeInt31ToTaggedSigned(node); 627 break; 628 case IrOpcode::kChangeInt32ToTagged: 629 result = LowerChangeInt32ToTagged(node); 630 break; 631 case IrOpcode::kChangeUint32ToTagged: 632 result = LowerChangeUint32ToTagged(node); 633 break; 634 case IrOpcode::kChangeFloat64ToTagged: 635 result = LowerChangeFloat64ToTagged(node); 636 break; 637 case IrOpcode::kChangeFloat64ToTaggedPointer: 638 result = LowerChangeFloat64ToTaggedPointer(node); 639 break; 640 case IrOpcode::kChangeTaggedSignedToInt32: 641 result = LowerChangeTaggedSignedToInt32(node); 642 break; 643 case IrOpcode::kChangeTaggedToBit: 644 result = LowerChangeTaggedToBit(node); 645 break; 646 case IrOpcode::kChangeTaggedToInt32: 647 result = LowerChangeTaggedToInt32(node); 648 break; 649 case IrOpcode::kChangeTaggedToUint32: 650 result = LowerChangeTaggedToUint32(node); 651 break; 652 case IrOpcode::kChangeTaggedToFloat64: 653 result = LowerChangeTaggedToFloat64(node); 654 break; 655 case IrOpcode::kChangeTaggedToTaggedSigned: 656 result = LowerChangeTaggedToTaggedSigned(node); 657 break; 658 case IrOpcode::kTruncateTaggedToBit: 659 result = LowerTruncateTaggedToBit(node); 660 break; 661 case IrOpcode::kTruncateTaggedPointerToBit: 662 result = LowerTruncateTaggedPointerToBit(node); 663 break; 664 case IrOpcode::kTruncateTaggedToFloat64: 665 result = LowerTruncateTaggedToFloat64(node); 666 break; 667 case IrOpcode::kCheckBounds: 668 result = LowerCheckBounds(node, frame_state); 669 break; 670 case IrOpcode::kPoisonIndex: 671 result = LowerPoisonIndex(node); 672 break; 673 case IrOpcode::kCheckMaps: 674 LowerCheckMaps(node, frame_state); 675 break; 676 case IrOpcode::kCompareMaps: 677 result = LowerCompareMaps(node); 678 break; 679 case IrOpcode::kCheckNumber: 680 result = LowerCheckNumber(node, frame_state); 681 break; 682 case IrOpcode::kCheckReceiver: 683 result = LowerCheckReceiver(node, frame_state); 684 break; 685 case IrOpcode::kCheckSymbol: 686 result = LowerCheckSymbol(node, frame_state); 687 break; 688 case IrOpcode::kCheckString: 689 result = LowerCheckString(node, frame_state); 690 break; 691 case IrOpcode::kCheckInternalizedString: 692 result = LowerCheckInternalizedString(node, frame_state); 693 break; 694 case IrOpcode::kCheckIf: 695 LowerCheckIf(node, frame_state); 696 break; 697 case IrOpcode::kCheckedInt32Add: 698 result = LowerCheckedInt32Add(node, frame_state); 699 break; 700 case IrOpcode::kCheckedInt32Sub: 701 result = LowerCheckedInt32Sub(node, frame_state); 702 break; 703 case IrOpcode::kCheckedInt32Div: 704 result = LowerCheckedInt32Div(node, frame_state); 705 break; 706 case IrOpcode::kCheckedInt32Mod: 707 result = LowerCheckedInt32Mod(node, frame_state); 708 break; 709 case IrOpcode::kCheckedUint32Div: 710 result = LowerCheckedUint32Div(node, frame_state); 711 break; 712 case IrOpcode::kCheckedUint32Mod: 713 result = LowerCheckedUint32Mod(node, frame_state); 714 break; 715 case IrOpcode::kCheckedInt32Mul: 716 result = LowerCheckedInt32Mul(node, frame_state); 717 break; 718 case IrOpcode::kCheckedInt32ToTaggedSigned: 719 result = LowerCheckedInt32ToTaggedSigned(node, frame_state); 720 break; 721 case IrOpcode::kCheckedUint32ToInt32: 722 result = LowerCheckedUint32ToInt32(node, frame_state); 723 break; 724 case IrOpcode::kCheckedUint32ToTaggedSigned: 725 result = LowerCheckedUint32ToTaggedSigned(node, frame_state); 726 break; 727 case IrOpcode::kCheckedFloat64ToInt32: 728 result = LowerCheckedFloat64ToInt32(node, frame_state); 729 break; 730 case IrOpcode::kCheckedTaggedSignedToInt32: 731 if (frame_state == nullptr) { 732 FATAL("No frame state (zapped by #%d: %s)", frame_state_zapper_->id(), 733 frame_state_zapper_->op()->mnemonic()); 734 } 735 result = LowerCheckedTaggedSignedToInt32(node, frame_state); 736 break; 737 case IrOpcode::kCheckedTaggedToInt32: 738 result = LowerCheckedTaggedToInt32(node, frame_state); 739 break; 740 case IrOpcode::kCheckedTaggedToFloat64: 741 result = LowerCheckedTaggedToFloat64(node, frame_state); 742 break; 743 case IrOpcode::kCheckedTaggedToTaggedSigned: 744 result = LowerCheckedTaggedToTaggedSigned(node, frame_state); 745 break; 746 case IrOpcode::kCheckedTaggedToTaggedPointer: 747 result = LowerCheckedTaggedToTaggedPointer(node, frame_state); 748 break; 749 case IrOpcode::kTruncateTaggedToWord32: 750 result = LowerTruncateTaggedToWord32(node); 751 break; 752 case IrOpcode::kCheckedTruncateTaggedToWord32: 753 result = LowerCheckedTruncateTaggedToWord32(node, frame_state); 754 break; 755 case IrOpcode::kNumberToString: 756 result = LowerNumberToString(node); 757 break; 758 case IrOpcode::kObjectIsArrayBufferView: 759 result = LowerObjectIsArrayBufferView(node); 760 break; 761 case IrOpcode::kObjectIsBigInt: 762 result = LowerObjectIsBigInt(node); 763 break; 764 case IrOpcode::kObjectIsCallable: 765 result = LowerObjectIsCallable(node); 766 break; 767 case IrOpcode::kObjectIsConstructor: 768 result = LowerObjectIsConstructor(node); 769 break; 770 case IrOpcode::kObjectIsDetectableCallable: 771 result = LowerObjectIsDetectableCallable(node); 772 break; 773 case IrOpcode::kObjectIsMinusZero: 774 result = LowerObjectIsMinusZero(node); 775 break; 776 case IrOpcode::kObjectIsNaN: 777 result = LowerObjectIsNaN(node); 778 break; 779 case IrOpcode::kNumberIsNaN: 780 result = LowerNumberIsNaN(node); 781 break; 782 case IrOpcode::kObjectIsNonCallable: 783 result = LowerObjectIsNonCallable(node); 784 break; 785 case IrOpcode::kObjectIsNumber: 786 result = LowerObjectIsNumber(node); 787 break; 788 case IrOpcode::kObjectIsReceiver: 789 result = LowerObjectIsReceiver(node); 790 break; 791 case IrOpcode::kObjectIsSmi: 792 result = LowerObjectIsSmi(node); 793 break; 794 case IrOpcode::kObjectIsString: 795 result = LowerObjectIsString(node); 796 break; 797 case IrOpcode::kObjectIsSymbol: 798 result = LowerObjectIsSymbol(node); 799 break; 800 case IrOpcode::kObjectIsUndetectable: 801 result = LowerObjectIsUndetectable(node); 802 break; 803 case IrOpcode::kArgumentsFrame: 804 result = LowerArgumentsFrame(node); 805 break; 806 case IrOpcode::kArgumentsLength: 807 result = LowerArgumentsLength(node); 808 break; 809 case IrOpcode::kToBoolean: 810 result = LowerToBoolean(node); 811 break; 812 case IrOpcode::kTypeOf: 813 result = LowerTypeOf(node); 814 break; 815 case IrOpcode::kNewDoubleElements: 816 result = LowerNewDoubleElements(node); 817 break; 818 case IrOpcode::kNewSmiOrObjectElements: 819 result = LowerNewSmiOrObjectElements(node); 820 break; 821 case IrOpcode::kNewArgumentsElements: 822 result = LowerNewArgumentsElements(node); 823 break; 824 case IrOpcode::kNewConsString: 825 result = LowerNewConsString(node); 826 break; 827 case IrOpcode::kArrayBufferWasNeutered: 828 result = LowerArrayBufferWasNeutered(node); 829 break; 830 case IrOpcode::kSameValue: 831 result = LowerSameValue(node); 832 break; 833 case IrOpcode::kDeadValue: 834 result = LowerDeadValue(node); 835 break; 836 case IrOpcode::kStringFromSingleCharCode: 837 result = LowerStringFromSingleCharCode(node); 838 break; 839 case IrOpcode::kStringFromSingleCodePoint: 840 result = LowerStringFromSingleCodePoint(node); 841 break; 842 case IrOpcode::kStringIndexOf: 843 result = LowerStringIndexOf(node); 844 break; 845 case IrOpcode::kStringLength: 846 result = LowerStringLength(node); 847 break; 848 case IrOpcode::kStringToNumber: 849 result = LowerStringToNumber(node); 850 break; 851 case IrOpcode::kStringCharCodeAt: 852 result = LowerStringCharCodeAt(node); 853 break; 854 case IrOpcode::kStringCodePointAt: 855 result = LowerStringCodePointAt(node, UnicodeEncodingOf(node->op())); 856 break; 857 case IrOpcode::kStringToLowerCaseIntl: 858 result = LowerStringToLowerCaseIntl(node); 859 break; 860 case IrOpcode::kStringToUpperCaseIntl: 861 result = LowerStringToUpperCaseIntl(node); 862 break; 863 case IrOpcode::kStringSubstring: 864 result = LowerStringSubstring(node); 865 break; 866 case IrOpcode::kStringEqual: 867 result = LowerStringEqual(node); 868 break; 869 case IrOpcode::kStringLessThan: 870 result = LowerStringLessThan(node); 871 break; 872 case IrOpcode::kStringLessThanOrEqual: 873 result = LowerStringLessThanOrEqual(node); 874 break; 875 case IrOpcode::kNumberIsFloat64Hole: 876 result = LowerNumberIsFloat64Hole(node); 877 break; 878 case IrOpcode::kNumberIsFinite: 879 result = LowerNumberIsFinite(node); 880 break; 881 case IrOpcode::kObjectIsFiniteNumber: 882 result = LowerObjectIsFiniteNumber(node); 883 break; 884 case IrOpcode::kNumberIsInteger: 885 result = LowerNumberIsInteger(node); 886 break; 887 case IrOpcode::kObjectIsInteger: 888 result = LowerObjectIsInteger(node); 889 break; 890 case IrOpcode::kNumberIsSafeInteger: 891 result = LowerNumberIsSafeInteger(node); 892 break; 893 case IrOpcode::kObjectIsSafeInteger: 894 result = LowerObjectIsSafeInteger(node); 895 break; 896 case IrOpcode::kCheckFloat64Hole: 897 result = LowerCheckFloat64Hole(node, frame_state); 898 break; 899 case IrOpcode::kCheckNotTaggedHole: 900 result = LowerCheckNotTaggedHole(node, frame_state); 901 break; 902 case IrOpcode::kConvertTaggedHoleToUndefined: 903 result = LowerConvertTaggedHoleToUndefined(node); 904 break; 905 case IrOpcode::kCheckEqualsInternalizedString: 906 LowerCheckEqualsInternalizedString(node, frame_state); 907 break; 908 case IrOpcode::kAllocate: 909 result = LowerAllocate(node); 910 break; 911 case IrOpcode::kCheckEqualsSymbol: 912 LowerCheckEqualsSymbol(node, frame_state); 913 break; 914 case IrOpcode::kPlainPrimitiveToNumber: 915 result = LowerPlainPrimitiveToNumber(node); 916 break; 917 case IrOpcode::kPlainPrimitiveToWord32: 918 result = LowerPlainPrimitiveToWord32(node); 919 break; 920 case IrOpcode::kPlainPrimitiveToFloat64: 921 result = LowerPlainPrimitiveToFloat64(node); 922 break; 923 case IrOpcode::kEnsureWritableFastElements: 924 result = LowerEnsureWritableFastElements(node); 925 break; 926 case IrOpcode::kMaybeGrowFastElements: 927 result = LowerMaybeGrowFastElements(node, frame_state); 928 break; 929 case IrOpcode::kTransitionElementsKind: 930 LowerTransitionElementsKind(node); 931 break; 932 case IrOpcode::kLoadFieldByIndex: 933 result = LowerLoadFieldByIndex(node); 934 break; 935 case IrOpcode::kLoadTypedElement: 936 result = LowerLoadTypedElement(node); 937 break; 938 case IrOpcode::kLoadDataViewElement: 939 result = LowerLoadDataViewElement(node); 940 break; 941 case IrOpcode::kStoreTypedElement: 942 LowerStoreTypedElement(node); 943 break; 944 case IrOpcode::kStoreDataViewElement: 945 LowerStoreDataViewElement(node); 946 break; 947 case IrOpcode::kStoreSignedSmallElement: 948 LowerStoreSignedSmallElement(node); 949 break; 950 case IrOpcode::kFindOrderedHashMapEntry: 951 result = LowerFindOrderedHashMapEntry(node); 952 break; 953 case IrOpcode::kFindOrderedHashMapEntryForInt32Key: 954 result = LowerFindOrderedHashMapEntryForInt32Key(node); 955 break; 956 case IrOpcode::kTransitionAndStoreNumberElement: 957 LowerTransitionAndStoreNumberElement(node); 958 break; 959 case IrOpcode::kTransitionAndStoreNonNumberElement: 960 LowerTransitionAndStoreNonNumberElement(node); 961 break; 962 case IrOpcode::kTransitionAndStoreElement: 963 LowerTransitionAndStoreElement(node); 964 break; 965 case IrOpcode::kRuntimeAbort: 966 LowerRuntimeAbort(node); 967 break; 968 case IrOpcode::kConvertReceiver: 969 result = LowerConvertReceiver(node); 970 break; 971 case IrOpcode::kFloat64RoundUp: 972 if (!LowerFloat64RoundUp(node).To(&result)) { 973 return false; 974 } 975 break; 976 case IrOpcode::kFloat64RoundDown: 977 if (!LowerFloat64RoundDown(node).To(&result)) { 978 return false; 979 } 980 break; 981 case IrOpcode::kFloat64RoundTruncate: 982 if (!LowerFloat64RoundTruncate(node).To(&result)) { 983 return false; 984 } 985 break; 986 case IrOpcode::kFloat64RoundTiesEven: 987 if (!LowerFloat64RoundTiesEven(node).To(&result)) { 988 return false; 989 } 990 break; 991 case IrOpcode::kDateNow: 992 result = LowerDateNow(node); 993 break; 994 default: 995 return false; 996 } 997 998 if ((result ? 1 : 0) != node->op()->ValueOutputCount()) { 999 FATAL( 1000 "Effect control linearizer lowering of '%s':" 1001 " value output count does not agree.", 1002 node->op()->mnemonic()); 1003 } 1004 1005 *effect = gasm()->ExtractCurrentEffect(); 1006 *control = gasm()->ExtractCurrentControl(); 1007 NodeProperties::ReplaceUses(node, result, *effect, *control); 1008 return true; 1009 } 1010 1011 #define __ gasm()-> 1012 1013 Node* EffectControlLinearizer::LowerChangeFloat64ToTagged(Node* node) { 1014 CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op()); 1015 Node* value = node->InputAt(0); 1016 1017 auto done = __ MakeLabel(MachineRepresentation::kTagged); 1018 auto if_heapnumber = __ MakeDeferredLabel(); 1019 auto if_int32 = __ MakeLabel(); 1020 1021 Node* value32 = __ RoundFloat64ToInt32(value); 1022 __ GotoIf(__ Float64Equal(value, __ ChangeInt32ToFloat64(value32)), 1023 &if_int32); 1024 __ Goto(&if_heapnumber); 1025 1026 __ Bind(&if_int32); 1027 { 1028 if (mode == CheckForMinusZeroMode::kCheckForMinusZero) { 1029 Node* zero = __ Int32Constant(0); 1030 auto if_zero = __ MakeDeferredLabel(); 1031 auto if_smi = __ MakeLabel(); 1032 1033 __ GotoIf(__ Word32Equal(value32, zero), &if_zero); 1034 __ Goto(&if_smi); 1035 1036 __ Bind(&if_zero); 1037 { 1038 // In case of 0, we need to check the high bits for the IEEE -0 pattern. 1039 __ GotoIf(__ Int32LessThan(__ Float64ExtractHighWord32(value), zero), 1040 &if_heapnumber); 1041 __ Goto(&if_smi); 1042 } 1043 1044 __ Bind(&if_smi); 1045 } 1046 1047 if (SmiValuesAre32Bits()) { 1048 Node* value_smi = ChangeInt32ToSmi(value32); 1049 __ Goto(&done, value_smi); 1050 } else { 1051 DCHECK(SmiValuesAre31Bits()); 1052 Node* add = __ Int32AddWithOverflow(value32, value32); 1053 Node* ovf = __ Projection(1, add); 1054 __ GotoIf(ovf, &if_heapnumber); 1055 Node* value_smi = __ Projection(0, add); 1056 value_smi = ChangeInt32ToIntPtr(value_smi); 1057 __ Goto(&done, value_smi); 1058 } 1059 } 1060 1061 __ Bind(&if_heapnumber); 1062 { 1063 Node* value_number = AllocateHeapNumberWithValue(value); 1064 __ Goto(&done, value_number); 1065 } 1066 1067 __ Bind(&done); 1068 return done.PhiAt(0); 1069 } 1070 1071 Node* EffectControlLinearizer::LowerChangeFloat64ToTaggedPointer(Node* node) { 1072 Node* value = node->InputAt(0); 1073 return AllocateHeapNumberWithValue(value); 1074 } 1075 1076 Node* EffectControlLinearizer::LowerChangeBitToTagged(Node* node) { 1077 Node* value = node->InputAt(0); 1078 1079 auto if_true = __ MakeLabel(); 1080 auto done = __ MakeLabel(MachineRepresentation::kTagged); 1081 1082 __ GotoIf(value, &if_true); 1083 __ Goto(&done, __ FalseConstant()); 1084 1085 __ Bind(&if_true); 1086 __ Goto(&done, __ TrueConstant()); 1087 1088 __ Bind(&done); 1089 return done.PhiAt(0); 1090 } 1091 1092 Node* EffectControlLinearizer::LowerChangeInt31ToTaggedSigned(Node* node) { 1093 Node* value = node->InputAt(0); 1094 return ChangeInt32ToSmi(value); 1095 } 1096 1097 Node* EffectControlLinearizer::LowerChangeInt32ToTagged(Node* node) { 1098 Node* value = node->InputAt(0); 1099 1100 if (SmiValuesAre32Bits()) { 1101 return ChangeInt32ToSmi(value); 1102 } 1103 DCHECK(SmiValuesAre31Bits()); 1104 1105 auto if_overflow = __ MakeDeferredLabel(); 1106 auto done = __ MakeLabel(MachineRepresentation::kTagged); 1107 1108 Node* add = __ Int32AddWithOverflow(value, value); 1109 Node* ovf = __ Projection(1, add); 1110 __ GotoIf(ovf, &if_overflow); 1111 Node* value_smi = __ Projection(0, add); 1112 value_smi = ChangeInt32ToIntPtr(value_smi); 1113 __ Goto(&done, value_smi); 1114 1115 __ Bind(&if_overflow); 1116 Node* number = AllocateHeapNumberWithValue(__ ChangeInt32ToFloat64(value)); 1117 __ Goto(&done, number); 1118 1119 __ Bind(&done); 1120 return done.PhiAt(0); 1121 } 1122 1123 Node* EffectControlLinearizer::LowerChangeUint32ToTagged(Node* node) { 1124 Node* value = node->InputAt(0); 1125 1126 auto if_not_in_smi_range = __ MakeDeferredLabel(); 1127 auto done = __ MakeLabel(MachineRepresentation::kTagged); 1128 1129 Node* check = __ Uint32LessThanOrEqual(value, SmiMaxValueConstant()); 1130 __ GotoIfNot(check, &if_not_in_smi_range); 1131 __ Goto(&done, ChangeUint32ToSmi(value)); 1132 1133 __ Bind(&if_not_in_smi_range); 1134 Node* number = AllocateHeapNumberWithValue(__ ChangeUint32ToFloat64(value)); 1135 1136 __ Goto(&done, number); 1137 __ Bind(&done); 1138 1139 return done.PhiAt(0); 1140 } 1141 1142 Node* EffectControlLinearizer::LowerChangeTaggedSignedToInt32(Node* node) { 1143 Node* value = node->InputAt(0); 1144 return ChangeSmiToInt32(value); 1145 } 1146 1147 Node* EffectControlLinearizer::LowerChangeTaggedToBit(Node* node) { 1148 Node* value = node->InputAt(0); 1149 return __ WordEqual(value, __ TrueConstant()); 1150 } 1151 1152 void EffectControlLinearizer::TruncateTaggedPointerToBit( 1153 Node* node, GraphAssemblerLabel<1>* done) { 1154 Node* value = node->InputAt(0); 1155 1156 auto if_heapnumber = __ MakeDeferredLabel(); 1157 auto if_bigint = __ MakeDeferredLabel(); 1158 1159 Node* zero = __ Int32Constant(0); 1160 Node* fzero = __ Float64Constant(0.0); 1161 1162 // Check if {value} is false. 1163 __ GotoIf(__ WordEqual(value, __ FalseConstant()), done, zero); 1164 1165 // Check if {value} is the empty string. 1166 __ GotoIf(__ WordEqual(value, __ EmptyStringConstant()), done, zero); 1167 1168 // Load the map of {value}. 1169 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1170 1171 // Check if the {value} is undetectable and immediately return false. 1172 // This includes undefined and null. 1173 Node* value_map_bitfield = 1174 __ LoadField(AccessBuilder::ForMapBitField(), value_map); 1175 __ GotoIfNot( 1176 __ Word32Equal( 1177 __ Word32And(value_map_bitfield, 1178 __ Int32Constant(Map::IsUndetectableBit::kMask)), 1179 zero), 1180 done, zero); 1181 1182 // Check if {value} is a HeapNumber. 1183 __ GotoIf(__ WordEqual(value_map, __ HeapNumberMapConstant()), 1184 &if_heapnumber); 1185 1186 // Check if {value} is a BigInt. 1187 Node* value_instance_type = 1188 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 1189 __ GotoIf(__ Word32Equal(value_instance_type, __ Int32Constant(BIGINT_TYPE)), 1190 &if_bigint); 1191 1192 // All other values that reach here are true. 1193 __ Goto(done, __ Int32Constant(1)); 1194 1195 __ Bind(&if_heapnumber); 1196 { 1197 // For HeapNumber {value}, just check that its value is not 0.0, -0.0 or 1198 // NaN. 1199 Node* value_value = 1200 __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 1201 __ Goto(done, __ Float64LessThan(fzero, __ Float64Abs(value_value))); 1202 } 1203 1204 __ Bind(&if_bigint); 1205 { 1206 Node* bitfield = __ LoadField(AccessBuilder::ForBigIntBitfield(), value); 1207 Node* length_is_zero = __ WordEqual( 1208 __ WordAnd(bitfield, __ IntPtrConstant(BigInt::LengthBits::kMask)), 1209 __ IntPtrConstant(0)); 1210 __ Goto(done, __ Word32Equal(length_is_zero, zero)); 1211 } 1212 } 1213 1214 Node* EffectControlLinearizer::LowerTruncateTaggedToBit(Node* node) { 1215 auto done = __ MakeLabel(MachineRepresentation::kBit); 1216 auto if_smi = __ MakeDeferredLabel(); 1217 1218 Node* value = node->InputAt(0); 1219 __ GotoIf(ObjectIsSmi(value), &if_smi); 1220 1221 TruncateTaggedPointerToBit(node, &done); 1222 1223 __ Bind(&if_smi); 1224 { 1225 // If {value} is a Smi, then we only need to check that it's not zero. 1226 __ Goto(&done, __ Word32Equal(__ WordEqual(value, __ IntPtrConstant(0)), 1227 __ Int32Constant(0))); 1228 } 1229 1230 __ Bind(&done); 1231 return done.PhiAt(0); 1232 } 1233 1234 Node* EffectControlLinearizer::LowerTruncateTaggedPointerToBit(Node* node) { 1235 auto done = __ MakeLabel(MachineRepresentation::kBit); 1236 1237 TruncateTaggedPointerToBit(node, &done); 1238 1239 __ Bind(&done); 1240 return done.PhiAt(0); 1241 } 1242 1243 Node* EffectControlLinearizer::LowerChangeTaggedToInt32(Node* node) { 1244 Node* value = node->InputAt(0); 1245 1246 auto if_not_smi = __ MakeDeferredLabel(); 1247 auto done = __ MakeLabel(MachineRepresentation::kWord32); 1248 1249 Node* check = ObjectIsSmi(value); 1250 __ GotoIfNot(check, &if_not_smi); 1251 __ Goto(&done, ChangeSmiToInt32(value)); 1252 1253 __ Bind(&if_not_smi); 1254 STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); 1255 Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 1256 vfalse = __ ChangeFloat64ToInt32(vfalse); 1257 __ Goto(&done, vfalse); 1258 1259 __ Bind(&done); 1260 return done.PhiAt(0); 1261 } 1262 1263 Node* EffectControlLinearizer::LowerChangeTaggedToUint32(Node* node) { 1264 Node* value = node->InputAt(0); 1265 1266 auto if_not_smi = __ MakeDeferredLabel(); 1267 auto done = __ MakeLabel(MachineRepresentation::kWord32); 1268 1269 Node* check = ObjectIsSmi(value); 1270 __ GotoIfNot(check, &if_not_smi); 1271 __ Goto(&done, ChangeSmiToInt32(value)); 1272 1273 __ Bind(&if_not_smi); 1274 STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); 1275 Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 1276 vfalse = __ ChangeFloat64ToUint32(vfalse); 1277 __ Goto(&done, vfalse); 1278 1279 __ Bind(&done); 1280 return done.PhiAt(0); 1281 } 1282 1283 Node* EffectControlLinearizer::LowerChangeTaggedToFloat64(Node* node) { 1284 return LowerTruncateTaggedToFloat64(node); 1285 } 1286 1287 Node* EffectControlLinearizer::LowerChangeTaggedToTaggedSigned(Node* node) { 1288 Node* value = node->InputAt(0); 1289 1290 auto if_not_smi = __ MakeDeferredLabel(); 1291 auto done = __ MakeLabel(MachineRepresentation::kWord32); 1292 1293 Node* check = ObjectIsSmi(value); 1294 __ GotoIfNot(check, &if_not_smi); 1295 __ Goto(&done, value); 1296 1297 __ Bind(&if_not_smi); 1298 STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); 1299 Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 1300 vfalse = __ ChangeFloat64ToInt32(vfalse); 1301 vfalse = ChangeInt32ToSmi(vfalse); 1302 __ Goto(&done, vfalse); 1303 1304 __ Bind(&done); 1305 return done.PhiAt(0); 1306 } 1307 1308 Node* EffectControlLinearizer::LowerTruncateTaggedToFloat64(Node* node) { 1309 Node* value = node->InputAt(0); 1310 1311 auto if_not_smi = __ MakeDeferredLabel(); 1312 auto done = __ MakeLabel(MachineRepresentation::kFloat64); 1313 1314 Node* check = ObjectIsSmi(value); 1315 __ GotoIfNot(check, &if_not_smi); 1316 Node* vtrue = ChangeSmiToInt32(value); 1317 vtrue = __ ChangeInt32ToFloat64(vtrue); 1318 __ Goto(&done, vtrue); 1319 1320 __ Bind(&if_not_smi); 1321 STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); 1322 Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 1323 __ Goto(&done, vfalse); 1324 1325 __ Bind(&done); 1326 return done.PhiAt(0); 1327 } 1328 1329 Node* EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state) { 1330 Node* index = node->InputAt(0); 1331 Node* limit = node->InputAt(1); 1332 const CheckParameters& params = CheckParametersOf(node->op()); 1333 1334 Node* check = __ Uint32LessThan(index, limit); 1335 __ DeoptimizeIfNot(DeoptimizeReason::kOutOfBounds, params.feedback(), check, 1336 frame_state, IsSafetyCheck::kCriticalSafetyCheck); 1337 return index; 1338 } 1339 1340 Node* EffectControlLinearizer::LowerPoisonIndex(Node* node) { 1341 Node* index = node->InputAt(0); 1342 if (mask_array_index_ == kMaskArrayIndex) { 1343 index = __ Word32PoisonOnSpeculation(index); 1344 } 1345 return index; 1346 } 1347 1348 void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) { 1349 CheckMapsParameters const& p = CheckMapsParametersOf(node->op()); 1350 Node* value = node->InputAt(0); 1351 1352 ZoneHandleSet<Map> const& maps = p.maps(); 1353 size_t const map_count = maps.size(); 1354 1355 if (p.flags() & CheckMapsFlag::kTryMigrateInstance) { 1356 auto done = __ MakeDeferredLabel(); 1357 auto migrate = __ MakeDeferredLabel(); 1358 1359 // Load the current map of the {value}. 1360 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1361 1362 // Perform the map checks. 1363 for (size_t i = 0; i < map_count; ++i) { 1364 Node* map = __ HeapConstant(maps[i]); 1365 Node* check = __ WordEqual(value_map, map); 1366 if (i == map_count - 1) { 1367 __ GotoIfNot(check, &migrate); 1368 __ Goto(&done); 1369 } else { 1370 __ GotoIf(check, &done); 1371 } 1372 } 1373 1374 // Perform the (deferred) instance migration. 1375 __ Bind(&migrate); 1376 { 1377 // If map is not deprecated the migration attempt does not make sense. 1378 Node* bitfield3 = 1379 __ LoadField(AccessBuilder::ForMapBitField3(), value_map); 1380 Node* if_not_deprecated = __ WordEqual( 1381 __ Word32And(bitfield3, 1382 __ Int32Constant(Map::IsDeprecatedBit::kMask)), 1383 __ Int32Constant(0)); 1384 __ DeoptimizeIf(DeoptimizeReason::kWrongMap, p.feedback(), 1385 if_not_deprecated, frame_state); 1386 1387 Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; 1388 Runtime::FunctionId id = Runtime::kTryMigrateInstance; 1389 auto call_descriptor = Linkage::GetRuntimeCallDescriptor( 1390 graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags); 1391 Node* result = __ Call(call_descriptor, __ CEntryStubConstant(1), value, 1392 __ ExternalConstant(ExternalReference::Create(id)), 1393 __ Int32Constant(1), __ NoContextConstant()); 1394 Node* check = ObjectIsSmi(result); 1395 __ DeoptimizeIf(DeoptimizeReason::kInstanceMigrationFailed, p.feedback(), 1396 check, frame_state); 1397 } 1398 1399 // Reload the current map of the {value}. 1400 value_map = __ LoadField(AccessBuilder::ForMap(), value); 1401 1402 // Perform the map checks again. 1403 for (size_t i = 0; i < map_count; ++i) { 1404 Node* map = __ HeapConstant(maps[i]); 1405 Node* check = __ WordEqual(value_map, map); 1406 if (i == map_count - 1) { 1407 __ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, p.feedback(), check, 1408 frame_state); 1409 } else { 1410 __ GotoIf(check, &done); 1411 } 1412 } 1413 1414 __ Goto(&done); 1415 __ Bind(&done); 1416 } else { 1417 auto done = __ MakeLabel(); 1418 1419 // Load the current map of the {value}. 1420 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1421 1422 for (size_t i = 0; i < map_count; ++i) { 1423 Node* map = __ HeapConstant(maps[i]); 1424 Node* check = __ WordEqual(value_map, map); 1425 if (i == map_count - 1) { 1426 __ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, p.feedback(), check, 1427 frame_state); 1428 } else { 1429 __ GotoIf(check, &done); 1430 } 1431 } 1432 __ Goto(&done); 1433 __ Bind(&done); 1434 } 1435 } 1436 1437 Node* EffectControlLinearizer::LowerCompareMaps(Node* node) { 1438 ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op()).maps(); 1439 size_t const map_count = maps.size(); 1440 Node* value = node->InputAt(0); 1441 1442 auto done = __ MakeLabel(MachineRepresentation::kBit); 1443 1444 // Load the current map of the {value}. 1445 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1446 1447 for (size_t i = 0; i < map_count; ++i) { 1448 Node* map = __ HeapConstant(maps[i]); 1449 Node* check = __ WordEqual(value_map, map); 1450 __ GotoIf(check, &done, __ Int32Constant(1)); 1451 } 1452 __ Goto(&done, __ Int32Constant(0)); 1453 1454 __ Bind(&done); 1455 return done.PhiAt(0); 1456 } 1457 1458 Node* EffectControlLinearizer::LowerCheckNumber(Node* node, Node* frame_state) { 1459 Node* value = node->InputAt(0); 1460 const CheckParameters& params = CheckParametersOf(node->op()); 1461 1462 auto if_not_smi = __ MakeDeferredLabel(); 1463 auto done = __ MakeLabel(); 1464 1465 Node* check0 = ObjectIsSmi(value); 1466 __ GotoIfNot(check0, &if_not_smi); 1467 __ Goto(&done); 1468 1469 __ Bind(&if_not_smi); 1470 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1471 Node* check1 = __ WordEqual(value_map, __ HeapNumberMapConstant()); 1472 __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, params.feedback(), 1473 check1, frame_state); 1474 __ Goto(&done); 1475 1476 __ Bind(&done); 1477 return value; 1478 } 1479 1480 Node* EffectControlLinearizer::LowerCheckReceiver(Node* node, 1481 Node* frame_state) { 1482 Node* value = node->InputAt(0); 1483 1484 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1485 Node* value_instance_type = 1486 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 1487 1488 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 1489 Node* check = __ Uint32LessThanOrEqual( 1490 __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type); 1491 __ DeoptimizeIfNot(DeoptimizeReason::kNotAJavaScriptObject, VectorSlotPair(), 1492 check, frame_state); 1493 return value; 1494 } 1495 1496 Node* EffectControlLinearizer::LowerCheckSymbol(Node* node, Node* frame_state) { 1497 Node* value = node->InputAt(0); 1498 1499 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1500 1501 Node* check = 1502 __ WordEqual(value_map, __ HeapConstant(factory()->symbol_map())); 1503 __ DeoptimizeIfNot(DeoptimizeReason::kNotASymbol, VectorSlotPair(), check, 1504 frame_state); 1505 return value; 1506 } 1507 1508 Node* EffectControlLinearizer::LowerCheckString(Node* node, Node* frame_state) { 1509 Node* value = node->InputAt(0); 1510 const CheckParameters& params = CheckParametersOf(node->op()); 1511 1512 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1513 Node* value_instance_type = 1514 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 1515 1516 Node* check = __ Uint32LessThan(value_instance_type, 1517 __ Uint32Constant(FIRST_NONSTRING_TYPE)); 1518 __ DeoptimizeIfNot(DeoptimizeReason::kNotAString, params.feedback(), check, 1519 frame_state); 1520 return value; 1521 } 1522 1523 Node* EffectControlLinearizer::LowerCheckInternalizedString(Node* node, 1524 Node* frame_state) { 1525 Node* value = node->InputAt(0); 1526 1527 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1528 Node* value_instance_type = 1529 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 1530 1531 Node* check = __ Word32Equal( 1532 __ Word32And(value_instance_type, 1533 __ Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)), 1534 __ Int32Constant(kInternalizedTag)); 1535 __ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, VectorSlotPair(), 1536 check, frame_state); 1537 1538 return value; 1539 } 1540 1541 void EffectControlLinearizer::LowerCheckIf(Node* node, Node* frame_state) { 1542 Node* value = node->InputAt(0); 1543 const CheckIfParameters& p = CheckIfParametersOf(node->op()); 1544 __ DeoptimizeIfNot(p.reason(), p.feedback(), value, frame_state); 1545 } 1546 1547 Node* EffectControlLinearizer::LowerCheckedInt32Add(Node* node, 1548 Node* frame_state) { 1549 Node* lhs = node->InputAt(0); 1550 Node* rhs = node->InputAt(1); 1551 1552 Node* value = __ Int32AddWithOverflow(lhs, rhs); 1553 Node* check = __ Projection(1, value); 1554 __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check, 1555 frame_state); 1556 return __ Projection(0, value); 1557 } 1558 1559 Node* EffectControlLinearizer::LowerCheckedInt32Sub(Node* node, 1560 Node* frame_state) { 1561 Node* lhs = node->InputAt(0); 1562 Node* rhs = node->InputAt(1); 1563 1564 Node* value = __ Int32SubWithOverflow(lhs, rhs); 1565 Node* check = __ Projection(1, value); 1566 __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check, 1567 frame_state); 1568 return __ Projection(0, value); 1569 } 1570 1571 Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node, 1572 Node* frame_state) { 1573 Node* lhs = node->InputAt(0); 1574 Node* rhs = node->InputAt(1); 1575 1576 auto if_not_positive = __ MakeDeferredLabel(); 1577 auto if_is_minint = __ MakeDeferredLabel(); 1578 auto done = __ MakeLabel(MachineRepresentation::kWord32); 1579 auto minint_check_done = __ MakeLabel(); 1580 1581 Node* zero = __ Int32Constant(0); 1582 1583 // Check if {rhs} is positive (and not zero). 1584 Node* check0 = __ Int32LessThan(zero, rhs); 1585 __ GotoIfNot(check0, &if_not_positive); 1586 1587 // Fast case, no additional checking required. 1588 __ Goto(&done, __ Int32Div(lhs, rhs)); 1589 1590 { 1591 __ Bind(&if_not_positive); 1592 1593 // Check if {rhs} is zero. 1594 Node* check = __ Word32Equal(rhs, zero); 1595 __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(), check, 1596 frame_state); 1597 1598 // Check if {lhs} is zero, as that would produce minus zero. 1599 check = __ Word32Equal(lhs, zero); 1600 __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(), check, 1601 frame_state); 1602 1603 // Check if {lhs} is kMinInt and {rhs} is -1, in which case we'd have 1604 // to return -kMinInt, which is not representable. 1605 Node* minint = __ Int32Constant(std::numeric_limits<int32_t>::min()); 1606 Node* check1 = graph()->NewNode(machine()->Word32Equal(), lhs, minint); 1607 __ GotoIf(check1, &if_is_minint); 1608 __ Goto(&minint_check_done); 1609 1610 __ Bind(&if_is_minint); 1611 // Check if {rhs} is -1. 1612 Node* minusone = __ Int32Constant(-1); 1613 Node* is_minus_one = __ Word32Equal(rhs, minusone); 1614 __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), is_minus_one, 1615 frame_state); 1616 __ Goto(&minint_check_done); 1617 1618 __ Bind(&minint_check_done); 1619 // Perform the actual integer division. 1620 __ Goto(&done, __ Int32Div(lhs, rhs)); 1621 } 1622 1623 __ Bind(&done); 1624 Node* value = done.PhiAt(0); 1625 1626 // Check if the remainder is non-zero. 1627 Node* check = __ Word32Equal(lhs, __ Int32Mul(rhs, value)); 1628 __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, VectorSlotPair(), check, 1629 frame_state); 1630 1631 return value; 1632 } 1633 1634 Node* EffectControlLinearizer::BuildUint32Mod(Node* lhs, Node* rhs) { 1635 auto if_rhs_power_of_two = __ MakeLabel(); 1636 auto done = __ MakeLabel(MachineRepresentation::kWord32); 1637 1638 // Compute the mask for the {rhs}. 1639 Node* one = __ Int32Constant(1); 1640 Node* msk = __ Int32Sub(rhs, one); 1641 1642 // Check if the {rhs} is a power of two. 1643 __ GotoIf(__ Word32Equal(__ Word32And(rhs, msk), __ Int32Constant(0)), 1644 &if_rhs_power_of_two); 1645 { 1646 // The {rhs} is not a power of two, do a generic Uint32Mod. 1647 __ Goto(&done, __ Uint32Mod(lhs, rhs)); 1648 } 1649 1650 __ Bind(&if_rhs_power_of_two); 1651 { 1652 // The {rhs} is a power of two, just do a fast bit masking. 1653 __ Goto(&done, __ Word32And(lhs, msk)); 1654 } 1655 1656 __ Bind(&done); 1657 return done.PhiAt(0); 1658 } 1659 1660 Node* EffectControlLinearizer::LowerCheckedInt32Mod(Node* node, 1661 Node* frame_state) { 1662 // General case for signed integer modulus, with optimization for (unknown) 1663 // power of 2 right hand side. 1664 // 1665 // if rhs <= 0 then 1666 // rhs = -rhs 1667 // deopt if rhs == 0 1668 // let msk = rhs - 1 in 1669 // if lhs < 0 then 1670 // let lhs_abs = -lsh in 1671 // let res = if rhs & msk == 0 then 1672 // lhs_abs & msk 1673 // else 1674 // lhs_abs % rhs in 1675 // if lhs < 0 then 1676 // deopt if res == 0 1677 // -res 1678 // else 1679 // res 1680 // else 1681 // if rhs & msk == 0 then 1682 // lhs & msk 1683 // else 1684 // lhs % rhs 1685 // 1686 Node* lhs = node->InputAt(0); 1687 Node* rhs = node->InputAt(1); 1688 1689 auto if_rhs_not_positive = __ MakeDeferredLabel(); 1690 auto if_lhs_negative = __ MakeDeferredLabel(); 1691 auto if_rhs_power_of_two = __ MakeLabel(); 1692 auto rhs_checked = __ MakeLabel(MachineRepresentation::kWord32); 1693 auto done = __ MakeLabel(MachineRepresentation::kWord32); 1694 1695 Node* zero = __ Int32Constant(0); 1696 1697 // Check if {rhs} is not strictly positive. 1698 Node* check0 = __ Int32LessThanOrEqual(rhs, zero); 1699 __ GotoIf(check0, &if_rhs_not_positive); 1700 __ Goto(&rhs_checked, rhs); 1701 1702 __ Bind(&if_rhs_not_positive); 1703 { 1704 // Negate {rhs}, might still produce a negative result in case of 1705 // -2^31, but that is handled safely below. 1706 Node* vtrue0 = __ Int32Sub(zero, rhs); 1707 1708 // Ensure that {rhs} is not zero, otherwise we'd have to return NaN. 1709 __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(), 1710 __ Word32Equal(vtrue0, zero), frame_state); 1711 __ Goto(&rhs_checked, vtrue0); 1712 } 1713 1714 __ Bind(&rhs_checked); 1715 rhs = rhs_checked.PhiAt(0); 1716 1717 __ GotoIf(__ Int32LessThan(lhs, zero), &if_lhs_negative); 1718 { 1719 // The {lhs} is a non-negative integer. 1720 __ Goto(&done, BuildUint32Mod(lhs, rhs)); 1721 } 1722 1723 __ Bind(&if_lhs_negative); 1724 { 1725 // The {lhs} is a negative integer. 1726 Node* res = BuildUint32Mod(__ Int32Sub(zero, lhs), rhs); 1727 1728 // Check if we would have to return -0. 1729 __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(), 1730 __ Word32Equal(res, zero), frame_state); 1731 __ Goto(&done, __ Int32Sub(zero, res)); 1732 } 1733 1734 __ Bind(&done); 1735 return done.PhiAt(0); 1736 } 1737 1738 Node* EffectControlLinearizer::LowerCheckedUint32Div(Node* node, 1739 Node* frame_state) { 1740 Node* lhs = node->InputAt(0); 1741 Node* rhs = node->InputAt(1); 1742 1743 Node* zero = __ Int32Constant(0); 1744 1745 // Ensure that {rhs} is not zero, otherwise we'd have to return NaN. 1746 Node* check = __ Word32Equal(rhs, zero); 1747 __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(), check, 1748 frame_state); 1749 1750 // Perform the actual unsigned integer division. 1751 Node* value = __ Uint32Div(lhs, rhs); 1752 1753 // Check if the remainder is non-zero. 1754 check = __ Word32Equal(lhs, __ Int32Mul(rhs, value)); 1755 __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, VectorSlotPair(), check, 1756 frame_state); 1757 return value; 1758 } 1759 1760 Node* EffectControlLinearizer::LowerCheckedUint32Mod(Node* node, 1761 Node* frame_state) { 1762 Node* lhs = node->InputAt(0); 1763 Node* rhs = node->InputAt(1); 1764 1765 Node* zero = __ Int32Constant(0); 1766 1767 // Ensure that {rhs} is not zero, otherwise we'd have to return NaN. 1768 Node* check = __ Word32Equal(rhs, zero); 1769 __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(), check, 1770 frame_state); 1771 1772 // Perform the actual unsigned integer modulus. 1773 return BuildUint32Mod(lhs, rhs); 1774 } 1775 1776 Node* EffectControlLinearizer::LowerCheckedInt32Mul(Node* node, 1777 Node* frame_state) { 1778 CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op()); 1779 Node* lhs = node->InputAt(0); 1780 Node* rhs = node->InputAt(1); 1781 1782 Node* projection = __ Int32MulWithOverflow(lhs, rhs); 1783 Node* check = __ Projection(1, projection); 1784 __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check, 1785 frame_state); 1786 1787 Node* value = __ Projection(0, projection); 1788 1789 if (mode == CheckForMinusZeroMode::kCheckForMinusZero) { 1790 auto if_zero = __ MakeDeferredLabel(); 1791 auto check_done = __ MakeLabel(); 1792 Node* zero = __ Int32Constant(0); 1793 Node* check_zero = __ Word32Equal(value, zero); 1794 __ GotoIf(check_zero, &if_zero); 1795 __ Goto(&check_done); 1796 1797 __ Bind(&if_zero); 1798 // We may need to return negative zero. 1799 Node* check_or = __ Int32LessThan(__ Word32Or(lhs, rhs), zero); 1800 __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(), check_or, 1801 frame_state); 1802 __ Goto(&check_done); 1803 1804 __ Bind(&check_done); 1805 } 1806 1807 return value; 1808 } 1809 1810 Node* EffectControlLinearizer::LowerCheckedInt32ToTaggedSigned( 1811 Node* node, Node* frame_state) { 1812 DCHECK(SmiValuesAre31Bits()); 1813 Node* value = node->InputAt(0); 1814 const CheckParameters& params = CheckParametersOf(node->op()); 1815 1816 Node* add = __ Int32AddWithOverflow(value, value); 1817 Node* check = __ Projection(1, add); 1818 __ DeoptimizeIf(DeoptimizeReason::kOverflow, params.feedback(), check, 1819 frame_state); 1820 Node* result = __ Projection(0, add); 1821 result = ChangeInt32ToIntPtr(result); 1822 return result; 1823 } 1824 1825 Node* EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node, 1826 Node* frame_state) { 1827 Node* value = node->InputAt(0); 1828 const CheckParameters& params = CheckParametersOf(node->op()); 1829 Node* unsafe = __ Int32LessThan(value, __ Int32Constant(0)); 1830 __ DeoptimizeIf(DeoptimizeReason::kLostPrecision, params.feedback(), unsafe, 1831 frame_state); 1832 return value; 1833 } 1834 1835 Node* EffectControlLinearizer::LowerCheckedUint32ToTaggedSigned( 1836 Node* node, Node* frame_state) { 1837 Node* value = node->InputAt(0); 1838 const CheckParameters& params = CheckParametersOf(node->op()); 1839 Node* check = __ Uint32LessThanOrEqual(value, SmiMaxValueConstant()); 1840 __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, params.feedback(), check, 1841 frame_state); 1842 return ChangeUint32ToSmi(value); 1843 } 1844 1845 Node* EffectControlLinearizer::BuildCheckedFloat64ToInt32( 1846 CheckForMinusZeroMode mode, const VectorSlotPair& feedback, Node* value, 1847 Node* frame_state) { 1848 Node* value32 = __ RoundFloat64ToInt32(value); 1849 Node* check_same = __ Float64Equal(value, __ ChangeInt32ToFloat64(value32)); 1850 __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecisionOrNaN, feedback, 1851 check_same, frame_state); 1852 1853 if (mode == CheckForMinusZeroMode::kCheckForMinusZero) { 1854 // Check if {value} is -0. 1855 auto if_zero = __ MakeDeferredLabel(); 1856 auto check_done = __ MakeLabel(); 1857 1858 Node* check_zero = __ Word32Equal(value32, __ Int32Constant(0)); 1859 __ GotoIf(check_zero, &if_zero); 1860 __ Goto(&check_done); 1861 1862 __ Bind(&if_zero); 1863 // In case of 0, we need to check the high bits for the IEEE -0 pattern. 1864 Node* check_negative = __ Int32LessThan(__ Float64ExtractHighWord32(value), 1865 __ Int32Constant(0)); 1866 __ DeoptimizeIf(DeoptimizeReason::kMinusZero, feedback, check_negative, 1867 frame_state); 1868 __ Goto(&check_done); 1869 1870 __ Bind(&check_done); 1871 } 1872 return value32; 1873 } 1874 1875 Node* EffectControlLinearizer::LowerCheckedFloat64ToInt32(Node* node, 1876 Node* frame_state) { 1877 const CheckMinusZeroParameters& params = 1878 CheckMinusZeroParametersOf(node->op()); 1879 Node* value = node->InputAt(0); 1880 return BuildCheckedFloat64ToInt32(params.mode(), params.feedback(), value, 1881 frame_state); 1882 } 1883 1884 Node* EffectControlLinearizer::LowerCheckedTaggedSignedToInt32( 1885 Node* node, Node* frame_state) { 1886 Node* value = node->InputAt(0); 1887 const CheckParameters& params = CheckParametersOf(node->op()); 1888 Node* check = ObjectIsSmi(value); 1889 __ DeoptimizeIfNot(DeoptimizeReason::kNotASmi, params.feedback(), check, 1890 frame_state); 1891 return ChangeSmiToInt32(value); 1892 } 1893 1894 Node* EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node, 1895 Node* frame_state) { 1896 const CheckMinusZeroParameters& params = 1897 CheckMinusZeroParametersOf(node->op()); 1898 Node* value = node->InputAt(0); 1899 1900 auto if_not_smi = __ MakeDeferredLabel(); 1901 auto done = __ MakeLabel(MachineRepresentation::kWord32); 1902 1903 Node* check = ObjectIsSmi(value); 1904 __ GotoIfNot(check, &if_not_smi); 1905 // In the Smi case, just convert to int32. 1906 __ Goto(&done, ChangeSmiToInt32(value)); 1907 1908 // In the non-Smi case, check the heap numberness, load the number and convert 1909 // to int32. 1910 __ Bind(&if_not_smi); 1911 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1912 Node* check_map = __ WordEqual(value_map, __ HeapNumberMapConstant()); 1913 __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, params.feedback(), 1914 check_map, frame_state); 1915 Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 1916 vfalse = BuildCheckedFloat64ToInt32(params.mode(), params.feedback(), vfalse, 1917 frame_state); 1918 __ Goto(&done, vfalse); 1919 1920 __ Bind(&done); 1921 return done.PhiAt(0); 1922 } 1923 1924 Node* EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64( 1925 CheckTaggedInputMode mode, const VectorSlotPair& feedback, Node* value, 1926 Node* frame_state) { 1927 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 1928 Node* check_number = __ WordEqual(value_map, __ HeapNumberMapConstant()); 1929 switch (mode) { 1930 case CheckTaggedInputMode::kNumber: { 1931 __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, feedback, 1932 check_number, frame_state); 1933 break; 1934 } 1935 case CheckTaggedInputMode::kNumberOrOddball: { 1936 auto check_done = __ MakeLabel(); 1937 1938 __ GotoIf(check_number, &check_done); 1939 // For oddballs also contain the numeric value, let us just check that 1940 // we have an oddball here. 1941 Node* instance_type = 1942 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 1943 Node* check_oddball = 1944 __ Word32Equal(instance_type, __ Int32Constant(ODDBALL_TYPE)); 1945 __ DeoptimizeIfNot(DeoptimizeReason::kNotANumberOrOddball, feedback, 1946 check_oddball, frame_state); 1947 STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); 1948 __ Goto(&check_done); 1949 1950 __ Bind(&check_done); 1951 break; 1952 } 1953 } 1954 return __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 1955 } 1956 1957 Node* EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node, 1958 Node* frame_state) { 1959 CheckTaggedInputParameters const& p = 1960 CheckTaggedInputParametersOf(node->op()); 1961 Node* value = node->InputAt(0); 1962 1963 auto if_smi = __ MakeLabel(); 1964 auto done = __ MakeLabel(MachineRepresentation::kFloat64); 1965 1966 Node* check = ObjectIsSmi(value); 1967 __ GotoIf(check, &if_smi); 1968 1969 // In the Smi case, just convert to int32 and then float64. 1970 // Otherwise, check heap numberness and load the number. 1971 Node* number = BuildCheckedHeapNumberOrOddballToFloat64( 1972 p.mode(), p.feedback(), value, frame_state); 1973 __ Goto(&done, number); 1974 1975 __ Bind(&if_smi); 1976 Node* from_smi = ChangeSmiToInt32(value); 1977 from_smi = __ ChangeInt32ToFloat64(from_smi); 1978 __ Goto(&done, from_smi); 1979 1980 __ Bind(&done); 1981 return done.PhiAt(0); 1982 } 1983 1984 Node* EffectControlLinearizer::LowerCheckedTaggedToTaggedSigned( 1985 Node* node, Node* frame_state) { 1986 Node* value = node->InputAt(0); 1987 const CheckParameters& params = CheckParametersOf(node->op()); 1988 1989 Node* check = ObjectIsSmi(value); 1990 __ DeoptimizeIfNot(DeoptimizeReason::kNotASmi, params.feedback(), check, 1991 frame_state); 1992 1993 return value; 1994 } 1995 1996 Node* EffectControlLinearizer::LowerCheckedTaggedToTaggedPointer( 1997 Node* node, Node* frame_state) { 1998 Node* value = node->InputAt(0); 1999 const CheckParameters& params = CheckParametersOf(node->op()); 2000 2001 Node* check = ObjectIsSmi(value); 2002 __ DeoptimizeIf(DeoptimizeReason::kSmi, params.feedback(), check, 2003 frame_state); 2004 return value; 2005 } 2006 2007 Node* EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node) { 2008 Node* value = node->InputAt(0); 2009 2010 auto if_not_smi = __ MakeDeferredLabel(); 2011 auto done = __ MakeLabel(MachineRepresentation::kWord32); 2012 2013 Node* check = ObjectIsSmi(value); 2014 __ GotoIfNot(check, &if_not_smi); 2015 __ Goto(&done, ChangeSmiToInt32(value)); 2016 2017 __ Bind(&if_not_smi); 2018 STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); 2019 Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 2020 vfalse = __ TruncateFloat64ToWord32(vfalse); 2021 __ Goto(&done, vfalse); 2022 2023 __ Bind(&done); 2024 return done.PhiAt(0); 2025 } 2026 2027 Node* EffectControlLinearizer::LowerCheckedTruncateTaggedToWord32( 2028 Node* node, Node* frame_state) { 2029 const CheckTaggedInputParameters& params = 2030 CheckTaggedInputParametersOf(node->op()); 2031 Node* value = node->InputAt(0); 2032 2033 auto if_not_smi = __ MakeLabel(); 2034 auto done = __ MakeLabel(MachineRepresentation::kWord32); 2035 2036 Node* check = ObjectIsSmi(value); 2037 __ GotoIfNot(check, &if_not_smi); 2038 // In the Smi case, just convert to int32. 2039 __ Goto(&done, ChangeSmiToInt32(value)); 2040 2041 // Otherwise, check that it's a heap number or oddball and truncate the value 2042 // to int32. 2043 __ Bind(&if_not_smi); 2044 Node* number = BuildCheckedHeapNumberOrOddballToFloat64( 2045 params.mode(), params.feedback(), value, frame_state); 2046 number = __ TruncateFloat64ToWord32(number); 2047 __ Goto(&done, number); 2048 2049 __ Bind(&done); 2050 return done.PhiAt(0); 2051 } 2052 2053 Node* EffectControlLinearizer::LowerAllocate(Node* node) { 2054 Node* size = node->InputAt(0); 2055 PretenureFlag pretenure = PretenureFlagOf(node->op()); 2056 Node* new_node = __ Allocate(pretenure, size); 2057 return new_node; 2058 } 2059 2060 Node* EffectControlLinearizer::LowerNumberToString(Node* node) { 2061 Node* argument = node->InputAt(0); 2062 2063 Callable const callable = 2064 Builtins::CallableFor(isolate(), Builtins::kNumberToString); 2065 Operator::Properties properties = Operator::kEliminatable; 2066 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 2067 auto call_descriptor = Linkage::GetStubCallDescriptor( 2068 graph()->zone(), callable.descriptor(), 0, flags, properties); 2069 return __ Call(call_descriptor, __ HeapConstant(callable.code()), argument, 2070 __ NoContextConstant()); 2071 } 2072 2073 Node* EffectControlLinearizer::LowerObjectIsArrayBufferView(Node* node) { 2074 Node* value = node->InputAt(0); 2075 2076 auto if_smi = __ MakeDeferredLabel(); 2077 auto done = __ MakeLabel(MachineRepresentation::kBit); 2078 2079 Node* check = ObjectIsSmi(value); 2080 __ GotoIf(check, &if_smi); 2081 2082 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2083 Node* value_instance_type = 2084 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 2085 STATIC_ASSERT(JS_TYPED_ARRAY_TYPE + 1 == JS_DATA_VIEW_TYPE); 2086 Node* vfalse = __ Uint32LessThan( 2087 __ Int32Sub(value_instance_type, __ Int32Constant(JS_TYPED_ARRAY_TYPE)), 2088 __ Int32Constant(2)); 2089 __ Goto(&done, vfalse); 2090 2091 __ Bind(&if_smi); 2092 __ Goto(&done, __ Int32Constant(0)); 2093 2094 __ Bind(&done); 2095 return done.PhiAt(0); 2096 } 2097 2098 Node* EffectControlLinearizer::LowerObjectIsBigInt(Node* node) { 2099 Node* value = node->InputAt(0); 2100 2101 auto if_smi = __ MakeDeferredLabel(); 2102 auto done = __ MakeLabel(MachineRepresentation::kBit); 2103 2104 Node* check = ObjectIsSmi(value); 2105 __ GotoIf(check, &if_smi); 2106 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2107 Node* value_instance_type = 2108 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 2109 Node* vfalse = 2110 __ Word32Equal(value_instance_type, __ Uint32Constant(BIGINT_TYPE)); 2111 __ Goto(&done, vfalse); 2112 2113 __ Bind(&if_smi); 2114 __ Goto(&done, __ Int32Constant(0)); 2115 2116 __ Bind(&done); 2117 return done.PhiAt(0); 2118 } 2119 2120 Node* EffectControlLinearizer::LowerObjectIsCallable(Node* node) { 2121 Node* value = node->InputAt(0); 2122 2123 auto if_smi = __ MakeDeferredLabel(); 2124 auto done = __ MakeLabel(MachineRepresentation::kBit); 2125 2126 Node* check = ObjectIsSmi(value); 2127 __ GotoIf(check, &if_smi); 2128 2129 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2130 Node* value_bit_field = 2131 __ LoadField(AccessBuilder::ForMapBitField(), value_map); 2132 Node* vfalse = 2133 __ Word32Equal(__ Int32Constant(Map::IsCallableBit::kMask), 2134 __ Word32And(value_bit_field, 2135 __ Int32Constant(Map::IsCallableBit::kMask))); 2136 __ Goto(&done, vfalse); 2137 2138 __ Bind(&if_smi); 2139 __ Goto(&done, __ Int32Constant(0)); 2140 2141 __ Bind(&done); 2142 return done.PhiAt(0); 2143 } 2144 2145 Node* EffectControlLinearizer::LowerObjectIsConstructor(Node* node) { 2146 Node* value = node->InputAt(0); 2147 2148 auto if_smi = __ MakeDeferredLabel(); 2149 auto done = __ MakeLabel(MachineRepresentation::kBit); 2150 2151 Node* check = ObjectIsSmi(value); 2152 __ GotoIf(check, &if_smi); 2153 2154 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2155 Node* value_bit_field = 2156 __ LoadField(AccessBuilder::ForMapBitField(), value_map); 2157 Node* vfalse = __ Word32Equal( 2158 __ Int32Constant(Map::IsConstructorBit::kMask), 2159 __ Word32And(value_bit_field, 2160 __ Int32Constant(Map::IsConstructorBit::kMask))); 2161 __ Goto(&done, vfalse); 2162 2163 __ Bind(&if_smi); 2164 __ Goto(&done, __ Int32Constant(0)); 2165 2166 __ Bind(&done); 2167 return done.PhiAt(0); 2168 } 2169 2170 Node* EffectControlLinearizer::LowerObjectIsDetectableCallable(Node* node) { 2171 Node* value = node->InputAt(0); 2172 2173 auto if_smi = __ MakeDeferredLabel(); 2174 auto done = __ MakeLabel(MachineRepresentation::kBit); 2175 2176 Node* check = ObjectIsSmi(value); 2177 __ GotoIf(check, &if_smi); 2178 2179 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2180 Node* value_bit_field = 2181 __ LoadField(AccessBuilder::ForMapBitField(), value_map); 2182 Node* vfalse = __ Word32Equal( 2183 __ Int32Constant(Map::IsCallableBit::kMask), 2184 __ Word32And(value_bit_field, 2185 __ Int32Constant((Map::IsCallableBit::kMask) | 2186 (Map::IsUndetectableBit::kMask)))); 2187 __ Goto(&done, vfalse); 2188 2189 __ Bind(&if_smi); 2190 __ Goto(&done, __ Int32Constant(0)); 2191 2192 __ Bind(&done); 2193 return done.PhiAt(0); 2194 } 2195 2196 Node* EffectControlLinearizer::LowerNumberIsFloat64Hole(Node* node) { 2197 Node* value = node->InputAt(0); 2198 Node* check = __ Word32Equal(__ Float64ExtractHighWord32(value), 2199 __ Int32Constant(kHoleNanUpper32)); 2200 return check; 2201 } 2202 2203 Node* EffectControlLinearizer::LowerNumberIsFinite(Node* node) { 2204 Node* number = node->InputAt(0); 2205 Node* diff = __ Float64Sub(number, number); 2206 Node* check = __ Float64Equal(diff, diff); 2207 return check; 2208 } 2209 2210 Node* EffectControlLinearizer::LowerObjectIsFiniteNumber(Node* node) { 2211 Node* object = node->InputAt(0); 2212 Node* zero = __ Int32Constant(0); 2213 Node* one = __ Int32Constant(1); 2214 2215 auto done = __ MakeLabel(MachineRepresentation::kBit); 2216 2217 // Check if {object} is a Smi. 2218 __ GotoIf(ObjectIsSmi(object), &done, one); 2219 2220 // Check if {object} is a HeapNumber. 2221 Node* value_map = __ LoadField(AccessBuilder::ForMap(), object); 2222 __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done, 2223 zero); 2224 2225 // {object} is a HeapNumber. 2226 Node* value = __ LoadField(AccessBuilder::ForHeapNumberValue(), object); 2227 Node* diff = __ Float64Sub(value, value); 2228 Node* check = __ Float64Equal(diff, diff); 2229 __ Goto(&done, check); 2230 2231 __ Bind(&done); 2232 return done.PhiAt(0); 2233 } 2234 2235 Node* EffectControlLinearizer::LowerNumberIsInteger(Node* node) { 2236 Node* number = node->InputAt(0); 2237 Node* trunc = BuildFloat64RoundTruncate(number); 2238 Node* diff = __ Float64Sub(number, trunc); 2239 Node* check = __ Float64Equal(diff, __ Float64Constant(0)); 2240 return check; 2241 } 2242 2243 Node* EffectControlLinearizer::LowerObjectIsInteger(Node* node) { 2244 Node* object = node->InputAt(0); 2245 Node* zero = __ Int32Constant(0); 2246 Node* one = __ Int32Constant(1); 2247 2248 auto done = __ MakeLabel(MachineRepresentation::kBit); 2249 2250 // Check if {object} is a Smi. 2251 __ GotoIf(ObjectIsSmi(object), &done, one); 2252 2253 // Check if {object} is a HeapNumber. 2254 Node* value_map = __ LoadField(AccessBuilder::ForMap(), object); 2255 __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done, 2256 zero); 2257 2258 // {object} is a HeapNumber. 2259 Node* value = __ LoadField(AccessBuilder::ForHeapNumberValue(), object); 2260 Node* trunc = BuildFloat64RoundTruncate(value); 2261 Node* diff = __ Float64Sub(value, trunc); 2262 Node* check = __ Float64Equal(diff, __ Float64Constant(0)); 2263 __ Goto(&done, check); 2264 2265 __ Bind(&done); 2266 return done.PhiAt(0); 2267 } 2268 2269 Node* EffectControlLinearizer::LowerNumberIsSafeInteger(Node* node) { 2270 Node* number = node->InputAt(0); 2271 Node* zero = __ Int32Constant(0); 2272 auto done = __ MakeLabel(MachineRepresentation::kBit); 2273 2274 Node* trunc = BuildFloat64RoundTruncate(number); 2275 Node* diff = __ Float64Sub(number, trunc); 2276 Node* check = __ Float64Equal(diff, __ Float64Constant(0)); 2277 __ GotoIfNot(check, &done, zero); 2278 Node* in_range = __ Float64LessThanOrEqual( 2279 __ Float64Abs(trunc), __ Float64Constant(kMaxSafeInteger)); 2280 __ Goto(&done, in_range); 2281 2282 __ Bind(&done); 2283 return done.PhiAt(0); 2284 } 2285 2286 Node* EffectControlLinearizer::LowerObjectIsSafeInteger(Node* node) { 2287 Node* object = node->InputAt(0); 2288 Node* zero = __ Int32Constant(0); 2289 Node* one = __ Int32Constant(1); 2290 2291 auto done = __ MakeLabel(MachineRepresentation::kBit); 2292 2293 // Check if {object} is a Smi. 2294 __ GotoIf(ObjectIsSmi(object), &done, one); 2295 2296 // Check if {object} is a HeapNumber. 2297 Node* value_map = __ LoadField(AccessBuilder::ForMap(), object); 2298 __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done, 2299 zero); 2300 2301 // {object} is a HeapNumber. 2302 Node* value = __ LoadField(AccessBuilder::ForHeapNumberValue(), object); 2303 Node* trunc = BuildFloat64RoundTruncate(value); 2304 Node* diff = __ Float64Sub(value, trunc); 2305 Node* check = __ Float64Equal(diff, __ Float64Constant(0)); 2306 __ GotoIfNot(check, &done, zero); 2307 Node* in_range = __ Float64LessThanOrEqual( 2308 __ Float64Abs(trunc), __ Float64Constant(kMaxSafeInteger)); 2309 __ Goto(&done, in_range); 2310 2311 __ Bind(&done); 2312 return done.PhiAt(0); 2313 } 2314 2315 Node* EffectControlLinearizer::LowerObjectIsMinusZero(Node* node) { 2316 Node* value = node->InputAt(0); 2317 Node* zero = __ Int32Constant(0); 2318 2319 auto done = __ MakeLabel(MachineRepresentation::kBit); 2320 2321 // Check if {value} is a Smi. 2322 __ GotoIf(ObjectIsSmi(value), &done, zero); 2323 2324 // Check if {value} is a HeapNumber. 2325 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2326 __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done, 2327 zero); 2328 2329 // Check if {value} contains -0. 2330 Node* value_value = __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 2331 __ Goto(&done, 2332 __ Float64Equal( 2333 __ Float64Div(__ Float64Constant(1.0), value_value), 2334 __ Float64Constant(-std::numeric_limits<double>::infinity()))); 2335 2336 __ Bind(&done); 2337 return done.PhiAt(0); 2338 } 2339 2340 Node* EffectControlLinearizer::LowerObjectIsNaN(Node* node) { 2341 Node* value = node->InputAt(0); 2342 Node* zero = __ Int32Constant(0); 2343 2344 auto done = __ MakeLabel(MachineRepresentation::kBit); 2345 2346 // Check if {value} is a Smi. 2347 __ GotoIf(ObjectIsSmi(value), &done, zero); 2348 2349 // Check if {value} is a HeapNumber. 2350 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2351 __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done, 2352 zero); 2353 2354 // Check if {value} contains a NaN. 2355 Node* value_value = __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 2356 __ Goto(&done, 2357 __ Word32Equal(__ Float64Equal(value_value, value_value), zero)); 2358 2359 __ Bind(&done); 2360 return done.PhiAt(0); 2361 } 2362 2363 Node* EffectControlLinearizer::LowerNumberIsNaN(Node* node) { 2364 Node* number = node->InputAt(0); 2365 Node* diff = __ Float64Equal(number, number); 2366 Node* check = __ Word32Equal(diff, __ Int32Constant(0)); 2367 return check; 2368 } 2369 2370 Node* EffectControlLinearizer::LowerObjectIsNonCallable(Node* node) { 2371 Node* value = node->InputAt(0); 2372 2373 auto if_primitive = __ MakeDeferredLabel(); 2374 auto done = __ MakeLabel(MachineRepresentation::kBit); 2375 2376 Node* check0 = ObjectIsSmi(value); 2377 __ GotoIf(check0, &if_primitive); 2378 2379 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2380 Node* value_instance_type = 2381 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 2382 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 2383 Node* check1 = __ Uint32LessThanOrEqual( 2384 __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type); 2385 __ GotoIfNot(check1, &if_primitive); 2386 2387 Node* value_bit_field = 2388 __ LoadField(AccessBuilder::ForMapBitField(), value_map); 2389 Node* check2 = 2390 __ Word32Equal(__ Int32Constant(0), 2391 __ Word32And(value_bit_field, 2392 __ Int32Constant(Map::IsCallableBit::kMask))); 2393 __ Goto(&done, check2); 2394 2395 __ Bind(&if_primitive); 2396 __ Goto(&done, __ Int32Constant(0)); 2397 2398 __ Bind(&done); 2399 return done.PhiAt(0); 2400 } 2401 2402 Node* EffectControlLinearizer::LowerObjectIsNumber(Node* node) { 2403 Node* value = node->InputAt(0); 2404 2405 auto if_smi = __ MakeLabel(); 2406 auto done = __ MakeLabel(MachineRepresentation::kBit); 2407 2408 __ GotoIf(ObjectIsSmi(value), &if_smi); 2409 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2410 __ Goto(&done, __ WordEqual(value_map, __ HeapNumberMapConstant())); 2411 2412 __ Bind(&if_smi); 2413 __ Goto(&done, __ Int32Constant(1)); 2414 2415 __ Bind(&done); 2416 return done.PhiAt(0); 2417 } 2418 2419 Node* EffectControlLinearizer::LowerObjectIsReceiver(Node* node) { 2420 Node* value = node->InputAt(0); 2421 2422 auto if_smi = __ MakeDeferredLabel(); 2423 auto done = __ MakeLabel(MachineRepresentation::kBit); 2424 2425 __ GotoIf(ObjectIsSmi(value), &if_smi); 2426 2427 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 2428 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2429 Node* value_instance_type = 2430 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 2431 Node* result = __ Uint32LessThanOrEqual( 2432 __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type); 2433 __ Goto(&done, result); 2434 2435 __ Bind(&if_smi); 2436 __ Goto(&done, __ Int32Constant(0)); 2437 2438 __ Bind(&done); 2439 return done.PhiAt(0); 2440 } 2441 2442 Node* EffectControlLinearizer::LowerObjectIsSmi(Node* node) { 2443 Node* value = node->InputAt(0); 2444 return ObjectIsSmi(value); 2445 } 2446 2447 Node* EffectControlLinearizer::LowerObjectIsString(Node* node) { 2448 Node* value = node->InputAt(0); 2449 2450 auto if_smi = __ MakeDeferredLabel(); 2451 auto done = __ MakeLabel(MachineRepresentation::kBit); 2452 2453 Node* check = ObjectIsSmi(value); 2454 __ GotoIf(check, &if_smi); 2455 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2456 Node* value_instance_type = 2457 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 2458 Node* vfalse = __ Uint32LessThan(value_instance_type, 2459 __ Uint32Constant(FIRST_NONSTRING_TYPE)); 2460 __ Goto(&done, vfalse); 2461 2462 __ Bind(&if_smi); 2463 __ Goto(&done, __ Int32Constant(0)); 2464 2465 __ Bind(&done); 2466 return done.PhiAt(0); 2467 } 2468 2469 Node* EffectControlLinearizer::LowerObjectIsSymbol(Node* node) { 2470 Node* value = node->InputAt(0); 2471 2472 auto if_smi = __ MakeDeferredLabel(); 2473 auto done = __ MakeLabel(MachineRepresentation::kBit); 2474 2475 Node* check = ObjectIsSmi(value); 2476 __ GotoIf(check, &if_smi); 2477 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2478 Node* value_instance_type = 2479 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 2480 Node* vfalse = 2481 __ Word32Equal(value_instance_type, __ Uint32Constant(SYMBOL_TYPE)); 2482 __ Goto(&done, vfalse); 2483 2484 __ Bind(&if_smi); 2485 __ Goto(&done, __ Int32Constant(0)); 2486 2487 __ Bind(&done); 2488 return done.PhiAt(0); 2489 } 2490 2491 Node* EffectControlLinearizer::LowerObjectIsUndetectable(Node* node) { 2492 Node* value = node->InputAt(0); 2493 2494 auto if_smi = __ MakeDeferredLabel(); 2495 auto done = __ MakeLabel(MachineRepresentation::kBit); 2496 2497 Node* check = ObjectIsSmi(value); 2498 __ GotoIf(check, &if_smi); 2499 2500 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 2501 Node* value_bit_field = 2502 __ LoadField(AccessBuilder::ForMapBitField(), value_map); 2503 Node* vfalse = __ Word32Equal( 2504 __ Word32Equal( 2505 __ Int32Constant(0), 2506 __ Word32And(value_bit_field, 2507 __ Int32Constant(Map::IsUndetectableBit::kMask))), 2508 __ Int32Constant(0)); 2509 __ Goto(&done, vfalse); 2510 2511 __ Bind(&if_smi); 2512 __ Goto(&done, __ Int32Constant(0)); 2513 2514 __ Bind(&done); 2515 return done.PhiAt(0); 2516 } 2517 2518 Node* EffectControlLinearizer::LowerTypeOf(Node* node) { 2519 Node* obj = node->InputAt(0); 2520 Callable const callable = Builtins::CallableFor(isolate(), Builtins::kTypeof); 2521 Operator::Properties const properties = Operator::kEliminatable; 2522 CallDescriptor::Flags const flags = CallDescriptor::kNoAllocate; 2523 auto call_descriptor = Linkage::GetStubCallDescriptor( 2524 graph()->zone(), callable.descriptor(), 0, flags, properties); 2525 return __ Call(call_descriptor, __ HeapConstant(callable.code()), obj, 2526 __ NoContextConstant()); 2527 } 2528 2529 Node* EffectControlLinearizer::LowerToBoolean(Node* node) { 2530 Node* obj = node->InputAt(0); 2531 Callable const callable = 2532 Builtins::CallableFor(isolate(), Builtins::kToBoolean); 2533 Operator::Properties const properties = Operator::kEliminatable; 2534 CallDescriptor::Flags const flags = CallDescriptor::kNoAllocate; 2535 auto call_descriptor = Linkage::GetStubCallDescriptor( 2536 graph()->zone(), callable.descriptor(), 0, flags, properties); 2537 return __ Call(call_descriptor, __ HeapConstant(callable.code()), obj, 2538 __ NoContextConstant()); 2539 } 2540 2541 Node* EffectControlLinearizer::LowerArgumentsLength(Node* node) { 2542 Node* arguments_frame = NodeProperties::GetValueInput(node, 0); 2543 int formal_parameter_count = FormalParameterCountOf(node->op()); 2544 bool is_rest_length = IsRestLengthOf(node->op()); 2545 DCHECK_LE(0, formal_parameter_count); 2546 2547 if (is_rest_length) { 2548 // The ArgumentsLength node is computing the number of rest parameters, 2549 // which is max(0, actual_parameter_count - formal_parameter_count). 2550 // We have to distinguish the case, when there is an arguments adaptor frame 2551 // (i.e., arguments_frame != LoadFramePointer()). 2552 auto if_adaptor_frame = __ MakeLabel(); 2553 auto done = __ MakeLabel(MachineRepresentation::kTaggedSigned); 2554 2555 Node* frame = __ LoadFramePointer(); 2556 __ GotoIf(__ WordEqual(arguments_frame, frame), &done, __ SmiConstant(0)); 2557 __ Goto(&if_adaptor_frame); 2558 2559 __ Bind(&if_adaptor_frame); 2560 Node* arguments_length = __ Load( 2561 MachineType::TaggedSigned(), arguments_frame, 2562 __ IntPtrConstant(ArgumentsAdaptorFrameConstants::kLengthOffset)); 2563 2564 Node* rest_length = 2565 __ IntSub(arguments_length, __ SmiConstant(formal_parameter_count)); 2566 __ GotoIf(__ IntLessThan(rest_length, __ SmiConstant(0)), &done, 2567 __ SmiConstant(0)); 2568 __ Goto(&done, rest_length); 2569 2570 __ Bind(&done); 2571 return done.PhiAt(0); 2572 } else { 2573 // The ArgumentsLength node is computing the actual number of arguments. 2574 // We have to distinguish the case when there is an arguments adaptor frame 2575 // (i.e., arguments_frame != LoadFramePointer()). 2576 auto if_adaptor_frame = __ MakeLabel(); 2577 auto done = __ MakeLabel(MachineRepresentation::kTaggedSigned); 2578 2579 Node* frame = __ LoadFramePointer(); 2580 __ GotoIf(__ WordEqual(arguments_frame, frame), &done, 2581 __ SmiConstant(formal_parameter_count)); 2582 __ Goto(&if_adaptor_frame); 2583 2584 __ Bind(&if_adaptor_frame); 2585 Node* arguments_length = __ Load( 2586 MachineType::TaggedSigned(), arguments_frame, 2587 __ IntPtrConstant(ArgumentsAdaptorFrameConstants::kLengthOffset)); 2588 __ Goto(&done, arguments_length); 2589 2590 __ Bind(&done); 2591 return done.PhiAt(0); 2592 } 2593 } 2594 2595 Node* EffectControlLinearizer::LowerArgumentsFrame(Node* node) { 2596 auto done = __ MakeLabel(MachineType::PointerRepresentation()); 2597 2598 Node* frame = __ LoadFramePointer(); 2599 Node* parent_frame = 2600 __ Load(MachineType::AnyTagged(), frame, 2601 __ IntPtrConstant(StandardFrameConstants::kCallerFPOffset)); 2602 Node* parent_frame_type = __ Load( 2603 MachineType::AnyTagged(), parent_frame, 2604 __ IntPtrConstant(CommonFrameConstants::kContextOrFrameTypeOffset)); 2605 __ GotoIf(__ WordEqual(parent_frame_type, 2606 __ IntPtrConstant(StackFrame::TypeToMarker( 2607 StackFrame::ARGUMENTS_ADAPTOR))), 2608 &done, parent_frame); 2609 __ Goto(&done, frame); 2610 2611 __ Bind(&done); 2612 return done.PhiAt(0); 2613 } 2614 2615 Node* EffectControlLinearizer::LowerNewDoubleElements(Node* node) { 2616 PretenureFlag const pretenure = PretenureFlagOf(node->op()); 2617 Node* length = node->InputAt(0); 2618 2619 auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer); 2620 Node* zero_length = __ Word32Equal(length, __ Int32Constant(0)); 2621 __ GotoIf(zero_length, &done, 2622 jsgraph()->HeapConstant(factory()->empty_fixed_array())); 2623 2624 // Compute the effective size of the backing store. 2625 Node* size = 2626 __ Int32Add(__ Word32Shl(length, __ Int32Constant(kDoubleSizeLog2)), 2627 __ Int32Constant(FixedDoubleArray::kHeaderSize)); 2628 2629 // Allocate the result and initialize the header. 2630 Node* result = __ Allocate(pretenure, size); 2631 __ StoreField(AccessBuilder::ForMap(), result, 2632 __ FixedDoubleArrayMapConstant()); 2633 __ StoreField(AccessBuilder::ForFixedArrayLength(), result, 2634 ChangeInt32ToSmi(length)); 2635 2636 // Initialize the backing store with holes. 2637 STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); 2638 Node* limit = ChangeUint32ToUintPtr(length); 2639 Node* the_hole = 2640 __ LoadField(AccessBuilder::ForHeapNumberValue(), __ TheHoleConstant()); 2641 auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation()); 2642 __ Goto(&loop, __ IntPtrConstant(0)); 2643 __ Bind(&loop); 2644 { 2645 // Check if we've initialized everything. 2646 Node* index = loop.PhiAt(0); 2647 Node* check = __ UintLessThan(index, limit); 2648 __ GotoIfNot(check, &done, result); 2649 2650 // Storing "the_hole" doesn't need a write barrier. 2651 StoreRepresentation rep(MachineRepresentation::kFloat64, kNoWriteBarrier); 2652 Node* offset = __ IntAdd( 2653 __ WordShl(index, __ IntPtrConstant(kDoubleSizeLog2)), 2654 __ IntPtrConstant(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); 2655 __ Store(rep, result, offset, the_hole); 2656 2657 // Advance the {index}. 2658 index = __ IntAdd(index, __ IntPtrConstant(1)); 2659 __ Goto(&loop, index); 2660 } 2661 2662 __ Bind(&done); 2663 return done.PhiAt(0); 2664 } 2665 2666 Node* EffectControlLinearizer::LowerNewSmiOrObjectElements(Node* node) { 2667 PretenureFlag const pretenure = PretenureFlagOf(node->op()); 2668 Node* length = node->InputAt(0); 2669 2670 auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer); 2671 Node* zero_length = __ Word32Equal(length, __ Int32Constant(0)); 2672 __ GotoIf(zero_length, &done, 2673 jsgraph()->HeapConstant(factory()->empty_fixed_array())); 2674 2675 // Compute the effective size of the backing store. 2676 Node* size = 2677 __ Int32Add(__ Word32Shl(length, __ Int32Constant(kPointerSizeLog2)), 2678 __ Int32Constant(FixedArray::kHeaderSize)); 2679 2680 // Allocate the result and initialize the header. 2681 Node* result = __ Allocate(pretenure, size); 2682 __ StoreField(AccessBuilder::ForMap(), result, __ FixedArrayMapConstant()); 2683 __ StoreField(AccessBuilder::ForFixedArrayLength(), result, 2684 ChangeInt32ToSmi(length)); 2685 2686 // Initialize the backing store with holes. 2687 Node* limit = ChangeUint32ToUintPtr(length); 2688 Node* the_hole = __ TheHoleConstant(); 2689 auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation()); 2690 __ Goto(&loop, __ IntPtrConstant(0)); 2691 __ Bind(&loop); 2692 { 2693 // Check if we've initialized everything. 2694 Node* index = loop.PhiAt(0); 2695 Node* check = __ UintLessThan(index, limit); 2696 __ GotoIfNot(check, &done, result); 2697 2698 // Storing "the_hole" doesn't need a write barrier. 2699 StoreRepresentation rep(MachineRepresentation::kTagged, kNoWriteBarrier); 2700 Node* offset = 2701 __ IntAdd(__ WordShl(index, __ IntPtrConstant(kPointerSizeLog2)), 2702 __ IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag)); 2703 __ Store(rep, result, offset, the_hole); 2704 2705 // Advance the {index}. 2706 index = __ IntAdd(index, __ IntPtrConstant(1)); 2707 __ Goto(&loop, index); 2708 } 2709 2710 __ Bind(&done); 2711 return done.PhiAt(0); 2712 } 2713 2714 Node* EffectControlLinearizer::LowerNewArgumentsElements(Node* node) { 2715 Node* frame = NodeProperties::GetValueInput(node, 0); 2716 Node* length = NodeProperties::GetValueInput(node, 1); 2717 int mapped_count = NewArgumentsElementsMappedCountOf(node->op()); 2718 2719 Callable const callable = 2720 Builtins::CallableFor(isolate(), Builtins::kNewArgumentsElements); 2721 Operator::Properties const properties = node->op()->properties(); 2722 CallDescriptor::Flags const flags = CallDescriptor::kNoFlags; 2723 auto call_descriptor = Linkage::GetStubCallDescriptor( 2724 graph()->zone(), callable.descriptor(), 0, flags, properties); 2725 return __ Call(call_descriptor, __ HeapConstant(callable.code()), frame, 2726 length, __ SmiConstant(mapped_count), __ NoContextConstant()); 2727 } 2728 2729 Node* EffectControlLinearizer::LowerNewConsString(Node* node) { 2730 Node* length = node->InputAt(0); 2731 Node* first = node->InputAt(1); 2732 Node* second = node->InputAt(2); 2733 2734 // Determine the instance types of {first} and {second}. 2735 Node* first_map = __ LoadField(AccessBuilder::ForMap(), first); 2736 Node* first_instance_type = 2737 __ LoadField(AccessBuilder::ForMapInstanceType(), first_map); 2738 Node* second_map = __ LoadField(AccessBuilder::ForMap(), second); 2739 Node* second_instance_type = 2740 __ LoadField(AccessBuilder::ForMapInstanceType(), second_map); 2741 2742 // Determine the proper map for the resulting ConsString. 2743 // If both {first} and {second} are one-byte strings, we 2744 // create a new ConsOneByteString, otherwise we create a 2745 // new ConsString instead. 2746 auto if_onebyte = __ MakeLabel(); 2747 auto if_twobyte = __ MakeLabel(); 2748 auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer); 2749 STATIC_ASSERT(kOneByteStringTag != 0); 2750 STATIC_ASSERT(kTwoByteStringTag == 0); 2751 Node* instance_type = __ Word32And(first_instance_type, second_instance_type); 2752 Node* encoding = 2753 __ Word32And(instance_type, __ Int32Constant(kStringEncodingMask)); 2754 __ Branch(__ Word32Equal(encoding, __ Int32Constant(kTwoByteStringTag)), 2755 &if_twobyte, &if_onebyte); 2756 __ Bind(&if_onebyte); 2757 __ Goto(&done, 2758 jsgraph()->HeapConstant(factory()->cons_one_byte_string_map())); 2759 __ Bind(&if_twobyte); 2760 __ Goto(&done, jsgraph()->HeapConstant(factory()->cons_string_map())); 2761 __ Bind(&done); 2762 Node* result_map = done.PhiAt(0); 2763 2764 // Allocate the resulting ConsString. 2765 Node* result = __ Allocate(NOT_TENURED, __ Int32Constant(ConsString::kSize)); 2766 __ StoreField(AccessBuilder::ForMap(), result, result_map); 2767 __ StoreField(AccessBuilder::ForNameHashField(), result, 2768 jsgraph()->Int32Constant(Name::kEmptyHashField)); 2769 __ StoreField(AccessBuilder::ForStringLength(), result, length); 2770 __ StoreField(AccessBuilder::ForConsStringFirst(), result, first); 2771 __ StoreField(AccessBuilder::ForConsStringSecond(), result, second); 2772 return result; 2773 } 2774 2775 Node* EffectControlLinearizer::LowerArrayBufferWasNeutered(Node* node) { 2776 Node* value = node->InputAt(0); 2777 2778 Node* value_bit_field = 2779 __ LoadField(AccessBuilder::ForJSArrayBufferBitField(), value); 2780 return __ Word32Equal( 2781 __ Word32Equal( 2782 __ Word32And(value_bit_field, 2783 __ Int32Constant(JSArrayBuffer::WasNeutered::kMask)), 2784 __ Int32Constant(0)), 2785 __ Int32Constant(0)); 2786 } 2787 2788 Node* EffectControlLinearizer::LowerSameValue(Node* node) { 2789 Node* lhs = node->InputAt(0); 2790 Node* rhs = node->InputAt(1); 2791 2792 Callable const callable = 2793 Builtins::CallableFor(isolate(), Builtins::kSameValue); 2794 Operator::Properties properties = Operator::kEliminatable; 2795 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 2796 auto call_descriptor = Linkage::GetStubCallDescriptor( 2797 graph()->zone(), callable.descriptor(), 0, flags, properties); 2798 return __ Call(call_descriptor, __ HeapConstant(callable.code()), lhs, rhs, 2799 __ NoContextConstant()); 2800 } 2801 2802 Node* EffectControlLinearizer::LowerDeadValue(Node* node) { 2803 Node* input = NodeProperties::GetValueInput(node, 0); 2804 if (input->opcode() != IrOpcode::kUnreachable) { 2805 Node* unreachable = __ Unreachable(); 2806 NodeProperties::ReplaceValueInput(node, unreachable, 0); 2807 } 2808 return node; 2809 } 2810 2811 Node* EffectControlLinearizer::LowerStringToNumber(Node* node) { 2812 Node* string = node->InputAt(0); 2813 2814 Callable const callable = 2815 Builtins::CallableFor(isolate(), Builtins::kStringToNumber); 2816 Operator::Properties properties = Operator::kEliminatable; 2817 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 2818 auto call_descriptor = Linkage::GetStubCallDescriptor( 2819 graph()->zone(), callable.descriptor(), 0, flags, properties); 2820 return __ Call(call_descriptor, __ HeapConstant(callable.code()), string, 2821 __ NoContextConstant()); 2822 } 2823 2824 Node* EffectControlLinearizer::LowerStringCharCodeAt(Node* node) { 2825 Node* receiver = node->InputAt(0); 2826 Node* position = node->InputAt(1); 2827 2828 // We need a loop here to properly deal with indirect strings 2829 // (SlicedString, ConsString and ThinString). 2830 auto loop = __ MakeLoopLabel(MachineRepresentation::kTagged, 2831 MachineRepresentation::kWord32); 2832 auto loop_next = __ MakeLabel(MachineRepresentation::kTagged, 2833 MachineRepresentation::kWord32); 2834 auto loop_done = __ MakeLabel(MachineRepresentation::kWord32); 2835 __ Goto(&loop, receiver, position); 2836 __ Bind(&loop); 2837 { 2838 Node* receiver = loop.PhiAt(0); 2839 Node* position = loop.PhiAt(1); 2840 Node* receiver_map = __ LoadField(AccessBuilder::ForMap(), receiver); 2841 Node* receiver_instance_type = 2842 __ LoadField(AccessBuilder::ForMapInstanceType(), receiver_map); 2843 Node* receiver_representation = __ Word32And( 2844 receiver_instance_type, __ Int32Constant(kStringRepresentationMask)); 2845 2846 // Dispatch on the current {receiver}s string representation. 2847 auto if_seqstring = __ MakeLabel(); 2848 auto if_consstring = __ MakeLabel(); 2849 auto if_thinstring = __ MakeLabel(); 2850 auto if_externalstring = __ MakeLabel(); 2851 auto if_slicedstring = __ MakeLabel(); 2852 auto if_runtime = __ MakeDeferredLabel(); 2853 __ GotoIf(__ Word32Equal(receiver_representation, 2854 __ Int32Constant(kSeqStringTag)), 2855 &if_seqstring); 2856 __ GotoIf(__ Word32Equal(receiver_representation, 2857 __ Int32Constant(kConsStringTag)), 2858 &if_consstring); 2859 __ GotoIf(__ Word32Equal(receiver_representation, 2860 __ Int32Constant(kThinStringTag)), 2861 &if_thinstring); 2862 __ GotoIf(__ Word32Equal(receiver_representation, 2863 __ Int32Constant(kExternalStringTag)), 2864 &if_externalstring); 2865 __ Branch(__ Word32Equal(receiver_representation, 2866 __ Int32Constant(kSlicedStringTag)), 2867 &if_slicedstring, &if_runtime); 2868 2869 __ Bind(&if_seqstring); 2870 { 2871 Node* receiver_is_onebyte = __ Word32Equal( 2872 __ Word32Equal(__ Word32And(receiver_instance_type, 2873 __ Int32Constant(kStringEncodingMask)), 2874 __ Int32Constant(kTwoByteStringTag)), 2875 __ Int32Constant(0)); 2876 Node* result = LoadFromSeqString(receiver, position, receiver_is_onebyte); 2877 __ Goto(&loop_done, result); 2878 } 2879 2880 __ Bind(&if_thinstring); 2881 { 2882 Node* receiver_actual = 2883 __ LoadField(AccessBuilder::ForThinStringActual(), receiver); 2884 __ Goto(&loop_next, receiver_actual, position); 2885 } 2886 2887 __ Bind(&if_consstring); 2888 { 2889 Node* receiver_second = 2890 __ LoadField(AccessBuilder::ForConsStringSecond(), receiver); 2891 __ GotoIfNot(__ WordEqual(receiver_second, __ EmptyStringConstant()), 2892 &if_runtime); 2893 Node* receiver_first = 2894 __ LoadField(AccessBuilder::ForConsStringFirst(), receiver); 2895 __ Goto(&loop_next, receiver_first, position); 2896 } 2897 2898 __ Bind(&if_externalstring); 2899 { 2900 // We need to bailout to the runtime for short external strings. 2901 __ GotoIf(__ Word32Equal( 2902 __ Word32And(receiver_instance_type, 2903 __ Int32Constant(kShortExternalStringMask)), 2904 __ Int32Constant(kShortExternalStringTag)), 2905 &if_runtime); 2906 2907 Node* receiver_data = __ LoadField( 2908 AccessBuilder::ForExternalStringResourceData(), receiver); 2909 2910 auto if_onebyte = __ MakeLabel(); 2911 auto if_twobyte = __ MakeLabel(); 2912 __ Branch( 2913 __ Word32Equal(__ Word32And(receiver_instance_type, 2914 __ Int32Constant(kStringEncodingMask)), 2915 __ Int32Constant(kTwoByteStringTag)), 2916 &if_twobyte, &if_onebyte); 2917 2918 __ Bind(&if_onebyte); 2919 { 2920 Node* result = __ Load(MachineType::Uint8(), receiver_data, 2921 ChangeInt32ToIntPtr(position)); 2922 __ Goto(&loop_done, result); 2923 } 2924 2925 __ Bind(&if_twobyte); 2926 { 2927 Node* result = __ Load( 2928 MachineType::Uint16(), receiver_data, 2929 __ Word32Shl(ChangeInt32ToIntPtr(position), __ Int32Constant(1))); 2930 __ Goto(&loop_done, result); 2931 } 2932 } 2933 2934 __ Bind(&if_slicedstring); 2935 { 2936 Node* receiver_offset = 2937 __ LoadField(AccessBuilder::ForSlicedStringOffset(), receiver); 2938 Node* receiver_parent = 2939 __ LoadField(AccessBuilder::ForSlicedStringParent(), receiver); 2940 __ Goto(&loop_next, receiver_parent, 2941 __ Int32Add(position, ChangeSmiToInt32(receiver_offset))); 2942 } 2943 2944 __ Bind(&if_runtime); 2945 { 2946 Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; 2947 Runtime::FunctionId id = Runtime::kStringCharCodeAt; 2948 auto call_descriptor = Linkage::GetRuntimeCallDescriptor( 2949 graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags); 2950 Node* result = __ Call(call_descriptor, __ CEntryStubConstant(1), 2951 receiver, ChangeInt32ToSmi(position), 2952 __ ExternalConstant(ExternalReference::Create(id)), 2953 __ Int32Constant(2), __ NoContextConstant()); 2954 __ Goto(&loop_done, ChangeSmiToInt32(result)); 2955 } 2956 2957 __ Bind(&loop_next); 2958 __ Goto(&loop, loop_next.PhiAt(0), loop_next.PhiAt(1)); 2959 } 2960 __ Bind(&loop_done); 2961 return loop_done.PhiAt(0); 2962 } 2963 2964 Node* EffectControlLinearizer::LowerStringCodePointAt( 2965 Node* node, UnicodeEncoding encoding) { 2966 Node* receiver = node->InputAt(0); 2967 Node* position = node->InputAt(1); 2968 2969 Builtins::Name builtin = encoding == UnicodeEncoding::UTF16 2970 ? Builtins::kStringCodePointAtUTF16 2971 : Builtins::kStringCodePointAtUTF32; 2972 2973 Callable const callable = Builtins::CallableFor(isolate(), builtin); 2974 Operator::Properties properties = Operator::kNoThrow | Operator::kNoWrite; 2975 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 2976 auto call_descriptor = Linkage::GetStubCallDescriptor( 2977 graph()->zone(), callable.descriptor(), 0, flags, properties); 2978 return __ Call(call_descriptor, __ HeapConstant(callable.code()), receiver, 2979 position, __ NoContextConstant()); 2980 } 2981 2982 Node* EffectControlLinearizer::LoadFromSeqString(Node* receiver, Node* position, 2983 Node* is_one_byte) { 2984 auto one_byte_load = __ MakeLabel(); 2985 auto done = __ MakeLabel(MachineRepresentation::kWord32); 2986 __ GotoIf(is_one_byte, &one_byte_load); 2987 Node* two_byte_result = __ LoadElement( 2988 AccessBuilder::ForSeqTwoByteStringCharacter(), receiver, position); 2989 __ Goto(&done, two_byte_result); 2990 2991 __ Bind(&one_byte_load); 2992 Node* one_byte_element = __ LoadElement( 2993 AccessBuilder::ForSeqOneByteStringCharacter(), receiver, position); 2994 __ Goto(&done, one_byte_element); 2995 2996 __ Bind(&done); 2997 return done.PhiAt(0); 2998 } 2999 3000 Node* EffectControlLinearizer::LowerStringFromSingleCharCode(Node* node) { 3001 Node* value = node->InputAt(0); 3002 Node* code = __ Word32And(value, __ Uint32Constant(0xFFFF)); 3003 3004 auto if_not_one_byte = __ MakeDeferredLabel(); 3005 auto cache_miss = __ MakeDeferredLabel(); 3006 auto done = __ MakeLabel(MachineRepresentation::kTagged); 3007 3008 // Check if the {code} is a one byte character 3009 Node* check1 = __ Uint32LessThanOrEqual( 3010 code, __ Uint32Constant(String::kMaxOneByteCharCode)); 3011 __ GotoIfNot(check1, &if_not_one_byte); 3012 { 3013 // Load the isolate wide single character string cache. 3014 Node* cache = __ HeapConstant(factory()->single_character_string_cache()); 3015 3016 // Compute the {cache} index for {code}. 3017 Node* index = machine()->Is32() ? code : __ ChangeUint32ToUint64(code); 3018 3019 // Check if we have an entry for the {code} in the single character string 3020 // cache already. 3021 Node* entry = 3022 __ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index); 3023 3024 Node* check2 = __ WordEqual(entry, __ UndefinedConstant()); 3025 __ GotoIf(check2, &cache_miss); 3026 3027 // Use the {entry} from the {cache}. 3028 __ Goto(&done, entry); 3029 3030 __ Bind(&cache_miss); 3031 { 3032 // Allocate a new SeqOneByteString for {code}. 3033 Node* vtrue2 = __ Allocate( 3034 NOT_TENURED, __ Int32Constant(SeqOneByteString::SizeFor(1))); 3035 __ StoreField(AccessBuilder::ForMap(), vtrue2, 3036 __ HeapConstant(factory()->one_byte_string_map())); 3037 __ StoreField(AccessBuilder::ForNameHashField(), vtrue2, 3038 __ IntPtrConstant(Name::kEmptyHashField)); 3039 __ StoreField(AccessBuilder::ForStringLength(), vtrue2, 3040 __ SmiConstant(1)); 3041 __ Store( 3042 StoreRepresentation(MachineRepresentation::kWord8, kNoWriteBarrier), 3043 vtrue2, 3044 __ IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), 3045 code); 3046 3047 // Remember it in the {cache}. 3048 __ StoreElement(AccessBuilder::ForFixedArrayElement(), cache, index, 3049 vtrue2); 3050 __ Goto(&done, vtrue2); 3051 } 3052 } 3053 3054 __ Bind(&if_not_one_byte); 3055 { 3056 // Allocate a new SeqTwoByteString for {code}. 3057 Node* vfalse1 = __ Allocate(NOT_TENURED, 3058 __ Int32Constant(SeqTwoByteString::SizeFor(1))); 3059 __ StoreField(AccessBuilder::ForMap(), vfalse1, 3060 __ HeapConstant(factory()->string_map())); 3061 __ StoreField(AccessBuilder::ForNameHashField(), vfalse1, 3062 __ IntPtrConstant(Name::kEmptyHashField)); 3063 __ StoreField(AccessBuilder::ForStringLength(), vfalse1, __ SmiConstant(1)); 3064 __ Store( 3065 StoreRepresentation(MachineRepresentation::kWord16, kNoWriteBarrier), 3066 vfalse1, 3067 __ IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), 3068 code); 3069 __ Goto(&done, vfalse1); 3070 } 3071 3072 __ Bind(&done); 3073 return done.PhiAt(0); 3074 } 3075 3076 #ifdef V8_INTL_SUPPORT 3077 3078 Node* EffectControlLinearizer::LowerStringToLowerCaseIntl(Node* node) { 3079 Node* receiver = node->InputAt(0); 3080 3081 Callable callable = 3082 Builtins::CallableFor(isolate(), Builtins::kStringToLowerCaseIntl); 3083 Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; 3084 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 3085 auto call_descriptor = Linkage::GetStubCallDescriptor( 3086 graph()->zone(), callable.descriptor(), 0, flags, properties); 3087 return __ Call(call_descriptor, __ HeapConstant(callable.code()), receiver, 3088 __ NoContextConstant()); 3089 } 3090 3091 Node* EffectControlLinearizer::LowerStringToUpperCaseIntl(Node* node) { 3092 Node* receiver = node->InputAt(0); 3093 Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; 3094 Runtime::FunctionId id = Runtime::kStringToUpperCaseIntl; 3095 auto call_descriptor = Linkage::GetRuntimeCallDescriptor( 3096 graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags); 3097 return __ Call(call_descriptor, __ CEntryStubConstant(1), receiver, 3098 __ ExternalConstant(ExternalReference::Create(id)), 3099 __ Int32Constant(1), __ NoContextConstant()); 3100 } 3101 3102 #else 3103 3104 Node* EffectControlLinearizer::LowerStringToLowerCaseIntl(Node* node) { 3105 UNREACHABLE(); 3106 return nullptr; 3107 } 3108 3109 Node* EffectControlLinearizer::LowerStringToUpperCaseIntl(Node* node) { 3110 UNREACHABLE(); 3111 return nullptr; 3112 } 3113 3114 #endif // V8_INTL_SUPPORT 3115 3116 Node* EffectControlLinearizer::LowerStringFromSingleCodePoint(Node* node) { 3117 Node* value = node->InputAt(0); 3118 Node* code = value; 3119 3120 auto if_not_single_code = __ MakeDeferredLabel(); 3121 auto if_not_one_byte = __ MakeDeferredLabel(); 3122 auto cache_miss = __ MakeDeferredLabel(); 3123 auto done = __ MakeLabel(MachineRepresentation::kTagged); 3124 3125 // Check if the {code} is a single code unit 3126 Node* check0 = __ Uint32LessThanOrEqual(code, __ Uint32Constant(0xFFFF)); 3127 __ GotoIfNot(check0, &if_not_single_code); 3128 3129 { 3130 // Check if the {code} is a one byte character 3131 Node* check1 = __ Uint32LessThanOrEqual( 3132 code, __ Uint32Constant(String::kMaxOneByteCharCode)); 3133 __ GotoIfNot(check1, &if_not_one_byte); 3134 { 3135 // Load the isolate wide single character string cache. 3136 Node* cache = __ HeapConstant(factory()->single_character_string_cache()); 3137 3138 // Compute the {cache} index for {code}. 3139 Node* index = machine()->Is32() ? code : __ ChangeUint32ToUint64(code); 3140 3141 // Check if we have an entry for the {code} in the single character string 3142 // cache already. 3143 Node* entry = 3144 __ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index); 3145 3146 Node* check2 = __ WordEqual(entry, __ UndefinedConstant()); 3147 __ GotoIf(check2, &cache_miss); 3148 3149 // Use the {entry} from the {cache}. 3150 __ Goto(&done, entry); 3151 3152 __ Bind(&cache_miss); 3153 { 3154 // Allocate a new SeqOneByteString for {code}. 3155 Node* vtrue2 = __ Allocate( 3156 NOT_TENURED, __ Int32Constant(SeqOneByteString::SizeFor(1))); 3157 __ StoreField(AccessBuilder::ForMap(), vtrue2, 3158 __ HeapConstant(factory()->one_byte_string_map())); 3159 __ StoreField(AccessBuilder::ForNameHashField(), vtrue2, 3160 __ IntPtrConstant(Name::kEmptyHashField)); 3161 __ StoreField(AccessBuilder::ForStringLength(), vtrue2, 3162 __ SmiConstant(1)); 3163 __ Store( 3164 StoreRepresentation(MachineRepresentation::kWord8, kNoWriteBarrier), 3165 vtrue2, 3166 __ IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), 3167 code); 3168 3169 // Remember it in the {cache}. 3170 __ StoreElement(AccessBuilder::ForFixedArrayElement(), cache, index, 3171 vtrue2); 3172 __ Goto(&done, vtrue2); 3173 } 3174 } 3175 3176 __ Bind(&if_not_one_byte); 3177 { 3178 // Allocate a new SeqTwoByteString for {code}. 3179 Node* vfalse1 = __ Allocate( 3180 NOT_TENURED, __ Int32Constant(SeqTwoByteString::SizeFor(1))); 3181 __ StoreField(AccessBuilder::ForMap(), vfalse1, 3182 __ HeapConstant(factory()->string_map())); 3183 __ StoreField(AccessBuilder::ForNameHashField(), vfalse1, 3184 __ IntPtrConstant(Name::kEmptyHashField)); 3185 __ StoreField(AccessBuilder::ForStringLength(), vfalse1, 3186 __ SmiConstant(1)); 3187 __ Store( 3188 StoreRepresentation(MachineRepresentation::kWord16, kNoWriteBarrier), 3189 vfalse1, 3190 __ IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), 3191 code); 3192 __ Goto(&done, vfalse1); 3193 } 3194 } 3195 3196 __ Bind(&if_not_single_code); 3197 // Generate surrogate pair string 3198 { 3199 switch (UnicodeEncodingOf(node->op())) { 3200 case UnicodeEncoding::UTF16: 3201 break; 3202 3203 case UnicodeEncoding::UTF32: { 3204 // Convert UTF32 to UTF16 code units, and store as a 32 bit word. 3205 Node* lead_offset = __ Int32Constant(0xD800 - (0x10000 >> 10)); 3206 3207 // lead = (codepoint >> 10) + LEAD_OFFSET 3208 Node* lead = 3209 __ Int32Add(__ Word32Shr(code, __ Int32Constant(10)), lead_offset); 3210 3211 // trail = (codepoint & 0x3FF) + 0xDC00; 3212 Node* trail = __ Int32Add(__ Word32And(code, __ Int32Constant(0x3FF)), 3213 __ Int32Constant(0xDC00)); 3214 3215 // codpoint = (trail << 16) | lead; 3216 #if V8_TARGET_BIG_ENDIAN 3217 code = __ Word32Or(__ Word32Shl(lead, __ Int32Constant(16)), trail); 3218 #else 3219 code = __ Word32Or(__ Word32Shl(trail, __ Int32Constant(16)), lead); 3220 #endif 3221 break; 3222 } 3223 } 3224 3225 // Allocate a new SeqTwoByteString for {code}. 3226 Node* vfalse0 = __ Allocate(NOT_TENURED, 3227 __ Int32Constant(SeqTwoByteString::SizeFor(2))); 3228 __ StoreField(AccessBuilder::ForMap(), vfalse0, 3229 __ HeapConstant(factory()->string_map())); 3230 __ StoreField(AccessBuilder::ForNameHashField(), vfalse0, 3231 __ IntPtrConstant(Name::kEmptyHashField)); 3232 __ StoreField(AccessBuilder::ForStringLength(), vfalse0, __ SmiConstant(2)); 3233 __ Store( 3234 StoreRepresentation(MachineRepresentation::kWord32, kNoWriteBarrier), 3235 vfalse0, 3236 __ IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), 3237 code); 3238 __ Goto(&done, vfalse0); 3239 } 3240 3241 __ Bind(&done); 3242 return done.PhiAt(0); 3243 } 3244 3245 Node* EffectControlLinearizer::LowerStringIndexOf(Node* node) { 3246 Node* subject = node->InputAt(0); 3247 Node* search_string = node->InputAt(1); 3248 Node* position = node->InputAt(2); 3249 3250 Callable callable = 3251 Builtins::CallableFor(isolate(), Builtins::kStringIndexOf); 3252 Operator::Properties properties = Operator::kEliminatable; 3253 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 3254 auto call_descriptor = Linkage::GetStubCallDescriptor( 3255 graph()->zone(), callable.descriptor(), 0, flags, properties); 3256 return __ Call(call_descriptor, __ HeapConstant(callable.code()), subject, 3257 search_string, position, __ NoContextConstant()); 3258 } 3259 3260 Node* EffectControlLinearizer::LowerStringLength(Node* node) { 3261 Node* subject = node->InputAt(0); 3262 3263 return __ LoadField(AccessBuilder::ForStringLength(), subject); 3264 } 3265 3266 Node* EffectControlLinearizer::LowerStringComparison(Callable const& callable, 3267 Node* node) { 3268 Node* lhs = node->InputAt(0); 3269 Node* rhs = node->InputAt(1); 3270 3271 Operator::Properties properties = Operator::kEliminatable; 3272 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 3273 auto call_descriptor = Linkage::GetStubCallDescriptor( 3274 graph()->zone(), callable.descriptor(), 0, flags, properties); 3275 return __ Call(call_descriptor, __ HeapConstant(callable.code()), lhs, rhs, 3276 __ NoContextConstant()); 3277 } 3278 3279 Node* EffectControlLinearizer::LowerStringSubstring(Node* node) { 3280 Node* receiver = node->InputAt(0); 3281 Node* start = ChangeInt32ToIntPtr(node->InputAt(1)); 3282 Node* end = ChangeInt32ToIntPtr(node->InputAt(2)); 3283 3284 Callable callable = 3285 Builtins::CallableFor(isolate(), Builtins::kStringSubstring); 3286 Operator::Properties properties = Operator::kEliminatable; 3287 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 3288 auto call_descriptor = Linkage::GetStubCallDescriptor( 3289 graph()->zone(), callable.descriptor(), 0, flags, properties); 3290 return __ Call(call_descriptor, __ HeapConstant(callable.code()), receiver, 3291 start, end, __ NoContextConstant()); 3292 } 3293 3294 Node* EffectControlLinearizer::LowerStringEqual(Node* node) { 3295 return LowerStringComparison( 3296 Builtins::CallableFor(isolate(), Builtins::kStringEqual), node); 3297 } 3298 3299 Node* EffectControlLinearizer::LowerStringLessThan(Node* node) { 3300 return LowerStringComparison( 3301 Builtins::CallableFor(isolate(), Builtins::kStringLessThan), node); 3302 } 3303 3304 Node* EffectControlLinearizer::LowerStringLessThanOrEqual(Node* node) { 3305 return LowerStringComparison( 3306 Builtins::CallableFor(isolate(), Builtins::kStringLessThanOrEqual), node); 3307 } 3308 3309 Node* EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, 3310 Node* frame_state) { 3311 // If we reach this point w/o eliminating the {node} that's marked 3312 // with allow-return-hole, we cannot do anything, so just deoptimize 3313 // in case of the hole NaN. 3314 CheckFloat64HoleParameters const& params = 3315 CheckFloat64HoleParametersOf(node->op()); 3316 Node* value = node->InputAt(0); 3317 Node* check = __ Word32Equal(__ Float64ExtractHighWord32(value), 3318 __ Int32Constant(kHoleNanUpper32)); 3319 __ DeoptimizeIf(DeoptimizeReason::kHole, params.feedback(), check, 3320 frame_state); 3321 return value; 3322 } 3323 3324 Node* EffectControlLinearizer::LowerCheckNotTaggedHole(Node* node, 3325 Node* frame_state) { 3326 Node* value = node->InputAt(0); 3327 Node* check = __ WordEqual(value, __ TheHoleConstant()); 3328 __ DeoptimizeIf(DeoptimizeReason::kHole, VectorSlotPair(), check, 3329 frame_state); 3330 return value; 3331 } 3332 3333 Node* EffectControlLinearizer::LowerConvertTaggedHoleToUndefined(Node* node) { 3334 Node* value = node->InputAt(0); 3335 3336 auto if_is_hole = __ MakeDeferredLabel(); 3337 auto done = __ MakeLabel(MachineRepresentation::kTagged); 3338 3339 Node* check = __ WordEqual(value, __ TheHoleConstant()); 3340 __ GotoIf(check, &if_is_hole); 3341 __ Goto(&done, value); 3342 3343 __ Bind(&if_is_hole); 3344 __ Goto(&done, __ UndefinedConstant()); 3345 3346 __ Bind(&done); 3347 return done.PhiAt(0); 3348 } 3349 3350 void EffectControlLinearizer::LowerCheckEqualsInternalizedString( 3351 Node* node, Node* frame_state) { 3352 Node* exp = node->InputAt(0); 3353 Node* val = node->InputAt(1); 3354 3355 auto if_same = __ MakeLabel(); 3356 auto if_notsame = __ MakeDeferredLabel(); 3357 auto if_thinstring = __ MakeLabel(); 3358 auto if_notthinstring = __ MakeLabel(); 3359 3360 // Check if {exp} and {val} are the same, which is the likely case. 3361 __ Branch(__ WordEqual(exp, val), &if_same, &if_notsame); 3362 3363 __ Bind(&if_notsame); 3364 { 3365 // Now {val} could still be a non-internalized String that matches {exp}. 3366 __ DeoptimizeIf(DeoptimizeReason::kWrongName, VectorSlotPair(), 3367 ObjectIsSmi(val), frame_state); 3368 Node* val_map = __ LoadField(AccessBuilder::ForMap(), val); 3369 Node* val_instance_type = 3370 __ LoadField(AccessBuilder::ForMapInstanceType(), val_map); 3371 3372 // Check for the common case of ThinString first. 3373 __ GotoIf(__ Word32Equal(val_instance_type, 3374 __ Int32Constant(THIN_ONE_BYTE_STRING_TYPE)), 3375 &if_thinstring); 3376 __ Branch( 3377 __ Word32Equal(val_instance_type, __ Int32Constant(THIN_STRING_TYPE)), 3378 &if_thinstring, &if_notthinstring); 3379 3380 __ Bind(&if_notthinstring); 3381 { 3382 // Check that the {val} is a non-internalized String, if it's anything 3383 // else it cannot match the recorded feedback {exp} anyways. 3384 __ DeoptimizeIfNot( 3385 DeoptimizeReason::kWrongName, VectorSlotPair(), 3386 __ Word32Equal(__ Word32And(val_instance_type, 3387 __ Int32Constant(kIsNotStringMask | 3388 kIsNotInternalizedMask)), 3389 __ Int32Constant(kStringTag | kNotInternalizedTag)), 3390 frame_state); 3391 3392 // Try to find the {val} in the string table. 3393 MachineSignature::Builder builder(graph()->zone(), 1, 2); 3394 builder.AddReturn(MachineType::AnyTagged()); 3395 builder.AddParam(MachineType::Pointer()); 3396 builder.AddParam(MachineType::AnyTagged()); 3397 Node* try_internalize_string_function = __ ExternalConstant( 3398 ExternalReference::try_internalize_string_function()); 3399 Node* const isolate_ptr = 3400 __ ExternalConstant(ExternalReference::isolate_address(isolate())); 3401 auto call_descriptor = 3402 Linkage::GetSimplifiedCDescriptor(graph()->zone(), builder.Build()); 3403 Node* val_internalized = 3404 __ Call(common()->Call(call_descriptor), 3405 try_internalize_string_function, isolate_ptr, val); 3406 3407 // Now see if the results match. 3408 __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, VectorSlotPair(), 3409 __ WordEqual(exp, val_internalized), frame_state); 3410 __ Goto(&if_same); 3411 } 3412 3413 __ Bind(&if_thinstring); 3414 { 3415 // The {val} is a ThinString, let's check the actual value. 3416 Node* val_actual = 3417 __ LoadField(AccessBuilder::ForThinStringActual(), val); 3418 __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, VectorSlotPair(), 3419 __ WordEqual(exp, val_actual), frame_state); 3420 __ Goto(&if_same); 3421 } 3422 } 3423 3424 __ Bind(&if_same); 3425 } 3426 3427 void EffectControlLinearizer::LowerCheckEqualsSymbol(Node* node, 3428 Node* frame_state) { 3429 Node* exp = node->InputAt(0); 3430 Node* val = node->InputAt(1); 3431 Node* check = __ WordEqual(exp, val); 3432 __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, VectorSlotPair(), check, 3433 frame_state); 3434 } 3435 3436 Node* EffectControlLinearizer::AllocateHeapNumberWithValue(Node* value) { 3437 Node* result = __ Allocate(NOT_TENURED, __ Int32Constant(HeapNumber::kSize)); 3438 __ StoreField(AccessBuilder::ForMap(), result, __ HeapNumberMapConstant()); 3439 __ StoreField(AccessBuilder::ForHeapNumberValue(), result, value); 3440 return result; 3441 } 3442 3443 Node* EffectControlLinearizer::ChangeInt32ToSmi(Node* value) { 3444 return __ WordShl(ChangeInt32ToIntPtr(value), SmiShiftBitsConstant()); 3445 } 3446 3447 Node* EffectControlLinearizer::ChangeInt32ToIntPtr(Node* value) { 3448 if (machine()->Is64()) { 3449 value = __ ChangeInt32ToInt64(value); 3450 } 3451 return value; 3452 } 3453 3454 Node* EffectControlLinearizer::ChangeIntPtrToInt32(Node* value) { 3455 if (machine()->Is64()) { 3456 value = __ TruncateInt64ToInt32(value); 3457 } 3458 return value; 3459 } 3460 3461 Node* EffectControlLinearizer::ChangeUint32ToUintPtr(Node* value) { 3462 if (machine()->Is64()) { 3463 value = __ ChangeUint32ToUint64(value); 3464 } 3465 return value; 3466 } 3467 3468 Node* EffectControlLinearizer::ChangeUint32ToSmi(Node* value) { 3469 value = ChangeUint32ToUintPtr(value); 3470 return __ WordShl(value, SmiShiftBitsConstant()); 3471 } 3472 3473 Node* EffectControlLinearizer::ChangeSmiToIntPtr(Node* value) { 3474 return __ WordSar(value, SmiShiftBitsConstant()); 3475 } 3476 3477 Node* EffectControlLinearizer::ChangeSmiToInt32(Node* value) { 3478 value = ChangeSmiToIntPtr(value); 3479 if (machine()->Is64()) { 3480 value = __ TruncateInt64ToInt32(value); 3481 } 3482 return value; 3483 } 3484 3485 Node* EffectControlLinearizer::ObjectIsSmi(Node* value) { 3486 return __ WordEqual(__ WordAnd(value, __ IntPtrConstant(kSmiTagMask)), 3487 __ IntPtrConstant(kSmiTag)); 3488 } 3489 3490 Node* EffectControlLinearizer::SmiMaxValueConstant() { 3491 return __ Int32Constant(Smi::kMaxValue); 3492 } 3493 3494 Node* EffectControlLinearizer::SmiShiftBitsConstant() { 3495 return __ IntPtrConstant(kSmiShiftSize + kSmiTagSize); 3496 } 3497 3498 Node* EffectControlLinearizer::LowerPlainPrimitiveToNumber(Node* node) { 3499 Node* value = node->InputAt(0); 3500 return __ ToNumber(value); 3501 } 3502 3503 Node* EffectControlLinearizer::LowerPlainPrimitiveToWord32(Node* node) { 3504 Node* value = node->InputAt(0); 3505 3506 auto if_not_smi = __ MakeDeferredLabel(); 3507 auto if_to_number_smi = __ MakeLabel(); 3508 auto done = __ MakeLabel(MachineRepresentation::kWord32); 3509 3510 Node* check0 = ObjectIsSmi(value); 3511 __ GotoIfNot(check0, &if_not_smi); 3512 __ Goto(&done, ChangeSmiToInt32(value)); 3513 3514 __ Bind(&if_not_smi); 3515 Node* to_number = __ ToNumber(value); 3516 3517 Node* check1 = ObjectIsSmi(to_number); 3518 __ GotoIf(check1, &if_to_number_smi); 3519 Node* number = __ LoadField(AccessBuilder::ForHeapNumberValue(), to_number); 3520 __ Goto(&done, __ TruncateFloat64ToWord32(number)); 3521 3522 __ Bind(&if_to_number_smi); 3523 __ Goto(&done, ChangeSmiToInt32(to_number)); 3524 3525 __ Bind(&done); 3526 return done.PhiAt(0); 3527 } 3528 3529 Node* EffectControlLinearizer::LowerPlainPrimitiveToFloat64(Node* node) { 3530 Node* value = node->InputAt(0); 3531 3532 auto if_not_smi = __ MakeDeferredLabel(); 3533 auto if_to_number_smi = __ MakeLabel(); 3534 auto done = __ MakeLabel(MachineRepresentation::kFloat64); 3535 3536 Node* check0 = ObjectIsSmi(value); 3537 __ GotoIfNot(check0, &if_not_smi); 3538 Node* from_smi = ChangeSmiToInt32(value); 3539 __ Goto(&done, __ ChangeInt32ToFloat64(from_smi)); 3540 3541 __ Bind(&if_not_smi); 3542 Node* to_number = __ ToNumber(value); 3543 Node* check1 = ObjectIsSmi(to_number); 3544 __ GotoIf(check1, &if_to_number_smi); 3545 3546 Node* number = __ LoadField(AccessBuilder::ForHeapNumberValue(), to_number); 3547 __ Goto(&done, number); 3548 3549 __ Bind(&if_to_number_smi); 3550 Node* number_from_smi = ChangeSmiToInt32(to_number); 3551 number_from_smi = __ ChangeInt32ToFloat64(number_from_smi); 3552 __ Goto(&done, number_from_smi); 3553 3554 __ Bind(&done); 3555 return done.PhiAt(0); 3556 } 3557 3558 Node* EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node) { 3559 Node* object = node->InputAt(0); 3560 Node* elements = node->InputAt(1); 3561 3562 auto if_not_fixed_array = __ MakeDeferredLabel(); 3563 auto done = __ MakeLabel(MachineRepresentation::kTagged); 3564 3565 // Load the current map of {elements}. 3566 Node* elements_map = __ LoadField(AccessBuilder::ForMap(), elements); 3567 3568 // Check if {elements} is not a copy-on-write FixedArray. 3569 Node* check = __ WordEqual(elements_map, __ FixedArrayMapConstant()); 3570 __ GotoIfNot(check, &if_not_fixed_array); 3571 // Nothing to do if the {elements} are not copy-on-write. 3572 __ Goto(&done, elements); 3573 3574 __ Bind(&if_not_fixed_array); 3575 // We need to take a copy of the {elements} and set them up for {object}. 3576 Operator::Properties properties = Operator::kEliminatable; 3577 Callable callable = 3578 Builtins::CallableFor(isolate(), Builtins::kCopyFastSmiOrObjectElements); 3579 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 3580 auto call_descriptor = Linkage::GetStubCallDescriptor( 3581 graph()->zone(), callable.descriptor(), 0, flags, properties); 3582 Node* result = __ Call(call_descriptor, __ HeapConstant(callable.code()), 3583 object, __ NoContextConstant()); 3584 __ Goto(&done, result); 3585 3586 __ Bind(&done); 3587 return done.PhiAt(0); 3588 } 3589 3590 Node* EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node, 3591 Node* frame_state) { 3592 GrowFastElementsParameters params = GrowFastElementsParametersOf(node->op()); 3593 Node* object = node->InputAt(0); 3594 Node* elements = node->InputAt(1); 3595 Node* index = node->InputAt(2); 3596 Node* elements_length = node->InputAt(3); 3597 3598 auto done = __ MakeLabel(MachineRepresentation::kTagged); 3599 auto if_grow = __ MakeDeferredLabel(); 3600 auto if_not_grow = __ MakeLabel(); 3601 3602 // Check if we need to grow the {elements} backing store. 3603 Node* check = __ Uint32LessThan(index, elements_length); 3604 __ GotoIfNot(check, &if_grow); 3605 __ Goto(&done, elements); 3606 3607 __ Bind(&if_grow); 3608 // We need to grow the {elements} for {object}. 3609 Operator::Properties properties = Operator::kEliminatable; 3610 Callable callable = 3611 (params.mode() == GrowFastElementsMode::kDoubleElements) 3612 ? Builtins::CallableFor(isolate(), Builtins::kGrowFastDoubleElements) 3613 : Builtins::CallableFor(isolate(), 3614 Builtins::kGrowFastSmiOrObjectElements); 3615 CallDescriptor::Flags call_flags = CallDescriptor::kNoFlags; 3616 auto call_descriptor = Linkage::GetStubCallDescriptor( 3617 graph()->zone(), callable.descriptor(), 0, call_flags, properties); 3618 Node* new_elements = 3619 __ Call(call_descriptor, __ HeapConstant(callable.code()), object, 3620 ChangeInt32ToSmi(index), __ NoContextConstant()); 3621 3622 // Ensure that we were able to grow the {elements}. 3623 __ DeoptimizeIf(DeoptimizeReason::kCouldNotGrowElements, params.feedback(), 3624 ObjectIsSmi(new_elements), frame_state); 3625 __ Goto(&done, new_elements); 3626 3627 __ Bind(&done); 3628 return done.PhiAt(0); 3629 } 3630 3631 void EffectControlLinearizer::LowerTransitionElementsKind(Node* node) { 3632 ElementsTransition const transition = ElementsTransitionOf(node->op()); 3633 Node* object = node->InputAt(0); 3634 3635 auto if_map_same = __ MakeDeferredLabel(); 3636 auto done = __ MakeLabel(); 3637 3638 Node* source_map = __ HeapConstant(transition.source()); 3639 Node* target_map = __ HeapConstant(transition.target()); 3640 3641 // Load the current map of {object}. 3642 Node* object_map = __ LoadField(AccessBuilder::ForMap(), object); 3643 3644 // Check if {object_map} is the same as {source_map}. 3645 Node* check = __ WordEqual(object_map, source_map); 3646 __ GotoIf(check, &if_map_same); 3647 __ Goto(&done); 3648 3649 __ Bind(&if_map_same); 3650 switch (transition.mode()) { 3651 case ElementsTransition::kFastTransition: 3652 // In-place migration of {object}, just store the {target_map}. 3653 __ StoreField(AccessBuilder::ForMap(), object, target_map); 3654 break; 3655 case ElementsTransition::kSlowTransition: { 3656 // Instance migration, call out to the runtime for {object}. 3657 Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; 3658 Runtime::FunctionId id = Runtime::kTransitionElementsKind; 3659 auto call_descriptor = Linkage::GetRuntimeCallDescriptor( 3660 graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags); 3661 __ Call(call_descriptor, __ CEntryStubConstant(1), object, target_map, 3662 __ ExternalConstant(ExternalReference::Create(id)), 3663 __ Int32Constant(2), __ NoContextConstant()); 3664 break; 3665 } 3666 } 3667 __ Goto(&done); 3668 3669 __ Bind(&done); 3670 } 3671 3672 Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) { 3673 Node* object = node->InputAt(0); 3674 Node* index = node->InputAt(1); 3675 Node* zero = __ IntPtrConstant(0); 3676 Node* one = __ IntPtrConstant(1); 3677 3678 // Sign-extend the {index} on 64-bit architectures. 3679 if (machine()->Is64()) { 3680 index = __ ChangeInt32ToInt64(index); 3681 } 3682 3683 auto if_double = __ MakeDeferredLabel(); 3684 auto done = __ MakeLabel(MachineRepresentation::kTagged); 3685 3686 // Check if field is a mutable double field. 3687 __ GotoIfNot(__ WordEqual(__ WordAnd(index, one), zero), &if_double); 3688 3689 // The field is a proper Tagged field on {object}. The {index} is shifted 3690 // to the left by one in the code below. 3691 { 3692 // Check if field is in-object or out-of-object. 3693 auto if_outofobject = __ MakeLabel(); 3694 __ GotoIf(__ IntLessThan(index, zero), &if_outofobject); 3695 3696 // The field is located in the {object} itself. 3697 { 3698 Node* offset = 3699 __ IntAdd(__ WordShl(index, __ IntPtrConstant(kPointerSizeLog2 - 1)), 3700 __ IntPtrConstant(JSObject::kHeaderSize - kHeapObjectTag)); 3701 Node* result = __ Load(MachineType::AnyTagged(), object, offset); 3702 __ Goto(&done, result); 3703 } 3704 3705 // The field is located in the properties backing store of {object}. 3706 // The {index} is equal to the negated out of property index plus 1. 3707 __ Bind(&if_outofobject); 3708 { 3709 Node* properties = 3710 __ LoadField(AccessBuilder::ForJSObjectPropertiesOrHash(), object); 3711 Node* offset = 3712 __ IntAdd(__ WordShl(__ IntSub(zero, index), 3713 __ IntPtrConstant(kPointerSizeLog2 - 1)), 3714 __ IntPtrConstant((FixedArray::kHeaderSize - kPointerSize) - 3715 kHeapObjectTag)); 3716 Node* result = __ Load(MachineType::AnyTagged(), properties, offset); 3717 __ Goto(&done, result); 3718 } 3719 } 3720 3721 // The field is a Double field, either unboxed in the object on 64-bit 3722 // architectures, or as MutableHeapNumber. 3723 __ Bind(&if_double); 3724 { 3725 auto done_double = __ MakeLabel(MachineRepresentation::kFloat64); 3726 3727 index = __ WordSar(index, one); 3728 3729 // Check if field is in-object or out-of-object. 3730 auto if_outofobject = __ MakeLabel(); 3731 __ GotoIf(__ IntLessThan(index, zero), &if_outofobject); 3732 3733 // The field is located in the {object} itself. 3734 { 3735 Node* offset = 3736 __ IntAdd(__ WordShl(index, __ IntPtrConstant(kPointerSizeLog2)), 3737 __ IntPtrConstant(JSObject::kHeaderSize - kHeapObjectTag)); 3738 if (FLAG_unbox_double_fields) { 3739 Node* result = __ Load(MachineType::Float64(), object, offset); 3740 __ Goto(&done_double, result); 3741 } else { 3742 Node* result = __ Load(MachineType::AnyTagged(), object, offset); 3743 result = __ LoadField(AccessBuilder::ForHeapNumberValue(), result); 3744 __ Goto(&done_double, result); 3745 } 3746 } 3747 3748 __ Bind(&if_outofobject); 3749 { 3750 Node* properties = 3751 __ LoadField(AccessBuilder::ForJSObjectPropertiesOrHash(), object); 3752 Node* offset = 3753 __ IntAdd(__ WordShl(__ IntSub(zero, index), 3754 __ IntPtrConstant(kPointerSizeLog2)), 3755 __ IntPtrConstant((FixedArray::kHeaderSize - kPointerSize) - 3756 kHeapObjectTag)); 3757 Node* result = __ Load(MachineType::AnyTagged(), properties, offset); 3758 result = __ LoadField(AccessBuilder::ForHeapNumberValue(), result); 3759 __ Goto(&done_double, result); 3760 } 3761 3762 __ Bind(&done_double); 3763 { 3764 Node* result = AllocateHeapNumberWithValue(done_double.PhiAt(0)); 3765 __ Goto(&done, result); 3766 } 3767 } 3768 3769 __ Bind(&done); 3770 return done.PhiAt(0); 3771 } 3772 3773 Node* EffectControlLinearizer::BuildReverseBytes(ExternalArrayType type, 3774 Node* value) { 3775 switch (type) { 3776 case kExternalInt8Array: 3777 case kExternalUint8Array: 3778 case kExternalUint8ClampedArray: 3779 return value; 3780 3781 case kExternalInt16Array: { 3782 Node* result = __ Word32ReverseBytes(value); 3783 result = __ Word32Sar(result, __ Int32Constant(16)); 3784 return result; 3785 } 3786 3787 case kExternalUint16Array: { 3788 Node* result = __ Word32ReverseBytes(value); 3789 result = __ Word32Shr(result, __ Int32Constant(16)); 3790 return result; 3791 } 3792 3793 case kExternalInt32Array: // Fall through. 3794 case kExternalUint32Array: 3795 return __ Word32ReverseBytes(value); 3796 3797 case kExternalFloat32Array: { 3798 Node* result = __ BitcastFloat32ToInt32(value); 3799 result = __ Word32ReverseBytes(result); 3800 result = __ BitcastInt32ToFloat32(result); 3801 return result; 3802 } 3803 3804 case kExternalFloat64Array: { 3805 if (machine()->Is64()) { 3806 Node* result = __ BitcastFloat64ToInt64(value); 3807 result = __ Word64ReverseBytes(result); 3808 result = __ BitcastInt64ToFloat64(result); 3809 return result; 3810 } else { 3811 Node* lo = __ Word32ReverseBytes(__ Float64ExtractLowWord32(value)); 3812 Node* hi = __ Word32ReverseBytes(__ Float64ExtractHighWord32(value)); 3813 Node* result = __ Float64Constant(0.0); 3814 result = __ Float64InsertLowWord32(result, hi); 3815 result = __ Float64InsertHighWord32(result, lo); 3816 return result; 3817 } 3818 } 3819 3820 case kExternalBigInt64Array: 3821 case kExternalBigUint64Array: 3822 UNREACHABLE(); 3823 } 3824 } 3825 3826 Node* EffectControlLinearizer::LowerLoadDataViewElement(Node* node) { 3827 ExternalArrayType element_type = ExternalArrayTypeOf(node->op()); 3828 Node* buffer = node->InputAt(0); 3829 Node* storage = node->InputAt(1); 3830 Node* index = node->InputAt(2); 3831 Node* is_little_endian = node->InputAt(3); 3832 3833 // On 64-bit platforms, we need to feed a Word64 index to the Load and 3834 // Store operators. 3835 if (machine()->Is64()) { 3836 index = __ ChangeUint32ToUint64(index); 3837 } 3838 3839 // We need to keep the {buffer} alive so that the GC will not release the 3840 // ArrayBuffer (if there's any) as long as we are still operating on it. 3841 __ Retain(buffer); 3842 3843 MachineType const machine_type = 3844 AccessBuilder::ForTypedArrayElement(element_type, true).machine_type; 3845 3846 Node* value = __ LoadUnaligned(machine_type, storage, index); 3847 auto big_endian = __ MakeLabel(); 3848 auto done = __ MakeLabel(machine_type.representation()); 3849 3850 __ GotoIfNot(is_little_endian, &big_endian); 3851 { // Little-endian load. 3852 #if V8_TARGET_LITTLE_ENDIAN 3853 __ Goto(&done, value); 3854 #else 3855 __ Goto(&done, BuildReverseBytes(element_type, value)); 3856 #endif // V8_TARGET_LITTLE_ENDIAN 3857 } 3858 3859 __ Bind(&big_endian); 3860 { // Big-endian load. 3861 #if V8_TARGET_LITTLE_ENDIAN 3862 __ Goto(&done, BuildReverseBytes(element_type, value)); 3863 #else 3864 __ Goto(&done, value); 3865 #endif // V8_TARGET_LITTLE_ENDIAN 3866 } 3867 3868 // We're done, return {result}. 3869 __ Bind(&done); 3870 return done.PhiAt(0); 3871 } 3872 3873 void EffectControlLinearizer::LowerStoreDataViewElement(Node* node) { 3874 ExternalArrayType element_type = ExternalArrayTypeOf(node->op()); 3875 Node* buffer = node->InputAt(0); 3876 Node* storage = node->InputAt(1); 3877 Node* index = node->InputAt(2); 3878 Node* value = node->InputAt(3); 3879 Node* is_little_endian = node->InputAt(4); 3880 3881 // On 64-bit platforms, we need to feed a Word64 index to the Load and 3882 // Store operators. 3883 if (machine()->Is64()) { 3884 index = __ ChangeUint32ToUint64(index); 3885 } 3886 3887 // We need to keep the {buffer} alive so that the GC will not release the 3888 // ArrayBuffer (if there's any) as long as we are still operating on it. 3889 __ Retain(buffer); 3890 3891 MachineType const machine_type = 3892 AccessBuilder::ForTypedArrayElement(element_type, true).machine_type; 3893 3894 auto big_endian = __ MakeLabel(); 3895 auto done = __ MakeLabel(machine_type.representation()); 3896 3897 __ GotoIfNot(is_little_endian, &big_endian); 3898 { // Little-endian store. 3899 #if V8_TARGET_LITTLE_ENDIAN 3900 __ Goto(&done, value); 3901 #else 3902 __ Goto(&done, BuildReverseBytes(element_type, value)); 3903 #endif // V8_TARGET_LITTLE_ENDIAN 3904 } 3905 3906 __ Bind(&big_endian); 3907 { // Big-endian store. 3908 #if V8_TARGET_LITTLE_ENDIAN 3909 __ Goto(&done, BuildReverseBytes(element_type, value)); 3910 #else 3911 __ Goto(&done, value); 3912 #endif // V8_TARGET_LITTLE_ENDIAN 3913 } 3914 3915 __ Bind(&done); 3916 __ StoreUnaligned(machine_type.representation(), storage, index, 3917 done.PhiAt(0)); 3918 } 3919 3920 Node* EffectControlLinearizer::LowerLoadTypedElement(Node* node) { 3921 ExternalArrayType array_type = ExternalArrayTypeOf(node->op()); 3922 Node* buffer = node->InputAt(0); 3923 Node* base = node->InputAt(1); 3924 Node* external = node->InputAt(2); 3925 Node* index = node->InputAt(3); 3926 3927 // We need to keep the {buffer} alive so that the GC will not release the 3928 // ArrayBuffer (if there's any) as long as we are still operating on it. 3929 __ Retain(buffer); 3930 3931 // Compute the effective storage pointer, handling the case where the 3932 // {external} pointer is the effective storage pointer (i.e. the {base} 3933 // is Smi zero). 3934 Node* storage = IntPtrMatcher(base).Is(0) 3935 ? external 3936 : __ UnsafePointerAdd(base, external); 3937 3938 // Perform the actual typed element access. 3939 return __ LoadElement(AccessBuilder::ForTypedArrayElement( 3940 array_type, true, LoadSensitivity::kCritical), 3941 storage, index); 3942 } 3943 3944 void EffectControlLinearizer::LowerStoreTypedElement(Node* node) { 3945 ExternalArrayType array_type = ExternalArrayTypeOf(node->op()); 3946 Node* buffer = node->InputAt(0); 3947 Node* base = node->InputAt(1); 3948 Node* external = node->InputAt(2); 3949 Node* index = node->InputAt(3); 3950 Node* value = node->InputAt(4); 3951 3952 // We need to keep the {buffer} alive so that the GC will not release the 3953 // ArrayBuffer (if there's any) as long as we are still operating on it. 3954 __ Retain(buffer); 3955 3956 // Compute the effective storage pointer, handling the case where the 3957 // {external} pointer is the effective storage pointer (i.e. the {base} 3958 // is Smi zero). 3959 Node* storage = IntPtrMatcher(base).Is(0) 3960 ? external 3961 : __ UnsafePointerAdd(base, external); 3962 3963 // Perform the actual typed element access. 3964 __ StoreElement(AccessBuilder::ForTypedArrayElement(array_type, true), 3965 storage, index, value); 3966 } 3967 3968 void EffectControlLinearizer::TransitionElementsTo(Node* node, Node* array, 3969 ElementsKind from, 3970 ElementsKind to) { 3971 DCHECK(IsMoreGeneralElementsKindTransition(from, to)); 3972 DCHECK(to == HOLEY_ELEMENTS || to == HOLEY_DOUBLE_ELEMENTS); 3973 3974 Handle<Map> target(to == HOLEY_ELEMENTS ? FastMapParameterOf(node->op()) 3975 : DoubleMapParameterOf(node->op())); 3976 Node* target_map = __ HeapConstant(target); 3977 3978 if (IsSimpleMapChangeTransition(from, to)) { 3979 __ StoreField(AccessBuilder::ForMap(), array, target_map); 3980 } else { 3981 // Instance migration, call out to the runtime for {array}. 3982 Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; 3983 Runtime::FunctionId id = Runtime::kTransitionElementsKind; 3984 auto call_descriptor = Linkage::GetRuntimeCallDescriptor( 3985 graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags); 3986 __ Call(call_descriptor, __ CEntryStubConstant(1), array, target_map, 3987 __ ExternalConstant(ExternalReference::Create(id)), 3988 __ Int32Constant(2), __ NoContextConstant()); 3989 } 3990 } 3991 3992 Node* EffectControlLinearizer::IsElementsKindGreaterThan( 3993 Node* kind, ElementsKind reference_kind) { 3994 Node* ref_kind = __ Int32Constant(reference_kind); 3995 Node* ret = __ Int32LessThan(ref_kind, kind); 3996 return ret; 3997 } 3998 3999 void EffectControlLinearizer::LowerTransitionAndStoreElement(Node* node) { 4000 Node* array = node->InputAt(0); 4001 Node* index = node->InputAt(1); 4002 Node* value = node->InputAt(2); 4003 4004 // Possibly transition array based on input and store. 4005 // 4006 // -- TRANSITION PHASE ----------------- 4007 // kind = ElementsKind(array) 4008 // if value is not smi { 4009 // if kind == HOLEY_SMI_ELEMENTS { 4010 // if value is heap number { 4011 // Transition array to HOLEY_DOUBLE_ELEMENTS 4012 // kind = HOLEY_DOUBLE_ELEMENTS 4013 // } else { 4014 // Transition array to HOLEY_ELEMENTS 4015 // kind = HOLEY_ELEMENTS 4016 // } 4017 // } else if kind == HOLEY_DOUBLE_ELEMENTS { 4018 // if value is not heap number { 4019 // Transition array to HOLEY_ELEMENTS 4020 // kind = HOLEY_ELEMENTS 4021 // } 4022 // } 4023 // } 4024 // 4025 // -- STORE PHASE ---------------------- 4026 // [make sure {kind} is up-to-date] 4027 // if kind == HOLEY_DOUBLE_ELEMENTS { 4028 // if value is smi { 4029 // float_value = convert smi to float 4030 // Store array[index] = float_value 4031 // } else { 4032 // float_value = value 4033 // Store array[index] = float_value 4034 // } 4035 // } else { 4036 // // kind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS 4037 // Store array[index] = value 4038 // } 4039 // 4040 Node* map = __ LoadField(AccessBuilder::ForMap(), array); 4041 Node* kind; 4042 { 4043 Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map); 4044 Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask); 4045 Node* andit = __ Word32And(bit_field2, mask); 4046 Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift); 4047 kind = __ Word32Shr(andit, shift); 4048 } 4049 4050 auto do_store = __ MakeLabel(MachineRepresentation::kWord32); 4051 // We can store a smi anywhere. 4052 __ GotoIf(ObjectIsSmi(value), &do_store, kind); 4053 4054 // {value} is a HeapObject. 4055 auto transition_smi_array = __ MakeDeferredLabel(); 4056 auto transition_double_to_fast = __ MakeDeferredLabel(); 4057 { 4058 __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS), 4059 &transition_smi_array); 4060 __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &do_store, 4061 kind); 4062 4063 // We have double elements kind. Only a HeapNumber can be stored 4064 // without effecting a transition. 4065 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 4066 Node* heap_number_map = __ HeapNumberMapConstant(); 4067 Node* check = __ WordEqual(value_map, heap_number_map); 4068 __ GotoIfNot(check, &transition_double_to_fast); 4069 __ Goto(&do_store, kind); 4070 } 4071 4072 __ Bind(&transition_smi_array); // deferred code. 4073 { 4074 // Transition {array} from HOLEY_SMI_ELEMENTS to HOLEY_DOUBLE_ELEMENTS or 4075 // to HOLEY_ELEMENTS. 4076 auto if_value_not_heap_number = __ MakeLabel(); 4077 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 4078 Node* heap_number_map = __ HeapNumberMapConstant(); 4079 Node* check = __ WordEqual(value_map, heap_number_map); 4080 __ GotoIfNot(check, &if_value_not_heap_number); 4081 { 4082 // {value} is a HeapNumber. 4083 TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS, 4084 HOLEY_DOUBLE_ELEMENTS); 4085 __ Goto(&do_store, __ Int32Constant(HOLEY_DOUBLE_ELEMENTS)); 4086 } 4087 __ Bind(&if_value_not_heap_number); 4088 { 4089 TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS); 4090 __ Goto(&do_store, __ Int32Constant(HOLEY_ELEMENTS)); 4091 } 4092 } 4093 4094 __ Bind(&transition_double_to_fast); // deferred code. 4095 { 4096 TransitionElementsTo(node, array, HOLEY_DOUBLE_ELEMENTS, HOLEY_ELEMENTS); 4097 __ Goto(&do_store, __ Int32Constant(HOLEY_ELEMENTS)); 4098 } 4099 4100 // Make sure kind is up-to-date. 4101 __ Bind(&do_store); 4102 kind = do_store.PhiAt(0); 4103 4104 Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array); 4105 auto if_kind_is_double = __ MakeLabel(); 4106 auto done = __ MakeLabel(); 4107 __ GotoIf(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), 4108 &if_kind_is_double); 4109 { 4110 // Our ElementsKind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS. 4111 __ StoreElement(AccessBuilder::ForFixedArrayElement(HOLEY_ELEMENTS), 4112 elements, index, value); 4113 __ Goto(&done); 4114 } 4115 __ Bind(&if_kind_is_double); 4116 { 4117 // Our ElementsKind is HOLEY_DOUBLE_ELEMENTS. 4118 auto do_double_store = __ MakeLabel(); 4119 __ GotoIfNot(ObjectIsSmi(value), &do_double_store); 4120 { 4121 Node* int_value = ChangeSmiToInt32(value); 4122 Node* float_value = __ ChangeInt32ToFloat64(int_value); 4123 __ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements, 4124 index, float_value); 4125 __ Goto(&done); 4126 } 4127 __ Bind(&do_double_store); 4128 { 4129 Node* float_value = 4130 __ LoadField(AccessBuilder::ForHeapNumberValue(), value); 4131 __ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements, 4132 index, float_value); 4133 __ Goto(&done); 4134 } 4135 } 4136 4137 __ Bind(&done); 4138 } 4139 4140 void EffectControlLinearizer::LowerTransitionAndStoreNumberElement(Node* node) { 4141 Node* array = node->InputAt(0); 4142 Node* index = node->InputAt(1); 4143 Node* value = node->InputAt(2); // This is a Float64, not tagged. 4144 4145 // Possibly transition array based on input and store. 4146 // 4147 // -- TRANSITION PHASE ----------------- 4148 // kind = ElementsKind(array) 4149 // if kind == HOLEY_SMI_ELEMENTS { 4150 // Transition array to HOLEY_DOUBLE_ELEMENTS 4151 // } else if kind != HOLEY_DOUBLE_ELEMENTS { 4152 // This is UNREACHABLE, execute a debug break. 4153 // } 4154 // 4155 // -- STORE PHASE ---------------------- 4156 // Store array[index] = value (it's a float) 4157 // 4158 Node* map = __ LoadField(AccessBuilder::ForMap(), array); 4159 Node* kind; 4160 { 4161 Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map); 4162 Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask); 4163 Node* andit = __ Word32And(bit_field2, mask); 4164 Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift); 4165 kind = __ Word32Shr(andit, shift); 4166 } 4167 4168 auto do_store = __ MakeLabel(); 4169 4170 // {value} is a float64. 4171 auto transition_smi_array = __ MakeDeferredLabel(); 4172 { 4173 __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS), 4174 &transition_smi_array); 4175 // We expect that our input array started at HOLEY_SMI_ELEMENTS, and 4176 // climbs the lattice up to HOLEY_DOUBLE_ELEMENTS. Force a debug break 4177 // if this assumption is broken. It also would be the case that 4178 // loop peeling can break this assumption. 4179 __ GotoIf(__ Word32Equal(kind, __ Int32Constant(HOLEY_DOUBLE_ELEMENTS)), 4180 &do_store); 4181 // TODO(turbofan): It would be good to have an "Unreachable()" node type. 4182 __ DebugBreak(); 4183 __ Goto(&do_store); 4184 } 4185 4186 __ Bind(&transition_smi_array); // deferred code. 4187 { 4188 // Transition {array} from HOLEY_SMI_ELEMENTS to HOLEY_DOUBLE_ELEMENTS. 4189 TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS, 4190 HOLEY_DOUBLE_ELEMENTS); 4191 __ Goto(&do_store); 4192 } 4193 4194 __ Bind(&do_store); 4195 4196 Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array); 4197 __ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements, index, 4198 value); 4199 } 4200 4201 void EffectControlLinearizer::LowerTransitionAndStoreNonNumberElement( 4202 Node* node) { 4203 Node* array = node->InputAt(0); 4204 Node* index = node->InputAt(1); 4205 Node* value = node->InputAt(2); 4206 4207 // Possibly transition array based on input and store. 4208 // 4209 // -- TRANSITION PHASE ----------------- 4210 // kind = ElementsKind(array) 4211 // if kind == HOLEY_SMI_ELEMENTS { 4212 // Transition array to HOLEY_ELEMENTS 4213 // } else if kind == HOLEY_DOUBLE_ELEMENTS { 4214 // Transition array to HOLEY_ELEMENTS 4215 // } 4216 // 4217 // -- STORE PHASE ---------------------- 4218 // // kind is HOLEY_ELEMENTS 4219 // Store array[index] = value 4220 // 4221 Node* map = __ LoadField(AccessBuilder::ForMap(), array); 4222 Node* kind; 4223 { 4224 Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map); 4225 Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask); 4226 Node* andit = __ Word32And(bit_field2, mask); 4227 Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift); 4228 kind = __ Word32Shr(andit, shift); 4229 } 4230 4231 auto do_store = __ MakeLabel(); 4232 4233 auto transition_smi_array = __ MakeDeferredLabel(); 4234 auto transition_double_to_fast = __ MakeDeferredLabel(); 4235 { 4236 __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS), 4237 &transition_smi_array); 4238 __ GotoIf(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), 4239 &transition_double_to_fast); 4240 __ Goto(&do_store); 4241 } 4242 4243 __ Bind(&transition_smi_array); // deferred code. 4244 { 4245 // Transition {array} from HOLEY_SMI_ELEMENTS to HOLEY_ELEMENTS. 4246 TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS); 4247 __ Goto(&do_store); 4248 } 4249 4250 __ Bind(&transition_double_to_fast); // deferred code. 4251 { 4252 TransitionElementsTo(node, array, HOLEY_DOUBLE_ELEMENTS, HOLEY_ELEMENTS); 4253 __ Goto(&do_store); 4254 } 4255 4256 __ Bind(&do_store); 4257 4258 Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array); 4259 // Our ElementsKind is HOLEY_ELEMENTS. 4260 ElementAccess access = AccessBuilder::ForFixedArrayElement(HOLEY_ELEMENTS); 4261 Type value_type = ValueTypeParameterOf(node->op()); 4262 if (value_type.Is(Type::BooleanOrNullOrUndefined())) { 4263 access.type = value_type; 4264 access.write_barrier_kind = kNoWriteBarrier; 4265 } 4266 __ StoreElement(access, elements, index, value); 4267 } 4268 4269 void EffectControlLinearizer::LowerStoreSignedSmallElement(Node* node) { 4270 Node* array = node->InputAt(0); 4271 Node* index = node->InputAt(1); 4272 Node* value = node->InputAt(2); // int32 4273 4274 // Store a signed small in an output array. 4275 // 4276 // kind = ElementsKind(array) 4277 // 4278 // -- STORE PHASE ---------------------- 4279 // if kind == HOLEY_DOUBLE_ELEMENTS { 4280 // float_value = convert int32 to float 4281 // Store array[index] = float_value 4282 // } else { 4283 // // kind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS 4284 // smi_value = convert int32 to smi 4285 // Store array[index] = smi_value 4286 // } 4287 // 4288 Node* map = __ LoadField(AccessBuilder::ForMap(), array); 4289 Node* kind; 4290 { 4291 Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map); 4292 Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask); 4293 Node* andit = __ Word32And(bit_field2, mask); 4294 Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift); 4295 kind = __ Word32Shr(andit, shift); 4296 } 4297 4298 Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array); 4299 auto if_kind_is_double = __ MakeLabel(); 4300 auto done = __ MakeLabel(); 4301 __ GotoIf(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), 4302 &if_kind_is_double); 4303 { 4304 // Our ElementsKind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS. 4305 // In this case, we know our value is a signed small, and we can optimize 4306 // the ElementAccess information. 4307 ElementAccess access = AccessBuilder::ForFixedArrayElement(); 4308 access.type = Type::SignedSmall(); 4309 access.machine_type = MachineType::TaggedSigned(); 4310 access.write_barrier_kind = kNoWriteBarrier; 4311 Node* smi_value = ChangeInt32ToSmi(value); 4312 __ StoreElement(access, elements, index, smi_value); 4313 __ Goto(&done); 4314 } 4315 __ Bind(&if_kind_is_double); 4316 { 4317 // Our ElementsKind is HOLEY_DOUBLE_ELEMENTS. 4318 Node* float_value = __ ChangeInt32ToFloat64(value); 4319 __ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements, 4320 index, float_value); 4321 __ Goto(&done); 4322 } 4323 4324 __ Bind(&done); 4325 } 4326 4327 void EffectControlLinearizer::LowerRuntimeAbort(Node* node) { 4328 AbortReason reason = AbortReasonOf(node->op()); 4329 Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; 4330 Runtime::FunctionId id = Runtime::kAbort; 4331 auto call_descriptor = Linkage::GetRuntimeCallDescriptor( 4332 graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags); 4333 __ Call(call_descriptor, __ CEntryStubConstant(1), 4334 jsgraph()->SmiConstant(static_cast<int>(reason)), 4335 __ ExternalConstant(ExternalReference::Create(id)), 4336 __ Int32Constant(1), __ NoContextConstant()); 4337 } 4338 4339 Node* EffectControlLinearizer::LowerConvertReceiver(Node* node) { 4340 ConvertReceiverMode const mode = ConvertReceiverModeOf(node->op()); 4341 Node* value = node->InputAt(0); 4342 Node* global_proxy = node->InputAt(1); 4343 4344 switch (mode) { 4345 case ConvertReceiverMode::kNullOrUndefined: { 4346 return global_proxy; 4347 } 4348 case ConvertReceiverMode::kNotNullOrUndefined: { 4349 auto convert_to_object = __ MakeDeferredLabel(); 4350 auto done_convert = __ MakeLabel(MachineRepresentation::kTagged); 4351 4352 // Check if {value} is already a JSReceiver. 4353 __ GotoIf(ObjectIsSmi(value), &convert_to_object); 4354 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 4355 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 4356 Node* value_instance_type = 4357 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 4358 Node* check = __ Uint32LessThan( 4359 value_instance_type, __ Uint32Constant(FIRST_JS_RECEIVER_TYPE)); 4360 __ GotoIf(check, &convert_to_object); 4361 __ Goto(&done_convert, value); 4362 4363 // Wrap the primitive {value} into a JSValue. 4364 __ Bind(&convert_to_object); 4365 Operator::Properties properties = Operator::kEliminatable; 4366 Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject); 4367 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 4368 auto call_descriptor = Linkage::GetStubCallDescriptor( 4369 graph()->zone(), callable.descriptor(), 0, flags, properties); 4370 Node* native_context = __ LoadField( 4371 AccessBuilder::ForJSGlobalProxyNativeContext(), global_proxy); 4372 Node* result = __ Call(call_descriptor, __ HeapConstant(callable.code()), 4373 value, native_context); 4374 __ Goto(&done_convert, result); 4375 4376 __ Bind(&done_convert); 4377 return done_convert.PhiAt(0); 4378 } 4379 case ConvertReceiverMode::kAny: { 4380 auto convert_to_object = __ MakeDeferredLabel(); 4381 auto convert_global_proxy = __ MakeDeferredLabel(); 4382 auto done_convert = __ MakeLabel(MachineRepresentation::kTagged); 4383 4384 // Check if {value} is already a JSReceiver, or null/undefined. 4385 __ GotoIf(ObjectIsSmi(value), &convert_to_object); 4386 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 4387 Node* value_map = __ LoadField(AccessBuilder::ForMap(), value); 4388 Node* value_instance_type = 4389 __ LoadField(AccessBuilder::ForMapInstanceType(), value_map); 4390 Node* check = __ Uint32LessThan( 4391 value_instance_type, __ Uint32Constant(FIRST_JS_RECEIVER_TYPE)); 4392 __ GotoIf(check, &convert_to_object); 4393 __ Goto(&done_convert, value); 4394 4395 // Wrap the primitive {value} into a JSValue. 4396 __ Bind(&convert_to_object); 4397 __ GotoIf(__ WordEqual(value, __ UndefinedConstant()), 4398 &convert_global_proxy); 4399 __ GotoIf(__ WordEqual(value, __ NullConstant()), &convert_global_proxy); 4400 Operator::Properties properties = Operator::kEliminatable; 4401 Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject); 4402 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 4403 auto call_descriptor = Linkage::GetStubCallDescriptor( 4404 graph()->zone(), callable.descriptor(), 0, flags, properties); 4405 Node* native_context = __ LoadField( 4406 AccessBuilder::ForJSGlobalProxyNativeContext(), global_proxy); 4407 Node* result = __ Call(call_descriptor, __ HeapConstant(callable.code()), 4408 value, native_context); 4409 __ Goto(&done_convert, result); 4410 4411 // Replace the {value} with the {global_proxy}. 4412 __ Bind(&convert_global_proxy); 4413 __ Goto(&done_convert, global_proxy); 4414 4415 __ Bind(&done_convert); 4416 return done_convert.PhiAt(0); 4417 } 4418 } 4419 4420 UNREACHABLE(); 4421 return nullptr; 4422 } 4423 4424 Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundUp(Node* node) { 4425 // Nothing to be done if a fast hardware instruction is available. 4426 if (machine()->Float64RoundUp().IsSupported()) { 4427 return Nothing<Node*>(); 4428 } 4429 4430 Node* const input = node->InputAt(0); 4431 4432 // General case for ceil. 4433 // 4434 // if 0.0 < input then 4435 // if 2^52 <= input then 4436 // input 4437 // else 4438 // let temp1 = (2^52 + input) - 2^52 in 4439 // if temp1 < input then 4440 // temp1 + 1 4441 // else 4442 // temp1 4443 // else 4444 // if input == 0 then 4445 // input 4446 // else 4447 // if input <= -2^52 then 4448 // input 4449 // else 4450 // let temp1 = -0 - input in 4451 // let temp2 = (2^52 + temp1) - 2^52 in 4452 // let temp3 = (if temp1 < temp2 then temp2 - 1 else temp2) in 4453 // -0 - temp3 4454 4455 auto if_not_positive = __ MakeDeferredLabel(); 4456 auto if_greater_than_two_52 = __ MakeDeferredLabel(); 4457 auto if_less_than_minus_two_52 = __ MakeDeferredLabel(); 4458 auto if_zero = __ MakeDeferredLabel(); 4459 auto done_temp3 = __ MakeLabel(MachineRepresentation::kFloat64); 4460 auto done = __ MakeLabel(MachineRepresentation::kFloat64); 4461 4462 Node* const zero = __ Float64Constant(0.0); 4463 Node* const two_52 = __ Float64Constant(4503599627370496.0E0); 4464 Node* const one = __ Float64Constant(1.0); 4465 4466 Node* check0 = __ Float64LessThan(zero, input); 4467 __ GotoIfNot(check0, &if_not_positive); 4468 { 4469 Node* check1 = __ Float64LessThanOrEqual(two_52, input); 4470 __ GotoIf(check1, &if_greater_than_two_52); 4471 { 4472 Node* temp1 = __ Float64Sub(__ Float64Add(two_52, input), two_52); 4473 __ GotoIfNot(__ Float64LessThan(temp1, input), &done, temp1); 4474 __ Goto(&done, __ Float64Add(temp1, one)); 4475 } 4476 4477 __ Bind(&if_greater_than_two_52); 4478 __ Goto(&done, input); 4479 } 4480 4481 __ Bind(&if_not_positive); 4482 { 4483 Node* check1 = __ Float64Equal(input, zero); 4484 __ GotoIf(check1, &if_zero); 4485 4486 Node* const minus_two_52 = __ Float64Constant(-4503599627370496.0E0); 4487 Node* check2 = __ Float64LessThanOrEqual(input, minus_two_52); 4488 __ GotoIf(check2, &if_less_than_minus_two_52); 4489 4490 { 4491 Node* const minus_zero = __ Float64Constant(-0.0); 4492 Node* temp1 = __ Float64Sub(minus_zero, input); 4493 Node* temp2 = __ Float64Sub(__ Float64Add(two_52, temp1), two_52); 4494 Node* check3 = __ Float64LessThan(temp1, temp2); 4495 __ GotoIfNot(check3, &done_temp3, temp2); 4496 __ Goto(&done_temp3, __ Float64Sub(temp2, one)); 4497 4498 __ Bind(&done_temp3); 4499 Node* temp3 = done_temp3.PhiAt(0); 4500 __ Goto(&done, __ Float64Sub(minus_zero, temp3)); 4501 } 4502 __ Bind(&if_less_than_minus_two_52); 4503 __ Goto(&done, input); 4504 4505 __ Bind(&if_zero); 4506 __ Goto(&done, input); 4507 } 4508 __ Bind(&done); 4509 return Just(done.PhiAt(0)); 4510 } 4511 4512 Node* EffectControlLinearizer::BuildFloat64RoundDown(Node* value) { 4513 if (machine()->Float64RoundDown().IsSupported()) { 4514 return __ Float64RoundDown(value); 4515 } 4516 4517 Node* const input = value; 4518 4519 // General case for floor. 4520 // 4521 // if 0.0 < input then 4522 // if 2^52 <= input then 4523 // input 4524 // else 4525 // let temp1 = (2^52 + input) - 2^52 in 4526 // if input < temp1 then 4527 // temp1 - 1 4528 // else 4529 // temp1 4530 // else 4531 // if input == 0 then 4532 // input 4533 // else 4534 // if input <= -2^52 then 4535 // input 4536 // else 4537 // let temp1 = -0 - input in 4538 // let temp2 = (2^52 + temp1) - 2^52 in 4539 // if temp2 < temp1 then 4540 // -1 - temp2 4541 // else 4542 // -0 - temp2 4543 4544 auto if_not_positive = __ MakeDeferredLabel(); 4545 auto if_greater_than_two_52 = __ MakeDeferredLabel(); 4546 auto if_less_than_minus_two_52 = __ MakeDeferredLabel(); 4547 auto if_temp2_lt_temp1 = __ MakeLabel(); 4548 auto if_zero = __ MakeDeferredLabel(); 4549 auto done = __ MakeLabel(MachineRepresentation::kFloat64); 4550 4551 Node* const zero = __ Float64Constant(0.0); 4552 Node* const two_52 = __ Float64Constant(4503599627370496.0E0); 4553 4554 Node* check0 = __ Float64LessThan(zero, input); 4555 __ GotoIfNot(check0, &if_not_positive); 4556 { 4557 Node* check1 = __ Float64LessThanOrEqual(two_52, input); 4558 __ GotoIf(check1, &if_greater_than_two_52); 4559 { 4560 Node* const one = __ Float64Constant(1.0); 4561 Node* temp1 = __ Float64Sub(__ Float64Add(two_52, input), two_52); 4562 __ GotoIfNot(__ Float64LessThan(input, temp1), &done, temp1); 4563 __ Goto(&done, __ Float64Sub(temp1, one)); 4564 } 4565 4566 __ Bind(&if_greater_than_two_52); 4567 __ Goto(&done, input); 4568 } 4569 4570 __ Bind(&if_not_positive); 4571 { 4572 Node* check1 = __ Float64Equal(input, zero); 4573 __ GotoIf(check1, &if_zero); 4574 4575 Node* const minus_two_52 = __ Float64Constant(-4503599627370496.0E0); 4576 Node* check2 = __ Float64LessThanOrEqual(input, minus_two_52); 4577 __ GotoIf(check2, &if_less_than_minus_two_52); 4578 4579 { 4580 Node* const minus_zero = __ Float64Constant(-0.0); 4581 Node* temp1 = __ Float64Sub(minus_zero, input); 4582 Node* temp2 = __ Float64Sub(__ Float64Add(two_52, temp1), two_52); 4583 Node* check3 = __ Float64LessThan(temp2, temp1); 4584 __ GotoIf(check3, &if_temp2_lt_temp1); 4585 __ Goto(&done, __ Float64Sub(minus_zero, temp2)); 4586 4587 __ Bind(&if_temp2_lt_temp1); 4588 __ Goto(&done, __ Float64Sub(__ Float64Constant(-1.0), temp2)); 4589 } 4590 __ Bind(&if_less_than_minus_two_52); 4591 __ Goto(&done, input); 4592 4593 __ Bind(&if_zero); 4594 __ Goto(&done, input); 4595 } 4596 __ Bind(&done); 4597 return done.PhiAt(0); 4598 } 4599 4600 Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundDown(Node* node) { 4601 // Nothing to be done if a fast hardware instruction is available. 4602 if (machine()->Float64RoundDown().IsSupported()) { 4603 return Nothing<Node*>(); 4604 } 4605 4606 Node* const input = node->InputAt(0); 4607 return Just(BuildFloat64RoundDown(input)); 4608 } 4609 4610 Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTiesEven(Node* node) { 4611 // Nothing to be done if a fast hardware instruction is available. 4612 if (machine()->Float64RoundTiesEven().IsSupported()) { 4613 return Nothing<Node*>(); 4614 } 4615 4616 Node* const input = node->InputAt(0); 4617 4618 // Generate case for round ties to even: 4619 // 4620 // let value = floor(input) in 4621 // let temp1 = input - value in 4622 // if temp1 < 0.5 then 4623 // value 4624 // else if 0.5 < temp1 then 4625 // value + 1.0 4626 // else 4627 // let temp2 = value % 2.0 in 4628 // if temp2 == 0.0 then 4629 // value 4630 // else 4631 // value + 1.0 4632 4633 auto if_is_half = __ MakeLabel(); 4634 auto done = __ MakeLabel(MachineRepresentation::kFloat64); 4635 4636 Node* value = BuildFloat64RoundDown(input); 4637 Node* temp1 = __ Float64Sub(input, value); 4638 4639 Node* const half = __ Float64Constant(0.5); 4640 Node* check0 = __ Float64LessThan(temp1, half); 4641 __ GotoIf(check0, &done, value); 4642 4643 Node* const one = __ Float64Constant(1.0); 4644 Node* check1 = __ Float64LessThan(half, temp1); 4645 __ GotoIfNot(check1, &if_is_half); 4646 __ Goto(&done, __ Float64Add(value, one)); 4647 4648 __ Bind(&if_is_half); 4649 Node* temp2 = __ Float64Mod(value, __ Float64Constant(2.0)); 4650 Node* check2 = __ Float64Equal(temp2, __ Float64Constant(0.0)); 4651 __ GotoIf(check2, &done, value); 4652 __ Goto(&done, __ Float64Add(value, one)); 4653 4654 __ Bind(&done); 4655 return Just(done.PhiAt(0)); 4656 } 4657 4658 Node* EffectControlLinearizer::BuildFloat64RoundTruncate(Node* input) { 4659 if (machine()->Float64RoundTruncate().IsSupported()) { 4660 return __ Float64RoundTruncate(input); 4661 } 4662 // General case for trunc. 4663 // 4664 // if 0.0 < input then 4665 // if 2^52 <= input then 4666 // input 4667 // else 4668 // let temp1 = (2^52 + input) - 2^52 in 4669 // if input < temp1 then 4670 // temp1 - 1 4671 // else 4672 // temp1 4673 // else 4674 // if input == 0 then 4675 // input 4676 // else 4677 // if input <= -2^52 then 4678 // input 4679 // else 4680 // let temp1 = -0 - input in 4681 // let temp2 = (2^52 + temp1) - 2^52 in 4682 // let temp3 = (if temp1 < temp2 then temp2 - 1 else temp2) in 4683 // -0 - temp3 4684 // 4685 // Note: We do not use the Diamond helper class here, because it really hurts 4686 // readability with nested diamonds. 4687 4688 auto if_not_positive = __ MakeDeferredLabel(); 4689 auto if_greater_than_two_52 = __ MakeDeferredLabel(); 4690 auto if_less_than_minus_two_52 = __ MakeDeferredLabel(); 4691 auto if_zero = __ MakeDeferredLabel(); 4692 auto done_temp3 = __ MakeLabel(MachineRepresentation::kFloat64); 4693 auto done = __ MakeLabel(MachineRepresentation::kFloat64); 4694 4695 Node* const zero = __ Float64Constant(0.0); 4696 Node* const two_52 = __ Float64Constant(4503599627370496.0E0); 4697 Node* const one = __ Float64Constant(1.0); 4698 4699 Node* check0 = __ Float64LessThan(zero, input); 4700 __ GotoIfNot(check0, &if_not_positive); 4701 { 4702 Node* check1 = __ Float64LessThanOrEqual(two_52, input); 4703 __ GotoIf(check1, &if_greater_than_two_52); 4704 { 4705 Node* temp1 = __ Float64Sub(__ Float64Add(two_52, input), two_52); 4706 __ GotoIfNot(__ Float64LessThan(input, temp1), &done, temp1); 4707 __ Goto(&done, __ Float64Sub(temp1, one)); 4708 } 4709 4710 __ Bind(&if_greater_than_two_52); 4711 __ Goto(&done, input); 4712 } 4713 4714 __ Bind(&if_not_positive); 4715 { 4716 Node* check1 = __ Float64Equal(input, zero); 4717 __ GotoIf(check1, &if_zero); 4718 4719 Node* const minus_two_52 = __ Float64Constant(-4503599627370496.0E0); 4720 Node* check2 = __ Float64LessThanOrEqual(input, minus_two_52); 4721 __ GotoIf(check2, &if_less_than_minus_two_52); 4722 4723 { 4724 Node* const minus_zero = __ Float64Constant(-0.0); 4725 Node* temp1 = __ Float64Sub(minus_zero, input); 4726 Node* temp2 = __ Float64Sub(__ Float64Add(two_52, temp1), two_52); 4727 Node* check3 = __ Float64LessThan(temp1, temp2); 4728 __ GotoIfNot(check3, &done_temp3, temp2); 4729 __ Goto(&done_temp3, __ Float64Sub(temp2, one)); 4730 4731 __ Bind(&done_temp3); 4732 Node* temp3 = done_temp3.PhiAt(0); 4733 __ Goto(&done, __ Float64Sub(minus_zero, temp3)); 4734 } 4735 __ Bind(&if_less_than_minus_two_52); 4736 __ Goto(&done, input); 4737 4738 __ Bind(&if_zero); 4739 __ Goto(&done, input); 4740 } 4741 __ Bind(&done); 4742 return done.PhiAt(0); 4743 } 4744 4745 Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTruncate(Node* node) { 4746 // Nothing to be done if a fast hardware instruction is available. 4747 if (machine()->Float64RoundTruncate().IsSupported()) { 4748 return Nothing<Node*>(); 4749 } 4750 4751 Node* const input = node->InputAt(0); 4752 return Just(BuildFloat64RoundTruncate(input)); 4753 } 4754 4755 Node* EffectControlLinearizer::LowerFindOrderedHashMapEntry(Node* node) { 4756 Node* table = NodeProperties::GetValueInput(node, 0); 4757 Node* key = NodeProperties::GetValueInput(node, 1); 4758 4759 { 4760 Callable const callable = 4761 Builtins::CallableFor(isolate(), Builtins::kFindOrderedHashMapEntry); 4762 Operator::Properties const properties = node->op()->properties(); 4763 CallDescriptor::Flags const flags = CallDescriptor::kNoFlags; 4764 auto call_descriptor = Linkage::GetStubCallDescriptor( 4765 graph()->zone(), callable.descriptor(), 0, flags, properties); 4766 return __ Call(call_descriptor, __ HeapConstant(callable.code()), table, 4767 key, __ NoContextConstant()); 4768 } 4769 } 4770 4771 Node* EffectControlLinearizer::ComputeIntegerHash(Node* value) { 4772 // See v8::internal::ComputeIntegerHash() 4773 value = __ Int32Add(__ Word32Xor(value, __ Int32Constant(0xFFFFFFFF)), 4774 __ Word32Shl(value, __ Int32Constant(15))); 4775 value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(12))); 4776 value = __ Int32Add(value, __ Word32Shl(value, __ Int32Constant(2))); 4777 value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(4))); 4778 value = __ Int32Mul(value, __ Int32Constant(2057)); 4779 value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(16))); 4780 value = __ Word32And(value, __ Int32Constant(0x3FFFFFFF)); 4781 return value; 4782 } 4783 4784 Node* EffectControlLinearizer::LowerFindOrderedHashMapEntryForInt32Key( 4785 Node* node) { 4786 Node* table = NodeProperties::GetValueInput(node, 0); 4787 Node* key = NodeProperties::GetValueInput(node, 1); 4788 4789 // Compute the integer hash code. 4790 Node* hash = ChangeUint32ToUintPtr(ComputeIntegerHash(key)); 4791 4792 Node* number_of_buckets = ChangeSmiToIntPtr(__ LoadField( 4793 AccessBuilder::ForOrderedHashTableBaseNumberOfBuckets(), table)); 4794 hash = __ WordAnd(hash, __ IntSub(number_of_buckets, __ IntPtrConstant(1))); 4795 Node* first_entry = ChangeSmiToIntPtr(__ Load( 4796 MachineType::TaggedSigned(), table, 4797 __ IntAdd(__ WordShl(hash, __ IntPtrConstant(kPointerSizeLog2)), 4798 __ IntPtrConstant(OrderedHashMap::kHashTableStartOffset - 4799 kHeapObjectTag)))); 4800 4801 auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation()); 4802 auto done = __ MakeLabel(MachineRepresentation::kWord32); 4803 __ Goto(&loop, first_entry); 4804 __ Bind(&loop); 4805 { 4806 Node* entry = loop.PhiAt(0); 4807 Node* check = 4808 __ WordEqual(entry, __ IntPtrConstant(OrderedHashMap::kNotFound)); 4809 __ GotoIf(check, &done, __ Int32Constant(-1)); 4810 entry = __ IntAdd( 4811 __ IntMul(entry, __ IntPtrConstant(OrderedHashMap::kEntrySize)), 4812 number_of_buckets); 4813 4814 Node* candidate_key = __ Load( 4815 MachineType::AnyTagged(), table, 4816 __ IntAdd(__ WordShl(entry, __ IntPtrConstant(kPointerSizeLog2)), 4817 __ IntPtrConstant(OrderedHashMap::kHashTableStartOffset - 4818 kHeapObjectTag))); 4819 4820 auto if_match = __ MakeLabel(); 4821 auto if_notmatch = __ MakeLabel(); 4822 auto if_notsmi = __ MakeDeferredLabel(); 4823 __ GotoIfNot(ObjectIsSmi(candidate_key), &if_notsmi); 4824 __ Branch(__ Word32Equal(ChangeSmiToInt32(candidate_key), key), &if_match, 4825 &if_notmatch); 4826 4827 __ Bind(&if_notsmi); 4828 __ GotoIfNot( 4829 __ WordEqual(__ LoadField(AccessBuilder::ForMap(), candidate_key), 4830 __ HeapNumberMapConstant()), 4831 &if_notmatch); 4832 __ Branch(__ Float64Equal(__ LoadField(AccessBuilder::ForHeapNumberValue(), 4833 candidate_key), 4834 __ ChangeInt32ToFloat64(key)), 4835 &if_match, &if_notmatch); 4836 4837 __ Bind(&if_match); 4838 { 4839 Node* index = ChangeIntPtrToInt32(entry); 4840 __ Goto(&done, index); 4841 } 4842 4843 __ Bind(&if_notmatch); 4844 { 4845 Node* next_entry = ChangeSmiToIntPtr(__ Load( 4846 MachineType::TaggedSigned(), table, 4847 __ IntAdd( 4848 __ WordShl(entry, __ IntPtrConstant(kPointerSizeLog2)), 4849 __ IntPtrConstant(OrderedHashMap::kHashTableStartOffset + 4850 OrderedHashMap::kChainOffset * kPointerSize - 4851 kHeapObjectTag)))); 4852 __ Goto(&loop, next_entry); 4853 } 4854 } 4855 4856 __ Bind(&done); 4857 return done.PhiAt(0); 4858 } 4859 4860 Node* EffectControlLinearizer::LowerDateNow(Node* node) { 4861 Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; 4862 Runtime::FunctionId id = Runtime::kDateCurrentTime; 4863 auto call_descriptor = Linkage::GetRuntimeCallDescriptor( 4864 graph()->zone(), id, 0, properties, CallDescriptor::kNoFlags); 4865 return __ Call(call_descriptor, __ CEntryStubConstant(1), 4866 __ ExternalConstant(ExternalReference::Create(id)), 4867 __ Int32Constant(0), __ NoContextConstant()); 4868 } 4869 4870 #undef __ 4871 4872 Factory* EffectControlLinearizer::factory() const { 4873 return isolate()->factory(); 4874 } 4875 4876 Isolate* EffectControlLinearizer::isolate() const { 4877 return jsgraph()->isolate(); 4878 } 4879 4880 } // namespace compiler 4881 } // namespace internal 4882 } // namespace v8 4883