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