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