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 464408 : 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 464408 : embedded_maps_(embedded_maps) {}
48 :
49 651681 : Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); }
50 0 : CommonOperatorBuilder* EffectControlLinearizer::common() const {
51 1099164 : 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 325938 : 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 464409 : class BlockEffectControlMap {
69 : public:
70 : explicit BlockEffectControlMap(Zone* temp_zone) : map_(temp_zone) {}
71 :
72 : BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) {
73 19423330 : 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 39803 : : effect_phi(effect_phi), block(block) {}
94 : };
95 :
96 1042 : void ConnectUnreachableToEnd(Node* effect, Node* control, JSGraph* jsgraph) {
97 : Graph* graph = jsgraph->graph();
98 : CommonOperatorBuilder* common = jsgraph->common();
99 1042 : if (effect->opcode() == IrOpcode::kDead) return;
100 1042 : if (effect->opcode() != IrOpcode::kUnreachable) {
101 0 : effect = graph->NewNode(common->Unreachable(), effect, control);
102 : }
103 1042 : Node* throw_node = graph->NewNode(common->Throw(), effect, control);
104 1042 : NodeProperties::MergeControlToEnd(graph, common, throw_node);
105 : }
106 :
107 796927 : 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 4397737 : for (int i = 0; i < node->op()->EffectInputCount(); i++) {
115 : Node* input = node->InputAt(i);
116 1800408 : BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
117 : const BlockEffectControlData& block_effect =
118 : block_effects->For(predecessor, block);
119 1800411 : Node* effect = block_effect.current_effect;
120 1800411 : if (input != effect) {
121 132906 : node->ReplaceInput(i, effect);
122 : }
123 : }
124 796924 : }
125 :
126 4388867 : 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 4388867 : 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 7850914 : 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 12400112 : for (int i = 0; i < control->op()->ControlInputCount(); i++) {
143 4335582 : Node* input = NodeProperties::GetControlInput(control, i);
144 4335505 : BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
145 : const BlockEffectControlData& block_effect =
146 : block_effects->For(predecessor, block);
147 4335507 : if (input != block_effect.current_control) {
148 : NodeProperties::ReplaceControlInput(control, block_effect.current_control,
149 36604 : i);
150 : }
151 : }
152 : }
153 :
154 : bool HasIncomingBackEdges(BasicBlock* block) {
155 12098430 : for (BasicBlock* pred : block->predecessors()) {
156 7003316 : if (pred->rpo_number() >= block->rpo_number()) {
157 : return true;
158 : }
159 : }
160 : return false;
161 : }
162 :
163 287609 : 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 3338417 : for (Edge edge : node->use_edges()) {
170 : DCHECK(!edge.from()->IsDead());
171 1525404 : if (NodeProperties::IsEffectEdge(edge)) {
172 289041 : edge.UpdateTo(NodeProperties::GetEffectInput(node));
173 : } else {
174 : DCHECK(!NodeProperties::IsControlEdge(edge));
175 : DCHECK(!NodeProperties::IsFrameStateEdge(edge));
176 1236365 : edge.UpdateTo(node->InputAt(0));
177 : }
178 : }
179 287609 : node->Kill();
180 287609 : }
181 :
182 1087969 : 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 1087969 : source_positions->GetSourcePosition(node));
240 : NodeOriginTable::Scope origin_scope(node_origins, "clone branch", node);
241 : Node* branch = node;
242 1087977 : Node* cond = NodeProperties::GetValueInput(branch, 0);
243 2151458 : if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return;
244 110545 : Node* merge = NodeProperties::GetControlInput(branch);
245 218686 : if (merge->opcode() != IrOpcode::kMerge ||
246 108142 : NodeProperties::GetControlInput(cond) != merge) {
247 : return;
248 : }
249 : // Grab the IfTrue/IfFalse projections of the Branch.
250 108068 : BranchMatcher matcher(branch);
251 : // Check/collect other Phi/EffectPhi nodes hanging off the Merge.
252 : NodeVector phis(temp_zone);
253 712478 : for (Node* const use : merge->uses()) {
254 307145 : 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 115664 : if (!NodeProperties::IsPhi(use)) return;
260 107296 : 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 11392 : if (edge.from()->op()->ControlInputCount() != 1) return;
265 10304 : Node* control = NodeProperties::GetControlInput(edge.from());
266 10304 : if (NodeProperties::IsPhi(edge.from())) {
267 705 : control = NodeProperties::GetControlInput(control, edge.index());
268 : }
269 10304 : if (control != matcher.IfTrue() && control != matcher.IfFalse()) return;
270 : }
271 95904 : phis.push_back(use);
272 : }
273 98188 : BranchHint const hint = BranchHintOf(branch->op());
274 : int const input_count = merge->op()->ControlInputCount();
275 : DCHECK_LE(1, input_count);
276 98188 : Node** const inputs = graph->zone()->NewArray<Node*>(2 * input_count);
277 : Node** const merge_true_inputs = &inputs[0];
278 98188 : Node** const merge_false_inputs = &inputs[input_count];
279 939542 : for (int index = 0; index < input_count; ++index) {
280 420677 : Node* cond1 = NodeProperties::GetValueInput(cond, index);
281 420677 : Node* control1 = NodeProperties::GetControlInput(merge, index);
282 420677 : Node* branch1 = graph->NewNode(common->Branch(hint), cond1, control1);
283 841356 : merge_true_inputs[index] = graph->NewNode(common->IfTrue(), branch1);
284 841355 : 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 98188 : merge_true->TrimInputCount(0);
289 98188 : merge_false->TrimInputCount(0);
290 939541 : for (int i = 0; i < input_count; ++i) {
291 420676 : merge_true->AppendInput(graph->zone(), merge_true_inputs[i]);
292 420677 : merge_false->AppendInput(graph->zone(), merge_false_inputs[i]);
293 : }
294 : DCHECK_EQ(2u, block->SuccessorCount());
295 98188 : NodeProperties::ChangeOp(matcher.IfTrue(), common->Merge(input_count));
296 98188 : NodeProperties::ChangeOp(matcher.IfFalse(), common->Merge(input_count));
297 : int const true_index =
298 98188 : block->SuccessorAt(0)->NodeAt(0) == matcher.IfTrue() ? 0 : 1;
299 : BlockEffectControlData* true_block_data =
300 98188 : &block_effects->For(block, block->SuccessorAt(true_index));
301 : BlockEffectControlData* false_block_data =
302 98189 : &block_effects->For(block, block->SuccessorAt(true_index ^ 1));
303 194093 : for (Node* const phi : phis) {
304 927487 : for (int index = 0; index < input_count; ++index) {
305 831582 : inputs[index] = phi->InputAt(index);
306 : }
307 95905 : inputs[input_count] = merge_true;
308 95905 : Node* phi_true = graph->NewNode(phi->op(), input_count + 1, inputs);
309 95905 : inputs[input_count] = merge_false;
310 95905 : Node* phi_false = graph->NewNode(phi->op(), input_count + 1, inputs);
311 95905 : if (phi->UseCount() == 0) {
312 : DCHECK_EQ(phi->opcode(), IrOpcode::kEffectPhi);
313 : } else {
314 22143 : for (Edge edge : phi->use_edges()) {
315 7670 : Node* control = NodeProperties::GetControlInput(edge.from());
316 7670 : if (NodeProperties::IsPhi(edge.from())) {
317 700 : control = NodeProperties::GetControlInput(control, edge.index());
318 : }
319 : DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse());
320 7670 : edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false);
321 : }
322 : }
323 95904 : if (phi->opcode() == IrOpcode::kEffectPhi) {
324 95904 : true_block_data->current_effect = phi_true;
325 95904 : false_block_data->current_effect = phi_false;
326 : }
327 95904 : phi->Kill();
328 : }
329 : // Fix up IfTrue and IfFalse and kill all dead nodes.
330 98188 : if (branch == block->control_input()) {
331 98188 : true_block_data->current_control = merge_true;
332 98188 : false_block_data->current_control = merge_false;
333 : }
334 98188 : branch->Kill();
335 98188 : cond->Kill();
336 98188 : merge->Kill();
337 : }
338 :
339 : } // namespace
340 :
341 464413 : 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 4853285 : for (BasicBlock* block : *(schedule()->rpo_order())) {
348 : size_t instr = 0;
349 :
350 : // The control node should be the first.
351 4388876 : Node* control = block->NodeAt(instr);
352 : DCHECK(NodeProperties::IsControl(control));
353 : // Update the control inputs.
354 4388876 : 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 39803 : pending_block_controls.push_back(block);
359 : } else {
360 : // If there are no back edges, we can update now.
361 4349073 : 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 12196170 : for (; instr < block->NodeCount(); instr++) {
369 : Node* node = block->NodeAt(instr);
370 : // Only go through the phis and effect phis.
371 3854048 : 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 3068219 : } else if (node->opcode() == IrOpcode::kPhi) {
378 : // Just skip phis.
379 2754346 : } else if (node->opcode() == IrOpcode::kTerminate) {
380 : DCHECK_NULL(terminate);
381 : terminate = node;
382 : } else {
383 : break;
384 : }
385 : }
386 :
387 4388814 : if (effect_phi) {
388 : // Make sure we update the inputs to the incoming blocks' effects.
389 785839 : 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 39796 : pending_effect_phis.push_back(PendingEffectPhi(effect_phi, block));
394 : } else {
395 746043 : UpdateEffectPhi(effect_phi, block, &block_effects, jsgraph());
396 : }
397 : }
398 :
399 4388871 : Node* effect = effect_phi;
400 4388871 : if (effect == nullptr) {
401 : // There was no effect phi.
402 3603003 : if (block == schedule()->start()) {
403 : // Start block => effect is start.
404 : DCHECK_EQ(graph()->start(), control);
405 464404 : effect = graph()->start();
406 6277198 : } 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 463406 : effect = nullptr;
411 : } else {
412 : // If all the predecessors have the same effect, we can use it as our
413 : // current effect.
414 13579053 : for (size_t i = 0; i < block->PredecessorCount(); ++i) {
415 : const BlockEffectControlData& data =
416 : block_effects.For(block->PredecessorAt(i), block);
417 2753971 : if (!effect) effect = data.current_effect;
418 2753971 : if (data.current_effect != effect) {
419 11082 : effect = nullptr;
420 11082 : break;
421 : }
422 : }
423 2675213 : 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 22164 : inputs_buffer.resize(block->PredecessorCount(), jsgraph()->Dead());
429 11082 : inputs_buffer.push_back(control);
430 44328 : effect = graph()->NewNode(
431 11082 : common()->EffectPhi(static_cast<int>(block->PredecessorCount())),
432 11082 : static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front()));
433 : // For loops, we update the effect phi node later to break cycles.
434 22164 : if (control->opcode() == IrOpcode::kLoop) {
435 14 : pending_effect_phis.push_back(PendingEffectPhi(effect, block));
436 : } else {
437 11075 : UpdateEffectPhi(effect, block, &block_effects, jsgraph());
438 : }
439 5328262 : } 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 200712 : NodeProperties::ReplaceEffectInput(control, effect);
443 200711 : effect = control;
444 : }
445 : }
446 : }
447 :
448 : // Fixup the Terminate node.
449 4388890 : if (terminate != nullptr) {
450 39802 : 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 4388890 : Node* frame_state = nullptr;
459 4388890 : 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 3924451 : block_effects.For(block->PredecessorAt(0), block).current_frame_state;
464 11126756 : for (size_t i = 1; i < block->PredecessorCount(); i++) {
465 1183968 : if (block_effects.For(block->PredecessorAt(i), block)
466 1183968 : .current_frame_state != frame_state) {
467 91350 : frame_state = nullptr;
468 91350 : frame_state_zapper_ = graph()->end();
469 91350 : break;
470 : }
471 : }
472 : }
473 :
474 : // Process the ordinary instructions.
475 109929217 : for (; instr < block->NodeCount(); instr++) {
476 : Node* node = block->NodeAt(instr);
477 33717216 : ProcessNode(node, &frame_state, &effect, &control);
478 : }
479 :
480 4388822 : 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 903634 : ProcessNode(block->control_input(), &frame_state, &effect, &control);
492 903634 : break;
493 :
494 : case BasicBlock::kBranch:
495 1087984 : ProcessNode(block->control_input(), &frame_state, &effect, &control);
496 2175946 : TryCloneBranch(block->control_input(), block, temp_zone(), graph(),
497 : common(), &block_effects, source_positions_,
498 1087973 : node_origins_);
499 1087978 : break;
500 : }
501 :
502 : // Store the effect, control and frame state for later use.
503 14006365 : for (BasicBlock* successor : block->successors()) {
504 5228677 : BlockEffectControlData* data = &block_effects.For(block, successor);
505 5228733 : if (data->current_effect == nullptr) {
506 5036895 : data->current_effect = effect;
507 : }
508 5228733 : if (data->current_control == nullptr) {
509 5032335 : data->current_control = control;
510 : }
511 5228733 : data->current_frame_state = frame_state;
512 : }
513 : }
514 :
515 504212 : for (BasicBlock* pending_block_control : pending_block_controls) {
516 39802 : 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 504213 : for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) {
521 39803 : UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block,
522 39803 : &block_effects, jsgraph());
523 : }
524 464409 : }
525 :
526 35708723 : void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
527 : Node** effect, Node** control) {
528 : SourcePositionTable::Scope scope(source_positions_,
529 35708723 : source_positions_->GetSourcePosition(node));
530 35708709 : 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 35708709 : 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 67545502 : if (region_observability_ == RegionObservability::kObservable &&
542 : !node->op()->HasProperty(Operator::kNoWrite)) {
543 3658022 : *frame_state = nullptr;
544 3658022 : 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 34602028 : if (node->opcode() == IrOpcode::kFinishRegion) {
550 : // Reset the current region observability.
551 133637 : 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 133637 : return RemoveRenameNode(node);
555 : }
556 34468391 : 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 133637 : 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 133637 : return RemoveRenameNode(node);
565 : }
566 34334754 : if (node->opcode() == IrOpcode::kTypeGuard) {
567 20335 : return RemoveRenameNode(node);
568 : }
569 :
570 : // Special treatment for checkpoint nodes.
571 34314419 : 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 2752145 : *frame_state = NodeProperties::GetFrameStateInput(node);
576 2752144 : 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 31562274 : if (node->op()->EffectInputCount() > 0) {
585 : DCHECK_EQ(1, node->op()->EffectInputCount());
586 8151707 : Node* input_effect = NodeProperties::GetEffectInput(node);
587 :
588 8151705 : if (input_effect != *effect) {
589 2759144 : 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 8151608 : if (node->op()->EffectOutputCount() > 0) {
595 : DCHECK_EQ(1, node->op()->EffectOutputCount());
596 7454942 : *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 49061531 : for (int i = 0; i < node->op()->ControlInputCount(); i++) {
606 8749686 : NodeProperties::ReplaceControlInput(node, *control, i);
607 : }
608 : // Update the current control.
609 31562167 : if (node->op()->ControlOutputCount() > 0) {
610 4766392 : *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 31562167 : if (node->opcode() == IrOpcode::kUnreachable) {
616 1042 : ConnectUnreachableToEnd(*effect, *control, jsgraph());
617 1042 : *effect = *control = jsgraph()->Dead();
618 : }
619 : }
620 :
621 35708727 : bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
622 : Node* frame_state,
623 : Node** effect,
624 : Node** control) {
625 71417454 : gasm()->Reset(*effect, *control);
626 : Node* result = nullptr;
627 35708729 : switch (node->opcode()) {
628 : case IrOpcode::kChangeBitToTagged:
629 9669 : result = LowerChangeBitToTagged(node);
630 9669 : break;
631 : case IrOpcode::kChangeInt31ToTaggedSigned:
632 38859 : result = LowerChangeInt31ToTaggedSigned(node);
633 38859 : break;
634 : case IrOpcode::kChangeInt32ToTagged:
635 35934 : result = LowerChangeInt32ToTagged(node);
636 35934 : break;
637 : case IrOpcode::kChangeInt64ToTagged:
638 45 : result = LowerChangeInt64ToTagged(node);
639 45 : break;
640 : case IrOpcode::kChangeUint32ToTagged:
641 655 : result = LowerChangeUint32ToTagged(node);
642 655 : break;
643 : case IrOpcode::kChangeUint64ToTagged:
644 53 : result = LowerChangeUint64ToTagged(node);
645 53 : break;
646 : case IrOpcode::kChangeFloat64ToTagged:
647 53359 : result = LowerChangeFloat64ToTagged(node);
648 53359 : break;
649 : case IrOpcode::kChangeFloat64ToTaggedPointer:
650 91 : result = LowerChangeFloat64ToTaggedPointer(node);
651 91 : break;
652 : case IrOpcode::kChangeTaggedSignedToInt32:
653 50399 : result = LowerChangeTaggedSignedToInt32(node);
654 50399 : break;
655 : case IrOpcode::kChangeTaggedSignedToInt64:
656 298 : result = LowerChangeTaggedSignedToInt64(node);
657 298 : break;
658 : case IrOpcode::kChangeTaggedToBit:
659 139177 : result = LowerChangeTaggedToBit(node);
660 139177 : break;
661 : case IrOpcode::kChangeTaggedToInt32:
662 1743 : result = LowerChangeTaggedToInt32(node);
663 1743 : break;
664 : case IrOpcode::kChangeTaggedToUint32:
665 393 : result = LowerChangeTaggedToUint32(node);
666 393 : break;
667 : case IrOpcode::kChangeTaggedToInt64:
668 2 : result = LowerChangeTaggedToInt64(node);
669 2 : break;
670 : case IrOpcode::kChangeTaggedToFloat64:
671 : result = LowerChangeTaggedToFloat64(node);
672 11248 : 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 47635 : result = LowerTruncateTaggedToBit(node);
684 47635 : break;
685 : case IrOpcode::kTruncateTaggedPointerToBit:
686 388 : result = LowerTruncateTaggedPointerToBit(node);
687 388 : break;
688 : case IrOpcode::kTruncateTaggedToFloat64:
689 731 : result = LowerTruncateTaggedToFloat64(node);
690 731 : break;
691 : case IrOpcode::kPoisonIndex:
692 1029 : result = LowerPoisonIndex(node);
693 1029 : break;
694 : case IrOpcode::kCheckMaps:
695 51406 : LowerCheckMaps(node, frame_state);
696 51406 : break;
697 : case IrOpcode::kCompareMaps:
698 7445 : result = LowerCompareMaps(node);
699 7445 : break;
700 : case IrOpcode::kCheckNumber:
701 482 : result = LowerCheckNumber(node, frame_state);
702 482 : break;
703 : case IrOpcode::kCheckReceiver:
704 812 : result = LowerCheckReceiver(node, frame_state);
705 812 : 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 6193 : result = LowerCheckString(node, frame_state);
714 6193 : break;
715 : case IrOpcode::kCheckInternalizedString:
716 1385 : result = LowerCheckInternalizedString(node, frame_state);
717 1385 : break;
718 : case IrOpcode::kCheckIf:
719 14540 : LowerCheckIf(node, frame_state);
720 14540 : break;
721 : case IrOpcode::kCheckedInt32Add:
722 55965 : result = LowerCheckedInt32Add(node, frame_state);
723 55967 : break;
724 : case IrOpcode::kCheckedInt32Sub:
725 7636 : result = LowerCheckedInt32Sub(node, frame_state);
726 7636 : break;
727 : case IrOpcode::kCheckedInt32Div:
728 236 : result = LowerCheckedInt32Div(node, frame_state);
729 236 : break;
730 : case IrOpcode::kCheckedInt32Mod:
731 814 : result = LowerCheckedInt32Mod(node, frame_state);
732 814 : 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 5830 : result = LowerCheckedInt32Mul(node, frame_state);
741 5830 : 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 51881 : result = LowerCheckedUint32Bounds(node, frame_state);
753 51881 : break;
754 : case IrOpcode::kCheckedUint32ToInt32:
755 398 : result = LowerCheckedUint32ToInt32(node, frame_state);
756 398 : 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 24770 : 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 24770 : result = LowerCheckedTaggedSignedToInt32(node, frame_state);
781 24771 : break;
782 : case IrOpcode::kCheckedTaggedToInt32:
783 2271 : result = LowerCheckedTaggedToInt32(node, frame_state);
784 2271 : break;
785 : case IrOpcode::kCheckedTaggedToInt64:
786 87 : result = LowerCheckedTaggedToInt64(node, frame_state);
787 87 : break;
788 : case IrOpcode::kCheckedTaggedToFloat64:
789 51054 : result = LowerCheckedTaggedToFloat64(node, frame_state);
790 51054 : break;
791 : case IrOpcode::kCheckedTaggedToTaggedSigned:
792 18951 : result = LowerCheckedTaggedToTaggedSigned(node, frame_state);
793 18951 : break;
794 : case IrOpcode::kCheckedTaggedToTaggedPointer:
795 34549 : result = LowerCheckedTaggedToTaggedPointer(node, frame_state);
796 34549 : 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 508 : result = LowerTruncateTaggedToWord32(node);
811 508 : break;
812 : case IrOpcode::kCheckedTruncateTaggedToWord32:
813 1179 : result = LowerCheckedTruncateTaggedToWord32(node, frame_state);
814 1179 : break;
815 : case IrOpcode::kNumberToString:
816 966 : result = LowerNumberToString(node);
817 966 : 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 103 : result = LowerObjectIsCallable(node);
826 103 : break;
827 : case IrOpcode::kObjectIsConstructor:
828 378 : result = LowerObjectIsConstructor(node);
829 378 : break;
830 : case IrOpcode::kObjectIsDetectableCallable:
831 14107 : result = LowerObjectIsDetectableCallable(node);
832 14107 : 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 714 : result = LowerObjectIsNaN(node);
841 714 : break;
842 : case IrOpcode::kNumberIsNaN:
843 2506 : result = LowerNumberIsNaN(node);
844 2506 : break;
845 : case IrOpcode::kObjectIsNonCallable:
846 6049 : result = LowerObjectIsNonCallable(node);
847 6049 : break;
848 : case IrOpcode::kObjectIsNumber:
849 7582 : result = LowerObjectIsNumber(node);
850 7582 : break;
851 : case IrOpcode::kObjectIsReceiver:
852 19633 : result = LowerObjectIsReceiver(node);
853 19633 : break;
854 : case IrOpcode::kObjectIsSmi:
855 4133 : result = LowerObjectIsSmi(node);
856 4133 : break;
857 : case IrOpcode::kObjectIsString:
858 2227 : result = LowerObjectIsString(node);
859 2227 : break;
860 : case IrOpcode::kObjectIsSymbol:
861 23 : result = LowerObjectIsSymbol(node);
862 23 : break;
863 : case IrOpcode::kObjectIsUndetectable:
864 1428 : result = LowerObjectIsUndetectable(node);
865 1428 : break;
866 : case IrOpcode::kArgumentsFrame:
867 16920 : result = LowerArgumentsFrame(node);
868 16920 : break;
869 : case IrOpcode::kArgumentsLength:
870 16947 : result = LowerArgumentsLength(node);
871 16947 : break;
872 : case IrOpcode::kToBoolean:
873 196 : result = LowerToBoolean(node);
874 196 : break;
875 : case IrOpcode::kTypeOf:
876 21288 : result = LowerTypeOf(node);
877 21288 : break;
878 : case IrOpcode::kNewDoubleElements:
879 27 : result = LowerNewDoubleElements(node);
880 27 : break;
881 : case IrOpcode::kNewSmiOrObjectElements:
882 466 : result = LowerNewSmiOrObjectElements(node);
883 466 : break;
884 : case IrOpcode::kNewArgumentsElements:
885 16443 : result = LowerNewArgumentsElements(node);
886 16443 : break;
887 : case IrOpcode::kNewConsString:
888 5073 : result = LowerNewConsString(node);
889 5073 : break;
890 : case IrOpcode::kSameValue:
891 1 : result = LowerSameValue(node);
892 1 : break;
893 : case IrOpcode::kSameValueNumbersOnly:
894 173 : result = LowerSameValueNumbersOnly(node);
895 173 : break;
896 : case IrOpcode::kNumberSameValue:
897 77 : result = LowerNumberSameValue(node);
898 77 : break;
899 : case IrOpcode::kDeadValue:
900 1322 : result = LowerDeadValue(node);
901 1322 : break;
902 : case IrOpcode::kStringConcat:
903 20684 : result = LowerStringConcat(node);
904 20684 : break;
905 : case IrOpcode::kStringFromSingleCharCode:
906 938 : result = LowerStringFromSingleCharCode(node);
907 938 : break;
908 : case IrOpcode::kStringFromSingleCodePoint:
909 207 : result = LowerStringFromSingleCodePoint(node);
910 207 : break;
911 : case IrOpcode::kStringIndexOf:
912 266 : result = LowerStringIndexOf(node);
913 266 : break;
914 : case IrOpcode::kStringLength:
915 24360 : result = LowerStringLength(node);
916 24360 : break;
917 : case IrOpcode::kStringToNumber:
918 330 : result = LowerStringToNumber(node);
919 330 : break;
920 : case IrOpcode::kStringCharCodeAt:
921 2228 : result = LowerStringCharCodeAt(node);
922 2228 : break;
923 : case IrOpcode::kStringCodePointAt:
924 223 : result = LowerStringCodePointAt(node, UnicodeEncodingOf(node->op()));
925 223 : break;
926 : case IrOpcode::kStringToLowerCaseIntl:
927 93 : result = LowerStringToLowerCaseIntl(node);
928 93 : break;
929 : case IrOpcode::kStringToUpperCaseIntl:
930 36 : result = LowerStringToUpperCaseIntl(node);
931 36 : break;
932 : case IrOpcode::kStringSubstring:
933 1085 : result = LowerStringSubstring(node);
934 1085 : break;
935 : case IrOpcode::kStringEqual:
936 10276 : result = LowerStringEqual(node);
937 10276 : break;
938 : case IrOpcode::kStringLessThan:
939 121 : result = LowerStringLessThan(node);
940 121 : break;
941 : case IrOpcode::kStringLessThanOrEqual:
942 701 : result = LowerStringLessThanOrEqual(node);
943 701 : 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 474 : result = LowerCheckFloat64Hole(node, frame_state);
967 474 : break;
968 : case IrOpcode::kCheckNotTaggedHole:
969 104 : result = LowerCheckNotTaggedHole(node, frame_state);
970 104 : break;
971 : case IrOpcode::kConvertTaggedHoleToUndefined:
972 1667 : result = LowerConvertTaggedHoleToUndefined(node);
973 1667 : break;
974 : case IrOpcode::kCheckEqualsInternalizedString:
975 109 : LowerCheckEqualsInternalizedString(node, frame_state);
976 109 : break;
977 : case IrOpcode::kAllocate:
978 113505 : result = LowerAllocate(node);
979 113505 : 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 1648 : result = LowerEnsureWritableFastElements(node);
994 1648 : break;
995 : case IrOpcode::kMaybeGrowFastElements:
996 3481 : result = LowerMaybeGrowFastElements(node, frame_state);
997 3481 : break;
998 : case IrOpcode::kTransitionElementsKind:
999 634 : LowerTransitionElementsKind(node);
1000 634 : break;
1001 : case IrOpcode::kLoadMessage:
1002 7221 : result = LowerLoadMessage(node);
1003 7221 : break;
1004 : case IrOpcode::kStoreMessage:
1005 29729 : LowerStoreMessage(node);
1006 29729 : break;
1007 : case IrOpcode::kLoadFieldByIndex:
1008 582 : result = LowerLoadFieldByIndex(node);
1009 582 : break;
1010 : case IrOpcode::kLoadTypedElement:
1011 4527 : result = LowerLoadTypedElement(node);
1012 4527 : 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 4368 : LowerStoreTypedElement(node);
1021 4368 : 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 175 : result = LowerFindOrderedHashMapEntry(node);
1030 175 : 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 20 : LowerTransitionAndStoreNonNumberElement(node);
1039 20 : break;
1040 : case IrOpcode::kTransitionAndStoreElement:
1041 86 : LowerTransitionAndStoreElement(node);
1042 86 : break;
1043 : case IrOpcode::kRuntimeAbort:
1044 2554 : LowerRuntimeAbort(node);
1045 2554 : break;
1046 : case IrOpcode::kConvertReceiver:
1047 874 : result = LowerConvertReceiver(node);
1048 874 : break;
1049 : case IrOpcode::kFloat64RoundUp:
1050 16444 : 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 2213590 : 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 1106795 : *effect = gasm()->ExtractCurrentEffect();
1084 1106796 : *control = gasm()->ExtractCurrentControl();
1085 1106795 : NodeProperties::ReplaceUses(node, result, *effect, *control);
1086 1106794 : return true;
1087 : }
1088 :
1089 : #define __ gasm()->
1090 :
1091 53361 : Node* EffectControlLinearizer::LowerChangeFloat64ToTagged(Node* node) {
1092 53361 : CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
1093 : Node* value = node->InputAt(0);
1094 :
1095 106720 : auto done = __ MakeLabel(MachineRepresentation::kTagged);
1096 53360 : auto if_heapnumber = __ MakeDeferredLabel();
1097 53360 : auto if_int32 = __ MakeLabel();
1098 :
1099 53360 : Node* value32 = __ RoundFloat64ToInt32(value);
1100 53360 : __ GotoIf(__ Float64Equal(value, __ ChangeInt32ToFloat64(value32)),
1101 53361 : &if_int32);
1102 : __ Goto(&if_heapnumber);
1103 :
1104 : __ Bind(&if_int32);
1105 : {
1106 53361 : if (mode == CheckForMinusZeroMode::kCheckForMinusZero) {
1107 40434 : Node* zero = __ Int32Constant(0);
1108 40434 : auto if_zero = __ MakeDeferredLabel();
1109 40434 : auto if_smi = __ MakeLabel();
1110 :
1111 40434 : __ 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 40434 : __ GotoIf(__ Int32LessThan(__ Float64ExtractHighWord32(value), zero),
1118 40434 : &if_heapnumber);
1119 : __ Goto(&if_smi);
1120 : }
1121 :
1122 : __ Bind(&if_smi);
1123 : }
1124 :
1125 : if (SmiValuesAre32Bits()) {
1126 53361 : 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 53361 : Node* value_number = AllocateHeapNumberWithValue(value);
1142 : __ Goto(&done, value_number);
1143 : }
1144 :
1145 : __ Bind(&done);
1146 53361 : 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 38859 : Node* EffectControlLinearizer::LowerChangeInt31ToTaggedSigned(Node* node) {
1171 : Node* value = node->InputAt(0);
1172 38859 : return ChangeInt32ToSmi(value);
1173 : }
1174 :
1175 35934 : Node* EffectControlLinearizer::LowerChangeInt32ToTagged(Node* node) {
1176 : Node* value = node->InputAt(0);
1177 :
1178 : if (SmiValuesAre32Bits()) {
1179 35934 : 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 655 : Node* EffectControlLinearizer::LowerChangeUint32ToTagged(Node* node) {
1231 : Node* value = node->InputAt(0);
1232 :
1233 655 : auto if_not_in_smi_range = __ MakeDeferredLabel();
1234 1310 : auto done = __ MakeLabel(MachineRepresentation::kTagged);
1235 :
1236 655 : Node* check = __ Uint32LessThanOrEqual(value, SmiMaxValueConstant());
1237 655 : __ GotoIfNot(check, &if_not_in_smi_range);
1238 655 : __ Goto(&done, ChangeUint32ToSmi(value));
1239 :
1240 : __ Bind(&if_not_in_smi_range);
1241 655 : Node* number = AllocateHeapNumberWithValue(__ ChangeUint32ToFloat64(value));
1242 :
1243 : __ Goto(&done, number);
1244 : __ Bind(&done);
1245 :
1246 655 : 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 50399 : Node* EffectControlLinearizer::LowerChangeTaggedSignedToInt32(Node* node) {
1270 : Node* value = node->InputAt(0);
1271 50399 : return ChangeSmiToInt32(value);
1272 : }
1273 :
1274 298 : Node* EffectControlLinearizer::LowerChangeTaggedSignedToInt64(Node* node) {
1275 : Node* value = node->InputAt(0);
1276 298 : return ChangeSmiToInt64(value);
1277 : }
1278 :
1279 139177 : Node* EffectControlLinearizer::LowerChangeTaggedToBit(Node* node) {
1280 : Node* value = node->InputAt(0);
1281 139177 : return __ WordEqual(value, __ TrueConstant());
1282 : }
1283 :
1284 48023 : void EffectControlLinearizer::TruncateTaggedPointerToBit(
1285 : Node* node, GraphAssemblerLabel<1>* done) {
1286 : Node* value = node->InputAt(0);
1287 :
1288 48023 : auto if_heapnumber = __ MakeDeferredLabel();
1289 48023 : auto if_bigint = __ MakeDeferredLabel();
1290 :
1291 48023 : Node* zero = __ Int32Constant(0);
1292 48023 : Node* fzero = __ Float64Constant(0.0);
1293 :
1294 : // Check if {value} is false.
1295 48023 : __ GotoIf(__ WordEqual(value, __ FalseConstant()), done, zero);
1296 :
1297 : // Check if {value} is the empty string.
1298 48023 : __ GotoIf(__ WordEqual(value, __ EmptyStringConstant()), done, zero);
1299 :
1300 : // Load the map of {value}.
1301 48023 : 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 48023 : __ LoadField(AccessBuilder::ForMapBitField(), value_map);
1307 48023 : __ GotoIfNot(
1308 : __ Word32Equal(
1309 : __ Word32And(value_map_bitfield,
1310 : __ Int32Constant(Map::IsUndetectableBit::kMask)),
1311 : zero),
1312 48023 : done, zero);
1313 :
1314 : // Check if {value} is a HeapNumber.
1315 48023 : __ GotoIf(__ WordEqual(value_map, __ HeapNumberMapConstant()),
1316 48023 : &if_heapnumber);
1317 :
1318 : // Check if {value} is a BigInt.
1319 48023 : __ GotoIf(__ WordEqual(value_map, __ BigIntMapConstant()), &if_bigint);
1320 :
1321 : // All other values that reach here are true.
1322 48023 : __ 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 48023 : __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
1330 48023 : __ Goto(done, __ Float64LessThan(fzero, __ Float64Abs(value_value)));
1331 : }
1332 :
1333 : __ Bind(&if_bigint);
1334 : {
1335 48023 : Node* bitfield = __ LoadField(AccessBuilder::ForBigIntBitfield(), value);
1336 48023 : Node* length_is_zero = __ Word32Equal(
1337 : __ Word32And(bitfield, __ Int32Constant(BigInt::LengthBits::kMask)),
1338 48023 : __ Int32Constant(0));
1339 48023 : __ Goto(done, __ Word32Equal(length_is_zero, zero));
1340 : }
1341 48023 : }
1342 :
1343 47635 : Node* EffectControlLinearizer::LowerTruncateTaggedToBit(Node* node) {
1344 95270 : auto done = __ MakeLabel(MachineRepresentation::kBit);
1345 47635 : auto if_smi = __ MakeDeferredLabel();
1346 :
1347 : Node* value = node->InputAt(0);
1348 95270 : __ GotoIf(ObjectIsSmi(value), &if_smi);
1349 :
1350 47635 : 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 47635 : __ Goto(&done, __ Word32Equal(__ WordEqual(value, __ IntPtrConstant(0)),
1356 : __ Int32Constant(0)));
1357 : }
1358 :
1359 : __ Bind(&done);
1360 47635 : return done.PhiAt(0);
1361 : }
1362 :
1363 388 : Node* EffectControlLinearizer::LowerTruncateTaggedPointerToBit(Node* node) {
1364 776 : auto done = __ MakeLabel(MachineRepresentation::kBit);
1365 :
1366 388 : TruncateTaggedPointerToBit(node, &done);
1367 :
1368 : __ Bind(&done);
1369 388 : return done.PhiAt(0);
1370 : }
1371 :
1372 1743 : Node* EffectControlLinearizer::LowerChangeTaggedToInt32(Node* node) {
1373 : Node* value = node->InputAt(0);
1374 :
1375 1743 : auto if_not_smi = __ MakeDeferredLabel();
1376 3486 : auto done = __ MakeLabel(MachineRepresentation::kWord32);
1377 :
1378 1743 : Node* check = ObjectIsSmi(value);
1379 1743 : __ GotoIfNot(check, &if_not_smi);
1380 1743 : __ Goto(&done, ChangeSmiToInt32(value));
1381 :
1382 : __ Bind(&if_not_smi);
1383 : STATIC_ASSERT_FIELD_OFFSETS_EQUAL(HeapNumber::kValueOffset,
1384 : Oddball::kToNumberRawOffset);
1385 1743 : Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
1386 1743 : vfalse = __ ChangeFloat64ToInt32(vfalse);
1387 : __ Goto(&done, vfalse);
1388 :
1389 : __ Bind(&done);
1390 1743 : return done.PhiAt(0);
1391 : }
1392 :
1393 393 : Node* EffectControlLinearizer::LowerChangeTaggedToUint32(Node* node) {
1394 : Node* value = node->InputAt(0);
1395 :
1396 393 : auto if_not_smi = __ MakeDeferredLabel();
1397 786 : auto done = __ MakeLabel(MachineRepresentation::kWord32);
1398 :
1399 393 : Node* check = ObjectIsSmi(value);
1400 393 : __ GotoIfNot(check, &if_not_smi);
1401 393 : __ Goto(&done, ChangeSmiToInt32(value));
1402 :
1403 : __ Bind(&if_not_smi);
1404 : STATIC_ASSERT_FIELD_OFFSETS_EQUAL(HeapNumber::kValueOffset,
1405 : Oddball::kToNumberRawOffset);
1406 393 : Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
1407 393 : vfalse = __ ChangeFloat64ToUint32(vfalse);
1408 : __ Goto(&done, vfalse);
1409 :
1410 : __ Bind(&done);
1411 393 : 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 11248 : 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 11979 : Node* EffectControlLinearizer::LowerTruncateTaggedToFloat64(Node* node) {
1506 : Node* value = node->InputAt(0);
1507 :
1508 11979 : auto if_not_smi = __ MakeDeferredLabel();
1509 23958 : auto done = __ MakeLabel(MachineRepresentation::kFloat64);
1510 :
1511 11979 : Node* check = ObjectIsSmi(value);
1512 11979 : __ GotoIfNot(check, &if_not_smi);
1513 11979 : Node* vtrue = ChangeSmiToInt32(value);
1514 11979 : 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 11979 : Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
1521 : __ Goto(&done, vfalse);
1522 :
1523 : __ Bind(&done);
1524 11979 : return done.PhiAt(0);
1525 : }
1526 :
1527 1029 : Node* EffectControlLinearizer::LowerPoisonIndex(Node* node) {
1528 : Node* index = node->InputAt(0);
1529 1029 : if (mask_array_index_ == kMaskArrayIndex) {
1530 0 : index = __ Word32PoisonOnSpeculation(index);
1531 : }
1532 1029 : return index;
1533 : }
1534 :
1535 51406 : void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
1536 51406 : 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 51406 : if (p.flags() & CheckMapsFlag::kTryMigrateInstance) {
1543 49 : auto done = __ MakeLabel();
1544 49 : auto migrate = __ MakeDeferredLabel();
1545 :
1546 : // Load the current map of the {value}.
1547 98 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
1548 :
1549 : // Perform the map checks.
1550 153 : for (size_t i = 0; i < map_count; ++i) {
1551 52 : Node* map = __ HeapConstant(maps[i]);
1552 52 : Node* check = __ WordEqual(value_map, map);
1553 52 : if (i == map_count - 1) {
1554 49 : __ 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 49 : __ LoadField(AccessBuilder::ForMapBitField3(), value_map);
1568 49 : Node* if_not_deprecated = __ WordEqual(
1569 : __ Word32And(bitfield3,
1570 : __ Int32Constant(Map::IsDeprecatedBit::kMask)),
1571 49 : __ Int32Constant(0));
1572 : __ DeoptimizeIf(DeoptimizeReason::kWrongMap, p.feedback(),
1573 : if_not_deprecated, frame_state,
1574 49 : IsSafetyCheck::kCriticalSafetyCheck);
1575 :
1576 49 : Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
1577 : Runtime::FunctionId id = Runtime::kTryMigrateInstance;
1578 49 : auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
1579 49 : graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
1580 49 : Node* result = __ Call(call_descriptor, __ CEntryStubConstant(1), value,
1581 : __ ExternalConstant(ExternalReference::Create(id)),
1582 49 : __ Int32Constant(1), __ NoContextConstant());
1583 49 : Node* check = ObjectIsSmi(result);
1584 : __ DeoptimizeIf(DeoptimizeReason::kInstanceMigrationFailed, p.feedback(),
1585 49 : check, frame_state, IsSafetyCheck::kCriticalSafetyCheck);
1586 : }
1587 :
1588 : // Reload the current map of the {value}.
1589 49 : value_map = __ LoadField(AccessBuilder::ForMap(), value);
1590 :
1591 : // Perform the map checks again.
1592 153 : for (size_t i = 0; i < map_count; ++i) {
1593 52 : Node* map = __ HeapConstant(maps[i]);
1594 52 : Node* check = __ WordEqual(value_map, map);
1595 52 : if (i == map_count - 1) {
1596 : __ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, p.feedback(), check,
1597 49 : 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 51357 : auto done = __ MakeLabel();
1609 :
1610 : // Load the current map of the {value}.
1611 : Node* value_map =
1612 : UsingCompressedPointers()
1613 : ? __ LoadField(AccessBuilder::ForCompressedMap(), value)
1614 102714 : : __ LoadField(AccessBuilder::ForMap(), value);
1615 :
1616 165749 : 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 57196 : Node* map = __ HeapConstant(maps[i]);
1629 57196 : check = __ WordEqual(value_map, map);
1630 : }
1631 :
1632 57196 : if (i == map_count - 1) {
1633 : __ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, p.feedback(), check,
1634 51357 : frame_state, IsSafetyCheck::kCriticalSafetyCheck);
1635 : } else {
1636 5839 : auto next_map = __ MakeLabel();
1637 5839 : __ Branch(check, &done, &next_map, IsSafetyCheck::kCriticalSafetyCheck);
1638 : __ Bind(&next_map);
1639 : }
1640 : }
1641 : __ Goto(&done);
1642 : __ Bind(&done);
1643 : }
1644 51406 : }
1645 :
1646 7445 : Node* EffectControlLinearizer::LowerCompareMaps(Node* node) {
1647 7445 : ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op());
1648 : size_t const map_count = maps.size();
1649 : Node* value = node->InputAt(0);
1650 :
1651 14890 : 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 14890 : : __ LoadField(AccessBuilder::ForMap(), value);
1657 :
1658 22351 : 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 7453 : Node* map = __ HeapConstant(maps[i]);
1671 7453 : check = __ WordEqual(value_map, map);
1672 : }
1673 :
1674 7453 : auto next_map = __ MakeLabel();
1675 7453 : auto passed = __ MakeLabel();
1676 7453 : __ Branch(check, &passed, &next_map, IsSafetyCheck::kCriticalSafetyCheck);
1677 :
1678 : __ Bind(&passed);
1679 7453 : __ Goto(&done, __ Int32Constant(1));
1680 :
1681 : __ Bind(&next_map);
1682 : }
1683 7445 : __ Goto(&done, __ Int32Constant(0));
1684 :
1685 : __ Bind(&done);
1686 7445 : return done.PhiAt(0);
1687 : }
1688 :
1689 482 : Node* EffectControlLinearizer::LowerCheckNumber(Node* node, Node* frame_state) {
1690 : Node* value = node->InputAt(0);
1691 482 : const CheckParameters& params = CheckParametersOf(node->op());
1692 :
1693 482 : auto if_not_smi = __ MakeDeferredLabel();
1694 482 : auto done = __ MakeLabel();
1695 :
1696 482 : Node* check0 = ObjectIsSmi(value);
1697 482 : __ GotoIfNot(check0, &if_not_smi);
1698 : __ Goto(&done);
1699 :
1700 : __ Bind(&if_not_smi);
1701 482 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
1702 482 : Node* check1 = __ WordEqual(value_map, __ HeapNumberMapConstant());
1703 : __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, params.feedback(),
1704 482 : check1, frame_state);
1705 : __ Goto(&done);
1706 :
1707 : __ Bind(&done);
1708 482 : return value;
1709 : }
1710 :
1711 812 : Node* EffectControlLinearizer::LowerCheckReceiver(Node* node,
1712 : Node* frame_state) {
1713 : Node* value = node->InputAt(0);
1714 :
1715 1624 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
1716 : Node* value_instance_type =
1717 812 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
1718 :
1719 : STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
1720 812 : Node* check = __ Uint32LessThanOrEqual(
1721 812 : __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type);
1722 1624 : __ DeoptimizeIfNot(DeoptimizeReason::kNotAJavaScriptObject, VectorSlotPair(),
1723 812 : check, frame_state);
1724 812 : 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 6193 : Node* EffectControlLinearizer::LowerCheckString(Node* node, Node* frame_state) {
1763 : Node* value = node->InputAt(0);
1764 6193 : const CheckParameters& params = CheckParametersOf(node->op());
1765 :
1766 12386 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
1767 : Node* value_instance_type =
1768 6193 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
1769 :
1770 6193 : Node* check = __ Uint32LessThan(value_instance_type,
1771 6193 : __ Uint32Constant(FIRST_NONSTRING_TYPE));
1772 : __ DeoptimizeIfNot(DeoptimizeReason::kNotAString, params.feedback(), check,
1773 6193 : frame_state);
1774 6193 : return value;
1775 : }
1776 :
1777 1385 : Node* EffectControlLinearizer::LowerCheckInternalizedString(Node* node,
1778 : Node* frame_state) {
1779 : Node* value = node->InputAt(0);
1780 :
1781 2770 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
1782 : Node* value_instance_type =
1783 1385 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
1784 :
1785 1385 : Node* check = __ Word32Equal(
1786 : __ Word32And(value_instance_type,
1787 : __ Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)),
1788 1385 : __ Int32Constant(kInternalizedTag));
1789 2770 : __ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, VectorSlotPair(),
1790 1385 : check, frame_state);
1791 :
1792 1385 : return value;
1793 : }
1794 :
1795 14540 : void EffectControlLinearizer::LowerCheckIf(Node* node, Node* frame_state) {
1796 : Node* value = node->InputAt(0);
1797 14540 : const CheckIfParameters& p = CheckIfParametersOf(node->op());
1798 14540 : __ DeoptimizeIfNot(p.reason(), p.feedback(), value, frame_state);
1799 14540 : }
1800 :
1801 20684 : Node* EffectControlLinearizer::LowerStringConcat(Node* node) {
1802 : Node* lhs = node->InputAt(1);
1803 : Node* rhs = node->InputAt(2);
1804 :
1805 : Callable const callable =
1806 20684 : CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE);
1807 20684 : auto call_descriptor = Linkage::GetStubCallDescriptor(
1808 20684 : graph()->zone(), callable.descriptor(),
1809 : callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
1810 20684 : Operator::kNoDeopt | Operator::kNoWrite | Operator::kNoThrow);
1811 :
1812 : Node* value =
1813 62052 : __ Call(call_descriptor, jsgraph()->HeapConstant(callable.code()), lhs,
1814 20684 : rhs, __ NoContextConstant());
1815 :
1816 20684 : return value;
1817 : }
1818 :
1819 55965 : Node* EffectControlLinearizer::LowerCheckedInt32Add(Node* node,
1820 : Node* frame_state) {
1821 : Node* lhs = node->InputAt(0);
1822 : Node* rhs = node->InputAt(1);
1823 :
1824 55965 : Node* value = __ Int32AddWithOverflow(lhs, rhs);
1825 55969 : Node* check = __ Projection(1, value);
1826 111932 : __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check,
1827 55968 : frame_state);
1828 55966 : return __ Projection(0, value);
1829 : }
1830 :
1831 7636 : Node* EffectControlLinearizer::LowerCheckedInt32Sub(Node* node,
1832 : Node* frame_state) {
1833 : Node* lhs = node->InputAt(0);
1834 : Node* rhs = node->InputAt(1);
1835 :
1836 7636 : Node* value = __ Int32SubWithOverflow(lhs, rhs);
1837 7636 : Node* check = __ Projection(1, value);
1838 15272 : __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check,
1839 7636 : frame_state);
1840 7636 : return __ Projection(0, value);
1841 : }
1842 :
1843 236 : Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node,
1844 : Node* frame_state) {
1845 : Node* lhs = node->InputAt(0);
1846 : Node* rhs = node->InputAt(1);
1847 236 : Node* zero = __ Int32Constant(0);
1848 :
1849 : // Check if the {rhs} is a known power of two.
1850 : Int32Matcher m(rhs);
1851 236 : 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 135 : Node* mask = __ Int32Constant(divisor - 1);
1859 135 : Node* shift = __ Int32Constant(WhichPowerOf2(divisor));
1860 135 : Node* check = __ Word32Equal(__ Word32And(lhs, mask), zero);
1861 270 : __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, VectorSlotPair(),
1862 135 : check, frame_state);
1863 135 : 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 851 : Node* EffectControlLinearizer::BuildUint32Mod(Node* lhs, Node* rhs) {
1931 851 : auto if_rhs_power_of_two = __ MakeLabel();
1932 1702 : auto done = __ MakeLabel(MachineRepresentation::kWord32);
1933 :
1934 : // Compute the mask for the {rhs}.
1935 851 : Node* one = __ Int32Constant(1);
1936 851 : Node* msk = __ Int32Sub(rhs, one);
1937 :
1938 : // Check if the {rhs} is a power of two.
1939 851 : __ GotoIf(__ Word32Equal(__ Word32And(rhs, msk), __ Int32Constant(0)),
1940 851 : &if_rhs_power_of_two);
1941 : {
1942 : // The {rhs} is not a power of two, do a generic Uint32Mod.
1943 851 : __ 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 851 : __ Goto(&done, __ Word32And(lhs, msk));
1950 : }
1951 :
1952 : __ Bind(&done);
1953 851 : return done.PhiAt(0);
1954 : }
1955 :
1956 814 : 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 814 : auto if_rhs_not_positive = __ MakeDeferredLabel();
1986 814 : auto if_lhs_negative = __ MakeDeferredLabel();
1987 : auto if_rhs_power_of_two = __ MakeLabel();
1988 1628 : auto rhs_checked = __ MakeLabel(MachineRepresentation::kWord32);
1989 1628 : auto done = __ MakeLabel(MachineRepresentation::kWord32);
1990 :
1991 814 : Node* zero = __ Int32Constant(0);
1992 :
1993 : // Check if {rhs} is not strictly positive.
1994 814 : Node* check0 = __ Int32LessThanOrEqual(rhs, zero);
1995 814 : __ 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 814 : Node* vtrue0 = __ Int32Sub(zero, rhs);
2003 :
2004 : // Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
2005 1628 : __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(),
2006 814 : __ Word32Equal(vtrue0, zero), frame_state);
2007 : __ Goto(&rhs_checked, vtrue0);
2008 : }
2009 :
2010 : __ Bind(&rhs_checked);
2011 : rhs = rhs_checked.PhiAt(0);
2012 :
2013 814 : __ GotoIf(__ Int32LessThan(lhs, zero), &if_lhs_negative);
2014 : {
2015 : // The {lhs} is a non-negative integer.
2016 814 : __ 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 814 : Node* res = __ Uint32Mod(__ Int32Sub(zero, lhs), rhs);
2026 :
2027 : // Check if we would have to return -0.
2028 1628 : __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(),
2029 814 : __ Word32Equal(res, zero), frame_state);
2030 814 : __ Goto(&done, __ Int32Sub(zero, res));
2031 : }
2032 :
2033 : __ Bind(&done);
2034 814 : 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 5830 : Node* EffectControlLinearizer::LowerCheckedInt32Mul(Node* node,
2092 : Node* frame_state) {
2093 5830 : CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
2094 : Node* lhs = node->InputAt(0);
2095 : Node* rhs = node->InputAt(1);
2096 :
2097 5830 : Node* projection = __ Int32MulWithOverflow(lhs, rhs);
2098 5830 : Node* check = __ Projection(1, projection);
2099 11660 : __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check,
2100 5830 : frame_state);
2101 :
2102 5830 : Node* value = __ Projection(0, projection);
2103 :
2104 5830 : if (mode == CheckForMinusZeroMode::kCheckForMinusZero) {
2105 3930 : auto if_zero = __ MakeDeferredLabel();
2106 3930 : auto check_done = __ MakeLabel();
2107 3930 : Node* zero = __ Int32Constant(0);
2108 3930 : Node* check_zero = __ Word32Equal(value, zero);
2109 3930 : __ GotoIf(check_zero, &if_zero);
2110 : __ Goto(&check_done);
2111 :
2112 : __ Bind(&if_zero);
2113 : // We may need to return negative zero.
2114 3930 : Node* check_or = __ Int32LessThan(__ Word32Or(lhs, rhs), zero);
2115 7860 : __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(), check_or,
2116 3930 : frame_state);
2117 : __ Goto(&check_done);
2118 :
2119 : __ Bind(&check_done);
2120 : }
2121 :
2122 5830 : 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 51881 : Node* EffectControlLinearizer::LowerCheckedUint32Bounds(Node* node,
2176 : Node* frame_state) {
2177 : Node* index = node->InputAt(0);
2178 : Node* limit = node->InputAt(1);
2179 51881 : const CheckBoundsParameters& params = CheckBoundsParametersOf(node->op());
2180 :
2181 51881 : Node* check = __ Uint32LessThan(index, limit);
2182 51881 : switch (params.mode()) {
2183 : case CheckBoundsParameters::kDeoptOnOutOfBounds:
2184 : __ DeoptimizeIfNot(DeoptimizeReason::kOutOfBounds,
2185 : params.check_parameters().feedback(), check,
2186 47374 : frame_state, IsSafetyCheck::kCriticalSafetyCheck);
2187 47374 : break;
2188 : case CheckBoundsParameters::kAbortOnOutOfBounds: {
2189 4507 : auto if_abort = __ MakeDeferredLabel();
2190 4507 : auto done = __ MakeLabel();
2191 :
2192 4507 : __ Branch(check, &done, &if_abort);
2193 :
2194 : __ Bind(&if_abort);
2195 4507 : __ Unreachable();
2196 : __ Goto(&done);
2197 :
2198 : __ Bind(&done);
2199 : break;
2200 : }
2201 : }
2202 :
2203 51881 : return index;
2204 : }
2205 :
2206 398 : Node* EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node,
2207 : Node* frame_state) {
2208 : Node* value = node->InputAt(0);
2209 398 : const CheckParameters& params = CheckParametersOf(node->op());
2210 398 : Node* unsafe = __ Int32LessThan(value, __ Int32Constant(0));
2211 : __ DeoptimizeIf(DeoptimizeReason::kLostPrecision, params.feedback(), unsafe,
2212 398 : frame_state);
2213 398 : 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 4586 : Node* EffectControlLinearizer::BuildCheckedFloat64ToInt32(
2262 : CheckForMinusZeroMode mode, const VectorSlotPair& feedback, Node* value,
2263 : Node* frame_state) {
2264 4586 : Node* value32 = __ RoundFloat64ToInt32(value);
2265 4586 : Node* check_same = __ Float64Equal(value, __ ChangeInt32ToFloat64(value32));
2266 : __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecisionOrNaN, feedback,
2267 4586 : check_same, frame_state);
2268 :
2269 4586 : 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 4586 : 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 24770 : Node* EffectControlLinearizer::LowerCheckedTaggedSignedToInt32(
2340 : Node* node, Node* frame_state) {
2341 : Node* value = node->InputAt(0);
2342 24770 : const CheckParameters& params = CheckParametersOf(node->op());
2343 24769 : Node* check = ObjectIsSmi(value);
2344 : __ DeoptimizeIfNot(DeoptimizeReason::kNotASmi, params.feedback(), check,
2345 24769 : frame_state);
2346 24770 : return ChangeSmiToInt32(value);
2347 : }
2348 :
2349 2271 : Node* EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node,
2350 : Node* frame_state) {
2351 : const CheckMinusZeroParameters& params =
2352 2271 : CheckMinusZeroParametersOf(node->op());
2353 : Node* value = node->InputAt(0);
2354 :
2355 2271 : auto if_not_smi = __ MakeDeferredLabel();
2356 4542 : auto done = __ MakeLabel(MachineRepresentation::kWord32);
2357 :
2358 2271 : Node* check = ObjectIsSmi(value);
2359 2271 : __ GotoIfNot(check, &if_not_smi);
2360 : // In the Smi case, just convert to int32.
2361 2271 : __ 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 2271 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2367 2271 : Node* check_map = __ WordEqual(value_map, __ HeapNumberMapConstant());
2368 : __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, params.feedback(),
2369 2271 : check_map, frame_state);
2370 2271 : Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
2371 : vfalse = BuildCheckedFloat64ToInt32(params.mode(), params.feedback(), vfalse,
2372 2271 : frame_state);
2373 : __ Goto(&done, vfalse);
2374 :
2375 : __ Bind(&done);
2376 2271 : 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 52233 : Node* EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64(
2410 : CheckTaggedInputMode mode, const VectorSlotPair& feedback, Node* value,
2411 : Node* frame_state) {
2412 104466 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2413 52233 : Node* check_number = __ WordEqual(value_map, __ HeapNumberMapConstant());
2414 52233 : switch (mode) {
2415 : case CheckTaggedInputMode::kNumber: {
2416 : __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, feedback,
2417 8302 : check_number, frame_state);
2418 8302 : break;
2419 : }
2420 : case CheckTaggedInputMode::kNumberOrOddball: {
2421 43931 : auto check_done = __ MakeLabel();
2422 :
2423 43931 : __ 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 43931 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
2428 : Node* check_oddball =
2429 43931 : __ Word32Equal(instance_type, __ Int32Constant(ODDBALL_TYPE));
2430 : __ DeoptimizeIfNot(DeoptimizeReason::kNotANumberOrOddball, feedback,
2431 43931 : 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 52233 : return __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
2441 : }
2442 :
2443 51054 : Node* EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node,
2444 : Node* frame_state) {
2445 : CheckTaggedInputParameters const& p =
2446 51054 : CheckTaggedInputParametersOf(node->op());
2447 : Node* value = node->InputAt(0);
2448 :
2449 51054 : auto if_smi = __ MakeLabel();
2450 102108 : auto done = __ MakeLabel(MachineRepresentation::kFloat64);
2451 :
2452 51054 : Node* check = ObjectIsSmi(value);
2453 51054 : __ 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 51054 : p.mode(), p.feedback(), value, frame_state);
2459 : __ Goto(&done, number);
2460 :
2461 : __ Bind(&if_smi);
2462 51054 : Node* from_smi = ChangeSmiToInt32(value);
2463 51054 : from_smi = __ ChangeInt32ToFloat64(from_smi);
2464 : __ Goto(&done, from_smi);
2465 :
2466 : __ Bind(&done);
2467 51054 : return done.PhiAt(0);
2468 : }
2469 :
2470 18951 : Node* EffectControlLinearizer::LowerCheckedTaggedToTaggedSigned(
2471 : Node* node, Node* frame_state) {
2472 : Node* value = node->InputAt(0);
2473 18951 : const CheckParameters& params = CheckParametersOf(node->op());
2474 :
2475 18951 : Node* check = ObjectIsSmi(value);
2476 : __ DeoptimizeIfNot(DeoptimizeReason::kNotASmi, params.feedback(), check,
2477 18951 : frame_state);
2478 :
2479 18951 : return value;
2480 : }
2481 :
2482 34549 : Node* EffectControlLinearizer::LowerCheckedTaggedToTaggedPointer(
2483 : Node* node, Node* frame_state) {
2484 : Node* value = node->InputAt(0);
2485 34549 : const CheckParameters& params = CheckParametersOf(node->op());
2486 :
2487 34549 : Node* check = ObjectIsSmi(value);
2488 : __ DeoptimizeIf(DeoptimizeReason::kSmi, params.feedback(), check,
2489 34549 : frame_state);
2490 34549 : 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 508 : Node* EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node) {
2540 : Node* value = node->InputAt(0);
2541 :
2542 508 : auto if_not_smi = __ MakeDeferredLabel();
2543 1016 : auto done = __ MakeLabel(MachineRepresentation::kWord32);
2544 :
2545 508 : Node* check = ObjectIsSmi(value);
2546 508 : __ GotoIfNot(check, &if_not_smi);
2547 508 : __ Goto(&done, ChangeSmiToInt32(value));
2548 :
2549 : __ Bind(&if_not_smi);
2550 : STATIC_ASSERT_FIELD_OFFSETS_EQUAL(HeapNumber::kValueOffset,
2551 : Oddball::kToNumberRawOffset);
2552 508 : Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
2553 508 : vfalse = __ TruncateFloat64ToWord32(vfalse);
2554 : __ Goto(&done, vfalse);
2555 :
2556 : __ Bind(&done);
2557 508 : return done.PhiAt(0);
2558 : }
2559 :
2560 1179 : Node* EffectControlLinearizer::LowerCheckedTruncateTaggedToWord32(
2561 : Node* node, Node* frame_state) {
2562 : const CheckTaggedInputParameters& params =
2563 1179 : CheckTaggedInputParametersOf(node->op());
2564 : Node* value = node->InputAt(0);
2565 :
2566 1179 : auto if_not_smi = __ MakeLabel();
2567 2358 : auto done = __ MakeLabel(MachineRepresentation::kWord32);
2568 :
2569 1179 : Node* check = ObjectIsSmi(value);
2570 1179 : __ GotoIfNot(check, &if_not_smi);
2571 : // In the Smi case, just convert to int32.
2572 1179 : __ 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 1179 : params.mode(), params.feedback(), value, frame_state);
2579 1179 : number = __ TruncateFloat64ToWord32(number);
2580 : __ Goto(&done, number);
2581 :
2582 : __ Bind(&done);
2583 1179 : return done.PhiAt(0);
2584 : }
2585 :
2586 113505 : Node* EffectControlLinearizer::LowerAllocate(Node* node) {
2587 : Node* size = node->InputAt(0);
2588 113505 : AllocationType allocation = AllocationTypeOf(node->op());
2589 113505 : Node* new_node = __ Allocate(allocation, size);
2590 113505 : return new_node;
2591 : }
2592 :
2593 966 : Node* EffectControlLinearizer::LowerNumberToString(Node* node) {
2594 : Node* argument = node->InputAt(0);
2595 :
2596 : Callable const callable =
2597 966 : Builtins::CallableFor(isolate(), Builtins::kNumberToString);
2598 : Operator::Properties properties = Operator::kEliminatable;
2599 : CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
2600 : auto call_descriptor = Linkage::GetStubCallDescriptor(
2601 966 : graph()->zone(), callable.descriptor(),
2602 966 : callable.descriptor().GetStackParameterCount(), flags, properties);
2603 2898 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), argument,
2604 1932 : __ 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 103 : Node* EffectControlLinearizer::LowerObjectIsCallable(Node* node) {
2652 : Node* value = node->InputAt(0);
2653 :
2654 103 : auto if_smi = __ MakeDeferredLabel();
2655 206 : auto done = __ MakeLabel(MachineRepresentation::kBit);
2656 :
2657 103 : Node* check = ObjectIsSmi(value);
2658 103 : __ GotoIf(check, &if_smi);
2659 :
2660 103 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2661 : Node* value_bit_field =
2662 103 : __ LoadField(AccessBuilder::ForMapBitField(), value_map);
2663 : Node* vfalse =
2664 103 : __ Word32Equal(__ Int32Constant(Map::IsCallableBit::kMask),
2665 : __ Word32And(value_bit_field,
2666 103 : __ Int32Constant(Map::IsCallableBit::kMask)));
2667 : __ Goto(&done, vfalse);
2668 :
2669 : __ Bind(&if_smi);
2670 103 : __ Goto(&done, __ Int32Constant(0));
2671 :
2672 : __ Bind(&done);
2673 103 : return done.PhiAt(0);
2674 : }
2675 :
2676 378 : Node* EffectControlLinearizer::LowerObjectIsConstructor(Node* node) {
2677 : Node* value = node->InputAt(0);
2678 :
2679 378 : auto if_smi = __ MakeDeferredLabel();
2680 756 : auto done = __ MakeLabel(MachineRepresentation::kBit);
2681 :
2682 378 : Node* check = ObjectIsSmi(value);
2683 378 : __ GotoIf(check, &if_smi);
2684 :
2685 378 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2686 : Node* value_bit_field =
2687 378 : __ LoadField(AccessBuilder::ForMapBitField(), value_map);
2688 378 : Node* vfalse = __ Word32Equal(
2689 : __ Int32Constant(Map::IsConstructorBit::kMask),
2690 : __ Word32And(value_bit_field,
2691 378 : __ Int32Constant(Map::IsConstructorBit::kMask)));
2692 : __ Goto(&done, vfalse);
2693 :
2694 : __ Bind(&if_smi);
2695 378 : __ Goto(&done, __ Int32Constant(0));
2696 :
2697 : __ Bind(&done);
2698 378 : return done.PhiAt(0);
2699 : }
2700 :
2701 14107 : Node* EffectControlLinearizer::LowerObjectIsDetectableCallable(Node* node) {
2702 : Node* value = node->InputAt(0);
2703 :
2704 14107 : auto if_smi = __ MakeDeferredLabel();
2705 28214 : auto done = __ MakeLabel(MachineRepresentation::kBit);
2706 :
2707 14107 : Node* check = ObjectIsSmi(value);
2708 14107 : __ GotoIf(check, &if_smi);
2709 :
2710 14107 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2711 : Node* value_bit_field =
2712 14107 : __ LoadField(AccessBuilder::ForMapBitField(), value_map);
2713 14107 : Node* vfalse = __ Word32Equal(
2714 : __ Int32Constant(Map::IsCallableBit::kMask),
2715 : __ Word32And(value_bit_field,
2716 : __ Int32Constant((Map::IsCallableBit::kMask) |
2717 14107 : (Map::IsUndetectableBit::kMask))));
2718 : __ Goto(&done, vfalse);
2719 :
2720 : __ Bind(&if_smi);
2721 14107 : __ Goto(&done, __ Int32Constant(0));
2722 :
2723 : __ Bind(&done);
2724 14107 : 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 714 : Node* EffectControlLinearizer::LowerObjectIsNaN(Node* node) {
2908 : Node* value = node->InputAt(0);
2909 714 : Node* zero = __ Int32Constant(0);
2910 :
2911 1428 : auto done = __ MakeLabel(MachineRepresentation::kBit);
2912 :
2913 : // Check if {value} is a Smi.
2914 714 : __ GotoIf(ObjectIsSmi(value), &done, zero);
2915 :
2916 : // Check if {value} is a HeapNumber.
2917 714 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2918 714 : __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
2919 714 : zero);
2920 :
2921 : // Check if {value} contains a NaN.
2922 714 : Node* value_value = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
2923 714 : __ Goto(&done,
2924 : __ Word32Equal(__ Float64Equal(value_value, value_value), zero));
2925 :
2926 : __ Bind(&done);
2927 714 : return done.PhiAt(0);
2928 : }
2929 :
2930 2506 : Node* EffectControlLinearizer::LowerNumberIsNaN(Node* node) {
2931 : Node* number = node->InputAt(0);
2932 2506 : Node* diff = __ Float64Equal(number, number);
2933 2506 : Node* check = __ Word32Equal(diff, __ Int32Constant(0));
2934 2506 : return check;
2935 : }
2936 :
2937 6049 : Node* EffectControlLinearizer::LowerObjectIsNonCallable(Node* node) {
2938 : Node* value = node->InputAt(0);
2939 :
2940 6049 : auto if_primitive = __ MakeDeferredLabel();
2941 12098 : auto done = __ MakeLabel(MachineRepresentation::kBit);
2942 :
2943 6049 : Node* check0 = ObjectIsSmi(value);
2944 6049 : __ GotoIf(check0, &if_primitive);
2945 :
2946 6049 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2947 : Node* value_instance_type =
2948 6049 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
2949 : STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2950 6049 : Node* check1 = __ Uint32LessThanOrEqual(
2951 6049 : __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type);
2952 6049 : __ GotoIfNot(check1, &if_primitive);
2953 :
2954 : Node* value_bit_field =
2955 6049 : __ LoadField(AccessBuilder::ForMapBitField(), value_map);
2956 : Node* check2 =
2957 6049 : __ Word32Equal(__ Int32Constant(0),
2958 : __ Word32And(value_bit_field,
2959 6049 : __ Int32Constant(Map::IsCallableBit::kMask)));
2960 : __ Goto(&done, check2);
2961 :
2962 : __ Bind(&if_primitive);
2963 6049 : __ Goto(&done, __ Int32Constant(0));
2964 :
2965 : __ Bind(&done);
2966 6049 : 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 19633 : Node* EffectControlLinearizer::LowerObjectIsReceiver(Node* node) {
2987 : Node* value = node->InputAt(0);
2988 :
2989 19633 : auto if_smi = __ MakeDeferredLabel();
2990 39266 : auto done = __ MakeLabel(MachineRepresentation::kBit);
2991 :
2992 39266 : __ GotoIf(ObjectIsSmi(value), &if_smi);
2993 :
2994 : STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2995 19633 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2996 : Node* value_instance_type =
2997 19633 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
2998 19633 : Node* result = __ Uint32LessThanOrEqual(
2999 19633 : __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type);
3000 : __ Goto(&done, result);
3001 :
3002 : __ Bind(&if_smi);
3003 19633 : __ Goto(&done, __ Int32Constant(0));
3004 :
3005 : __ Bind(&done);
3006 19633 : return done.PhiAt(0);
3007 : }
3008 :
3009 4133 : Node* EffectControlLinearizer::LowerObjectIsSmi(Node* node) {
3010 : Node* value = node->InputAt(0);
3011 4133 : return ObjectIsSmi(value);
3012 : }
3013 :
3014 2227 : Node* EffectControlLinearizer::LowerObjectIsString(Node* node) {
3015 : Node* value = node->InputAt(0);
3016 :
3017 2227 : auto if_smi = __ MakeDeferredLabel();
3018 4454 : auto done = __ MakeLabel(MachineRepresentation::kBit);
3019 :
3020 2227 : Node* check = ObjectIsSmi(value);
3021 2227 : __ GotoIf(check, &if_smi);
3022 2227 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
3023 : Node* value_instance_type =
3024 2227 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
3025 2227 : Node* vfalse = __ Uint32LessThan(value_instance_type,
3026 2227 : __ Uint32Constant(FIRST_NONSTRING_TYPE));
3027 : __ Goto(&done, vfalse);
3028 :
3029 : __ Bind(&if_smi);
3030 2227 : __ Goto(&done, __ Int32Constant(0));
3031 :
3032 : __ Bind(&done);
3033 2227 : 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 1428 : Node* EffectControlLinearizer::LowerObjectIsUndetectable(Node* node) {
3059 : Node* value = node->InputAt(0);
3060 :
3061 1428 : auto if_smi = __ MakeDeferredLabel();
3062 2856 : auto done = __ MakeLabel(MachineRepresentation::kBit);
3063 :
3064 1428 : Node* check = ObjectIsSmi(value);
3065 1428 : __ GotoIf(check, &if_smi);
3066 :
3067 1428 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
3068 : Node* value_bit_field =
3069 1428 : __ LoadField(AccessBuilder::ForMapBitField(), value_map);
3070 1428 : Node* vfalse = __ Word32Equal(
3071 : __ Word32Equal(
3072 : __ Int32Constant(0),
3073 : __ Word32And(value_bit_field,
3074 : __ Int32Constant(Map::IsUndetectableBit::kMask))),
3075 1428 : __ Int32Constant(0));
3076 : __ Goto(&done, vfalse);
3077 :
3078 : __ Bind(&if_smi);
3079 1428 : __ Goto(&done, __ Int32Constant(0));
3080 :
3081 : __ Bind(&done);
3082 1428 : return done.PhiAt(0);
3083 : }
3084 :
3085 21288 : Node* EffectControlLinearizer::LowerTypeOf(Node* node) {
3086 : Node* obj = node->InputAt(0);
3087 21288 : 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 21288 : graph()->zone(), callable.descriptor(),
3092 21288 : callable.descriptor().GetStackParameterCount(), flags, properties);
3093 63864 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), obj,
3094 42576 : __ NoContextConstant());
3095 : }
3096 :
3097 196 : Node* EffectControlLinearizer::LowerToBoolean(Node* node) {
3098 : Node* obj = node->InputAt(0);
3099 : Callable const callable =
3100 196 : 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 196 : graph()->zone(), callable.descriptor(),
3105 196 : callable.descriptor().GetStackParameterCount(), flags, properties);
3106 588 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), obj,
3107 392 : __ NoContextConstant());
3108 : }
3109 :
3110 16947 : Node* EffectControlLinearizer::LowerArgumentsLength(Node* node) {
3111 16947 : Node* arguments_frame = NodeProperties::GetValueInput(node, 0);
3112 16947 : int formal_parameter_count = FormalParameterCountOf(node->op());
3113 16947 : bool is_rest_length = IsRestLengthOf(node->op());
3114 : DCHECK_LE(0, formal_parameter_count);
3115 :
3116 16947 : 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 16718 : auto if_adaptor_frame = __ MakeLabel();
3146 33436 : auto done = __ MakeLabel(MachineRepresentation::kTaggedSigned);
3147 :
3148 16718 : Node* frame = __ LoadFramePointer();
3149 16718 : __ GotoIf(__ WordEqual(arguments_frame, frame), &done,
3150 16718 : __ SmiConstant(formal_parameter_count));
3151 : __ Goto(&if_adaptor_frame);
3152 :
3153 : __ Bind(&if_adaptor_frame);
3154 16718 : Node* arguments_length = __ Load(
3155 : MachineType::TaggedSigned(), arguments_frame,
3156 16718 : __ IntPtrConstant(ArgumentsAdaptorFrameConstants::kLengthOffset));
3157 : __ Goto(&done, arguments_length);
3158 :
3159 : __ Bind(&done);
3160 : return done.PhiAt(0);
3161 : }
3162 : }
3163 :
3164 16920 : Node* EffectControlLinearizer::LowerArgumentsFrame(Node* node) {
3165 33840 : auto done = __ MakeLabel(MachineType::PointerRepresentation());
3166 :
3167 16920 : Node* frame = __ LoadFramePointer();
3168 : Node* parent_frame =
3169 16920 : __ Load(MachineType::Pointer(), frame,
3170 16920 : __ IntPtrConstant(StandardFrameConstants::kCallerFPOffset));
3171 16920 : Node* parent_frame_type = __ Load(
3172 : MachineType::AnyTagged(), parent_frame,
3173 16920 : __ IntPtrConstant(CommonFrameConstants::kContextOrFrameTypeOffset));
3174 16920 : __ GotoIf(__ WordEqual(parent_frame_type,
3175 : __ IntPtrConstant(StackFrame::TypeToMarker(
3176 : StackFrame::ARGUMENTS_ADAPTOR))),
3177 16920 : &done, parent_frame);
3178 : __ Goto(&done, frame);
3179 :
3180 : __ Bind(&done);
3181 16920 : return done.PhiAt(0);
3182 : }
3183 :
3184 27 : Node* EffectControlLinearizer::LowerNewDoubleElements(Node* node) {
3185 27 : AllocationType const allocation = AllocationTypeOf(node->op());
3186 : Node* length = node->InputAt(0);
3187 :
3188 54 : auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer);
3189 27 : Node* zero_length = __ WordEqual(length, __ IntPtrConstant(0));
3190 54 : __ GotoIf(zero_length, &done,
3191 27 : jsgraph()->HeapConstant(factory()->empty_fixed_array()));
3192 :
3193 : // Compute the effective size of the backing store.
3194 27 : Node* size = __ IntAdd(__ WordShl(length, __ IntPtrConstant(kDoubleSizeLog2)),
3195 27 : __ IntPtrConstant(FixedDoubleArray::kHeaderSize));
3196 :
3197 : // Allocate the result and initialize the header.
3198 27 : Node* result = __ Allocate(allocation, size);
3199 54 : __ StoreField(AccessBuilder::ForMap(), result,
3200 27 : __ FixedDoubleArrayMapConstant());
3201 54 : __ StoreField(AccessBuilder::ForFixedArrayLength(), result,
3202 27 : 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 27 : __ LoadField(AccessBuilder::ForHeapNumberValue(), __ TheHoleConstant());
3209 54 : auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation());
3210 27 : __ Goto(&loop, __ IntPtrConstant(0));
3211 : __ Bind(&loop);
3212 : {
3213 : // Check if we've initialized everything.
3214 : Node* index = loop.PhiAt(0);
3215 27 : Node* check = __ UintLessThan(index, length);
3216 27 : __ GotoIfNot(check, &done, result);
3217 :
3218 : ElementAccess const access = {kTaggedBase, FixedDoubleArray::kHeaderSize,
3219 : Type::NumberOrHole(), MachineType::Float64(),
3220 : kNoWriteBarrier};
3221 27 : __ StoreElement(access, result, index, the_hole);
3222 :
3223 : // Advance the {index}.
3224 27 : index = __ IntAdd(index, __ IntPtrConstant(1));
3225 : __ Goto(&loop, index);
3226 : }
3227 :
3228 : __ Bind(&done);
3229 27 : return done.PhiAt(0);
3230 : }
3231 :
3232 466 : Node* EffectControlLinearizer::LowerNewSmiOrObjectElements(Node* node) {
3233 466 : AllocationType const allocation = AllocationTypeOf(node->op());
3234 : Node* length = node->InputAt(0);
3235 :
3236 932 : auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer);
3237 466 : Node* zero_length = __ WordEqual(length, __ IntPtrConstant(0));
3238 932 : __ GotoIf(zero_length, &done,
3239 466 : jsgraph()->HeapConstant(factory()->empty_fixed_array()));
3240 :
3241 : // Compute the effective size of the backing store.
3242 466 : Node* size = __ IntAdd(__ WordShl(length, __ IntPtrConstant(kTaggedSizeLog2)),
3243 466 : __ IntPtrConstant(FixedArray::kHeaderSize));
3244 :
3245 : // Allocate the result and initialize the header.
3246 466 : Node* result = __ Allocate(allocation, size);
3247 466 : __ StoreField(AccessBuilder::ForMap(), result, __ FixedArrayMapConstant());
3248 932 : __ StoreField(AccessBuilder::ForFixedArrayLength(), result,
3249 466 : ChangeIntPtrToSmi(length));
3250 :
3251 : // Initialize the backing store with holes.
3252 466 : Node* the_hole = __ TheHoleConstant();
3253 932 : auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation());
3254 466 : __ Goto(&loop, __ IntPtrConstant(0));
3255 : __ Bind(&loop);
3256 : {
3257 : // Check if we've initialized everything.
3258 : Node* index = loop.PhiAt(0);
3259 466 : Node* check = __ UintLessThan(index, length);
3260 466 : __ 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 466 : __ StoreElement(access, result, index, the_hole);
3267 :
3268 : // Advance the {index}.
3269 466 : index = __ IntAdd(index, __ IntPtrConstant(1));
3270 : __ Goto(&loop, index);
3271 : }
3272 :
3273 : __ Bind(&done);
3274 466 : return done.PhiAt(0);
3275 : }
3276 :
3277 16443 : Node* EffectControlLinearizer::LowerNewArgumentsElements(Node* node) {
3278 16443 : Node* frame = NodeProperties::GetValueInput(node, 0);
3279 16443 : Node* length = NodeProperties::GetValueInput(node, 1);
3280 16443 : int mapped_count = NewArgumentsElementsMappedCountOf(node->op());
3281 :
3282 : Callable const callable =
3283 16443 : Builtins::CallableFor(isolate(), Builtins::kNewArgumentsElements);
3284 16443 : Operator::Properties const properties = node->op()->properties();
3285 : CallDescriptor::Flags const flags = CallDescriptor::kNoFlags;
3286 : auto call_descriptor = Linkage::GetStubCallDescriptor(
3287 16443 : graph()->zone(), callable.descriptor(),
3288 16443 : callable.descriptor().GetStackParameterCount(), flags, properties);
3289 49329 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), frame,
3290 32886 : length, __ SmiConstant(mapped_count), __ NoContextConstant());
3291 : }
3292 :
3293 5073 : 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 10146 : Node* first_map = __ LoadField(AccessBuilder::ForMap(), first);
3300 : Node* first_instance_type =
3301 5073 : __ LoadField(AccessBuilder::ForMapInstanceType(), first_map);
3302 5073 : Node* second_map = __ LoadField(AccessBuilder::ForMap(), second);
3303 : Node* second_instance_type =
3304 5073 : __ 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 5073 : auto if_onebyte = __ MakeLabel();
3311 5073 : auto if_twobyte = __ MakeLabel();
3312 10146 : auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer);
3313 : STATIC_ASSERT(kOneByteStringTag != 0);
3314 : STATIC_ASSERT(kTwoByteStringTag == 0);
3315 5073 : Node* instance_type = __ Word32And(first_instance_type, second_instance_type);
3316 : Node* encoding =
3317 5073 : __ Word32And(instance_type, __ Int32Constant(kStringEncodingMask));
3318 5073 : __ Branch(__ Word32Equal(encoding, __ Int32Constant(kTwoByteStringTag)),
3319 5073 : &if_twobyte, &if_onebyte);
3320 : __ Bind(&if_onebyte);
3321 10146 : __ Goto(&done,
3322 : jsgraph()->HeapConstant(factory()->cons_one_byte_string_map()));
3323 : __ Bind(&if_twobyte);
3324 10146 : __ 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 5073 : __ Allocate(AllocationType::kYoung, __ IntPtrConstant(ConsString::kSize));
3331 5073 : __ StoreField(AccessBuilder::ForMap(), result, result_map);
3332 10146 : __ StoreField(AccessBuilder::ForNameHashField(), result,
3333 5073 : __ Int32Constant(Name::kEmptyHashField));
3334 5073 : __ StoreField(AccessBuilder::ForStringLength(), result, length);
3335 5073 : __ StoreField(AccessBuilder::ForConsStringFirst(), result, first);
3336 5073 : __ StoreField(AccessBuilder::ForConsStringSecond(), result, second);
3337 5073 : 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 173 : Node* EffectControlLinearizer::LowerSameValueNumbersOnly(Node* node) {
3356 : Node* lhs = node->InputAt(0);
3357 : Node* rhs = node->InputAt(1);
3358 :
3359 : Callable const callable =
3360 173 : Builtins::CallableFor(isolate(), Builtins::kSameValueNumbersOnly);
3361 : Operator::Properties properties = Operator::kEliminatable;
3362 : CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
3363 : auto call_descriptor = Linkage::GetStubCallDescriptor(
3364 173 : graph()->zone(), callable.descriptor(),
3365 173 : callable.descriptor().GetStackParameterCount(), flags, properties);
3366 519 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), lhs, rhs,
3367 346 : __ 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 1322 : Node* EffectControlLinearizer::LowerDeadValue(Node* node) {
3396 1322 : Node* input = NodeProperties::GetValueInput(node, 0);
3397 1322 : if (input->opcode() != IrOpcode::kUnreachable) {
3398 1018 : Node* unreachable = __ Unreachable();
3399 1018 : NodeProperties::ReplaceValueInput(node, unreachable, 0);
3400 : }
3401 1322 : 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 2228 : 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 4456 : MachineType::PointerRepresentation());
3426 : auto loop_next = __ MakeLabel(MachineRepresentation::kTagged,
3427 4456 : MachineType::PointerRepresentation());
3428 4456 : 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 2228 : Node* receiver_map = __ LoadField(AccessBuilder::ForMap(), receiver);
3435 : Node* receiver_instance_type =
3436 2228 : __ LoadField(AccessBuilder::ForMapInstanceType(), receiver_map);
3437 2228 : Node* receiver_representation = __ Word32And(
3438 2228 : receiver_instance_type, __ Int32Constant(kStringRepresentationMask));
3439 :
3440 : // Dispatch on the current {receiver}s string representation.
3441 2228 : auto if_seqstring = __ MakeLabel();
3442 2228 : auto if_consstring = __ MakeLabel();
3443 2228 : auto if_thinstring = __ MakeLabel();
3444 2228 : auto if_externalstring = __ MakeLabel();
3445 2228 : auto if_slicedstring = __ MakeLabel();
3446 2228 : auto if_runtime = __ MakeDeferredLabel();
3447 2228 : __ GotoIf(__ Word32Equal(receiver_representation,
3448 : __ Int32Constant(kSeqStringTag)),
3449 2228 : &if_seqstring);
3450 2228 : __ GotoIf(__ Word32Equal(receiver_representation,
3451 : __ Int32Constant(kConsStringTag)),
3452 2228 : &if_consstring);
3453 2228 : __ GotoIf(__ Word32Equal(receiver_representation,
3454 : __ Int32Constant(kThinStringTag)),
3455 2228 : &if_thinstring);
3456 2228 : __ GotoIf(__ Word32Equal(receiver_representation,
3457 : __ Int32Constant(kExternalStringTag)),
3458 2228 : &if_externalstring);
3459 2228 : __ Branch(__ Word32Equal(receiver_representation,
3460 : __ Int32Constant(kSlicedStringTag)),
3461 2228 : &if_slicedstring, &if_runtime);
3462 :
3463 : __ Bind(&if_seqstring);
3464 : {
3465 2228 : Node* receiver_is_onebyte = __ Word32Equal(
3466 : __ Word32Equal(__ Word32And(receiver_instance_type,
3467 : __ Int32Constant(kStringEncodingMask)),
3468 : __ Int32Constant(kTwoByteStringTag)),
3469 2228 : __ Int32Constant(0));
3470 2228 : 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 2228 : __ LoadField(AccessBuilder::ForThinStringActual(), receiver);
3478 : __ Goto(&loop_next, receiver_actual, position);
3479 : }
3480 :
3481 : __ Bind(&if_consstring);
3482 : {
3483 : Node* receiver_second =
3484 2228 : __ LoadField(AccessBuilder::ForConsStringSecond(), receiver);
3485 2228 : __ GotoIfNot(__ WordEqual(receiver_second, __ EmptyStringConstant()),
3486 2228 : &if_runtime);
3487 : Node* receiver_first =
3488 2228 : __ 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 2228 : __ GotoIf(__ Word32Equal(
3496 : __ Word32And(receiver_instance_type,
3497 : __ Int32Constant(kUncachedExternalStringMask)),
3498 : __ Int32Constant(kUncachedExternalStringTag)),
3499 2228 : &if_runtime);
3500 :
3501 : Node* receiver_data = __ LoadField(
3502 2228 : AccessBuilder::ForExternalStringResourceData(), receiver);
3503 :
3504 2228 : auto if_onebyte = __ MakeLabel();
3505 2228 : auto if_twobyte = __ MakeLabel();
3506 2228 : __ Branch(
3507 : __ Word32Equal(__ Word32And(receiver_instance_type,
3508 : __ Int32Constant(kStringEncodingMask)),
3509 : __ Int32Constant(kTwoByteStringTag)),
3510 2228 : &if_twobyte, &if_onebyte);
3511 :
3512 : __ Bind(&if_onebyte);
3513 : {
3514 2228 : Node* result = __ Load(MachineType::Uint8(), receiver_data, position);
3515 : __ Goto(&loop_done, result);
3516 : }
3517 :
3518 : __ Bind(&if_twobyte);
3519 : {
3520 2228 : Node* result = __ Load(MachineType::Uint16(), receiver_data,
3521 2228 : __ WordShl(position, __ IntPtrConstant(1)));
3522 : __ Goto(&loop_done, result);
3523 : }
3524 : }
3525 :
3526 : __ Bind(&if_slicedstring);
3527 : {
3528 : Node* receiver_offset =
3529 2228 : __ LoadField(AccessBuilder::ForSlicedStringOffset(), receiver);
3530 : Node* receiver_parent =
3531 2228 : __ LoadField(AccessBuilder::ForSlicedStringParent(), receiver);
3532 2228 : __ Goto(&loop_next, receiver_parent,
3533 : __ IntAdd(position, ChangeSmiToIntPtr(receiver_offset)));
3534 : }
3535 :
3536 : __ Bind(&if_runtime);
3537 : {
3538 2228 : Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
3539 : Runtime::FunctionId id = Runtime::kStringCharCodeAt;
3540 2228 : auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
3541 2228 : graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags);
3542 2228 : Node* result = __ Call(call_descriptor, __ CEntryStubConstant(1),
3543 : receiver, ChangeIntPtrToSmi(position),
3544 : __ ExternalConstant(ExternalReference::Create(id)),
3545 2228 : __ Int32Constant(2), __ NoContextConstant());
3546 2228 : __ 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 2228 : 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 2228 : Node* EffectControlLinearizer::LoadFromSeqString(Node* receiver, Node* position,
3576 : Node* is_one_byte) {
3577 2228 : auto one_byte_load = __ MakeLabel();
3578 4456 : auto done = __ MakeLabel(MachineRepresentation::kWord32);
3579 2228 : __ GotoIf(is_one_byte, &one_byte_load);
3580 : Node* two_byte_result = __ LoadElement(
3581 2228 : AccessBuilder::ForSeqTwoByteStringCharacter(), receiver, position);
3582 : __ Goto(&done, two_byte_result);
3583 :
3584 : __ Bind(&one_byte_load);
3585 : Node* one_byte_element = __ LoadElement(
3586 2228 : AccessBuilder::ForSeqOneByteStringCharacter(), receiver, position);
3587 : __ Goto(&done, one_byte_element);
3588 :
3589 : __ Bind(&done);
3590 2228 : return done.PhiAt(0);
3591 : }
3592 :
3593 938 : Node* EffectControlLinearizer::LowerStringFromSingleCharCode(Node* node) {
3594 : Node* value = node->InputAt(0);
3595 938 : Node* code = __ Word32And(value, __ Uint32Constant(0xFFFF));
3596 :
3597 938 : auto if_not_one_byte = __ MakeDeferredLabel();
3598 938 : auto cache_miss = __ MakeDeferredLabel();
3599 1876 : auto done = __ MakeLabel(MachineRepresentation::kTagged);
3600 :
3601 : // Check if the {code} is a one byte character
3602 938 : Node* check1 = __ Uint32LessThanOrEqual(
3603 938 : code, __ Uint32Constant(String::kMaxOneByteCharCode));
3604 938 : __ GotoIfNot(check1, &if_not_one_byte);
3605 : {
3606 : // Load the isolate wide single character string cache.
3607 938 : Node* cache = __ HeapConstant(factory()->single_character_string_cache());
3608 :
3609 : // Compute the {cache} index for {code}.
3610 938 : 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 938 : __ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index);
3616 :
3617 938 : Node* check2 = __ WordEqual(entry, __ UndefinedConstant());
3618 938 : __ 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 938 : __ Allocate(AllocationType::kYoung,
3628 938 : __ IntPtrConstant(SeqOneByteString::SizeFor(1)));
3629 1876 : __ StoreField(AccessBuilder::ForMap(), vtrue2,
3630 938 : __ HeapConstant(factory()->one_byte_string_map()));
3631 1876 : __ StoreField(AccessBuilder::ForNameHashField(), vtrue2,
3632 938 : __ Int32Constant(Name::kEmptyHashField));
3633 1876 : __ StoreField(AccessBuilder::ForStringLength(), vtrue2,
3634 938 : __ Int32Constant(1));
3635 1876 : __ Store(
3636 : StoreRepresentation(MachineRepresentation::kWord8, kNoWriteBarrier),
3637 : vtrue2,
3638 : __ IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag),
3639 938 : code);
3640 :
3641 : // Remember it in the {cache}.
3642 1876 : __ StoreElement(AccessBuilder::ForFixedArrayElement(), cache, index,
3643 938 : 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 938 : __ Allocate(AllocationType::kYoung,
3653 938 : __ IntPtrConstant(SeqTwoByteString::SizeFor(1)));
3654 1876 : __ StoreField(AccessBuilder::ForMap(), vfalse1,
3655 938 : __ HeapConstant(factory()->string_map()));
3656 1876 : __ StoreField(AccessBuilder::ForNameHashField(), vfalse1,
3657 938 : __ Int32Constant(Name::kEmptyHashField));
3658 1876 : __ StoreField(AccessBuilder::ForStringLength(), vfalse1,
3659 938 : __ Int32Constant(1));
3660 1876 : __ Store(
3661 : StoreRepresentation(MachineRepresentation::kWord16, kNoWriteBarrier),
3662 : vfalse1,
3663 : __ IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag),
3664 938 : code);
3665 : __ Goto(&done, vfalse1);
3666 : }
3667 :
3668 : __ Bind(&done);
3669 938 : return done.PhiAt(0);
3670 : }
3671 :
3672 : #ifdef V8_INTL_SUPPORT
3673 :
3674 93 : Node* EffectControlLinearizer::LowerStringToLowerCaseIntl(Node* node) {
3675 : Node* receiver = node->InputAt(0);
3676 :
3677 : Callable callable =
3678 93 : Builtins::CallableFor(isolate(), Builtins::kStringToLowerCaseIntl);
3679 93 : Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
3680 : CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
3681 : auto call_descriptor = Linkage::GetStubCallDescriptor(
3682 93 : graph()->zone(), callable.descriptor(),
3683 93 : callable.descriptor().GetStackParameterCount(), flags, properties);
3684 279 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), receiver,
3685 186 : __ 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 266 : 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 266 : Builtins::CallableFor(isolate(), Builtins::kStringIndexOf);
3853 : Operator::Properties properties = Operator::kEliminatable;
3854 : CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
3855 : auto call_descriptor = Linkage::GetStubCallDescriptor(
3856 266 : graph()->zone(), callable.descriptor(),
3857 266 : callable.descriptor().GetStackParameterCount(), flags, properties);
3858 798 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), subject,
3859 532 : search_string, position, __ NoContextConstant());
3860 : }
3861 :
3862 24360 : Node* EffectControlLinearizer::LowerStringLength(Node* node) {
3863 : Node* subject = node->InputAt(0);
3864 :
3865 48720 : return __ LoadField(AccessBuilder::ForStringLength(), subject);
3866 : }
3867 :
3868 11098 : 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 11098 : graph()->zone(), callable.descriptor(),
3877 11098 : callable.descriptor().GetStackParameterCount(), flags, properties);
3878 33294 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), lhs, rhs,
3879 22196 : __ NoContextConstant());
3880 : }
3881 :
3882 1085 : 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 1085 : Builtins::CallableFor(isolate(), Builtins::kStringSubstring);
3889 : Operator::Properties properties = Operator::kEliminatable;
3890 : CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
3891 : auto call_descriptor = Linkage::GetStubCallDescriptor(
3892 1085 : graph()->zone(), callable.descriptor(),
3893 1085 : callable.descriptor().GetStackParameterCount(), flags, properties);
3894 3255 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), receiver,
3895 2170 : start, end, __ NoContextConstant());
3896 : }
3897 :
3898 10276 : Node* EffectControlLinearizer::LowerStringEqual(Node* node) {
3899 : return LowerStringComparison(
3900 20552 : 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 701 : Node* EffectControlLinearizer::LowerStringLessThanOrEqual(Node* node) {
3909 : return LowerStringComparison(
3910 1402 : Builtins::CallableFor(isolate(), Builtins::kStringLessThanOrEqual), node);
3911 : }
3912 :
3913 474 : 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 474 : CheckFloat64HoleParametersOf(node->op());
3920 : Node* value = node->InputAt(0);
3921 :
3922 474 : auto if_nan = __ MakeDeferredLabel();
3923 474 : auto done = __ MakeLabel();
3924 :
3925 : // First check whether {value} is a NaN at all...
3926 474 : __ 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 474 : Node* check = __ Word32Equal(__ Float64ExtractHighWord32(value),
3933 474 : __ Int32Constant(kHoleNanUpper32));
3934 : __ DeoptimizeIf(DeoptimizeReason::kHole, params.feedback(), check,
3935 474 : frame_state);
3936 : __ Goto(&done);
3937 : }
3938 :
3939 : __ Bind(&done);
3940 474 : return value;
3941 : }
3942 :
3943 104 : Node* EffectControlLinearizer::LowerCheckNotTaggedHole(Node* node,
3944 : Node* frame_state) {
3945 : Node* value = node->InputAt(0);
3946 104 : Node* check = __ WordEqual(value, __ TheHoleConstant());
3947 208 : __ DeoptimizeIf(DeoptimizeReason::kHole, VectorSlotPair(), check,
3948 104 : frame_state);
3949 104 : return value;
3950 : }
3951 :
3952 1667 : Node* EffectControlLinearizer::LowerConvertTaggedHoleToUndefined(Node* node) {
3953 : Node* value = node->InputAt(0);
3954 :
3955 1667 : auto if_is_hole = __ MakeDeferredLabel();
3956 3334 : auto done = __ MakeLabel(MachineRepresentation::kTagged);
3957 :
3958 1667 : Node* check = __ WordEqual(value, __ TheHoleConstant());
3959 1667 : __ GotoIf(check, &if_is_hole);
3960 : __ Goto(&done, value);
3961 :
3962 : __ Bind(&if_is_hole);
3963 1667 : __ Goto(&done, __ UndefinedConstant());
3964 :
3965 : __ Bind(&done);
3966 1667 : 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 54787 : Node* EffectControlLinearizer::AllocateHeapNumberWithValue(Node* value) {
4056 : Node* result =
4057 54787 : __ Allocate(AllocationType::kYoung, __ IntPtrConstant(HeapNumber::kSize));
4058 54787 : __ StoreField(AccessBuilder::ForMap(), result, __ HeapNumberMapConstant());
4059 54787 : __ StoreField(AccessBuilder::ForHeapNumberValue(), result, value);
4060 54787 : return result;
4061 : }
4062 :
4063 134689 : 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 134689 : return __ WordShl(value, SmiShiftBitsConstant());
4070 : }
4071 :
4072 0 : Node* EffectControlLinearizer::ChangeInt32ToIntPtr(Node* value) {
4073 133889 : if (machine()->Is64()) {
4074 133889 : 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 131719 : 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 131719 : 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 678 : if (machine()->Is64()) {
4101 678 : value = __ ChangeUint32ToUint64(value);
4102 : }
4103 0 : return value;
4104 : }
4105 :
4106 662 : 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 662 : return __ WordShl(ChangeUint32ToUintPtr(value), SmiShiftBitsConstant());
4112 : }
4113 : }
4114 :
4115 149306 : 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 149307 : return __ WordSar(value, SmiShiftBitsConstant());
4122 : }
4123 :
4124 146643 : 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 146643 : if (machine()->Is64()) {
4130 293288 : return __ TruncateInt64ToInt32(ChangeSmiToIntPtr(value));
4131 : }
4132 0 : return ChangeSmiToIntPtr(value);
4133 : }
4134 :
4135 387 : Node* EffectControlLinearizer::ChangeSmiToInt64(Node* value) {
4136 387 : CHECK(machine()->Is64());
4137 387 : return ChangeSmiToIntPtr(value);
4138 : }
4139 :
4140 256796 : Node* EffectControlLinearizer::ObjectIsSmi(Node* value) {
4141 256796 : return __ WordEqual(__ WordAnd(value, __ IntPtrConstant(kSmiTagMask)),
4142 256799 : __ IntPtrConstant(kSmiTag));
4143 : }
4144 :
4145 0 : Node* EffectControlLinearizer::SmiMaxValueConstant() {
4146 662 : return __ Int32Constant(Smi::kMaxValue);
4147 : }
4148 :
4149 0 : Node* EffectControlLinearizer::SmiShiftBitsConstant() {
4150 : if (machine()->Is64() && SmiValuesAre31Bits()) {
4151 : return __ Int32Constant(kSmiShiftSize + kSmiTagSize);
4152 : }
4153 284657 : 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 1648 : Node* EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node) {
4217 : Node* object = node->InputAt(0);
4218 : Node* elements = node->InputAt(1);
4219 :
4220 1648 : auto if_not_fixed_array = __ MakeDeferredLabel();
4221 3296 : auto done = __ MakeLabel(MachineRepresentation::kTagged);
4222 :
4223 : // Load the current map of {elements}.
4224 3296 : Node* elements_map = __ LoadField(AccessBuilder::ForMap(), elements);
4225 :
4226 : // Check if {elements} is not a copy-on-write FixedArray.
4227 1648 : Node* check = __ WordEqual(elements_map, __ FixedArrayMapConstant());
4228 1648 : __ 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 1648 : Builtins::CallableFor(isolate(), Builtins::kCopyFastSmiOrObjectElements);
4237 : CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
4238 : auto call_descriptor = Linkage::GetStubCallDescriptor(
4239 1648 : graph()->zone(), callable.descriptor(),
4240 1648 : callable.descriptor().GetStackParameterCount(), flags, properties);
4241 4944 : Node* result = __ Call(call_descriptor, __ HeapConstant(callable.code()),
4242 1648 : object, __ NoContextConstant());
4243 : __ Goto(&done, result);
4244 :
4245 : __ Bind(&done);
4246 1648 : return done.PhiAt(0);
4247 : }
4248 :
4249 3481 : Node* EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node,
4250 : Node* frame_state) {
4251 3481 : 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 6962 : auto done = __ MakeLabel(MachineRepresentation::kTagged);
4258 3481 : auto if_grow = __ MakeDeferredLabel();
4259 : auto if_not_grow = __ MakeLabel();
4260 :
4261 : // Check if we need to grow the {elements} backing store.
4262 3481 : Node* check = __ Uint32LessThan(index, elements_length);
4263 3481 : __ 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 3481 : Builtins::kGrowFastSmiOrObjectElements);
4274 : CallDescriptor::Flags call_flags = CallDescriptor::kNoFlags;
4275 : auto call_descriptor = Linkage::GetStubCallDescriptor(
4276 3481 : graph()->zone(), callable.descriptor(),
4277 3481 : callable.descriptor().GetStackParameterCount(), call_flags, properties);
4278 : Node* new_elements =
4279 10443 : __ Call(call_descriptor, __ HeapConstant(callable.code()), object,
4280 3481 : ChangeInt32ToSmi(index), __ NoContextConstant());
4281 :
4282 : // Ensure that we were able to grow the {elements}.
4283 3481 : __ DeoptimizeIf(DeoptimizeReason::kCouldNotGrowElements, params.feedback(),
4284 3481 : ObjectIsSmi(new_elements), frame_state);
4285 : __ Goto(&done, new_elements);
4286 :
4287 : __ Bind(&done);
4288 3481 : return done.PhiAt(0);
4289 : }
4290 :
4291 634 : void EffectControlLinearizer::LowerTransitionElementsKind(Node* node) {
4292 634 : ElementsTransition const transition = ElementsTransitionOf(node->op());
4293 : Node* object = node->InputAt(0);
4294 :
4295 634 : auto if_map_same = __ MakeDeferredLabel();
4296 634 : auto done = __ MakeLabel();
4297 :
4298 634 : Node* source_map = __ HeapConstant(transition.source());
4299 634 : Node* target_map = __ HeapConstant(transition.target());
4300 :
4301 : // Load the current map of {object}.
4302 634 : Node* object_map = __ LoadField(AccessBuilder::ForMap(), object);
4303 :
4304 : // Check if {object_map} is the same as {source_map}.
4305 634 : Node* check = __ WordEqual(object_map, source_map);
4306 634 : __ GotoIf(check, &if_map_same);
4307 : __ Goto(&done);
4308 :
4309 : __ Bind(&if_map_same);
4310 634 : 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 402 : Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
4318 : Runtime::FunctionId id = Runtime::kTransitionElementsKind;
4319 402 : auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
4320 402 : graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags);
4321 402 : __ Call(call_descriptor, __ CEntryStubConstant(1), object, target_map,
4322 : __ ExternalConstant(ExternalReference::Create(id)),
4323 402 : __ Int32Constant(2), __ NoContextConstant());
4324 : break;
4325 : }
4326 : }
4327 : __ Goto(&done);
4328 :
4329 : __ Bind(&done);
4330 634 : }
4331 :
4332 7221 : Node* EffectControlLinearizer::LowerLoadMessage(Node* node) {
4333 : Node* offset = node->InputAt(0);
4334 : Node* object_pattern =
4335 14442 : __ LoadField(AccessBuilder::ForExternalIntPtr(), offset);
4336 7221 : return __ BitcastWordToTagged(object_pattern);
4337 : }
4338 :
4339 29729 : void EffectControlLinearizer::LowerStoreMessage(Node* node) {
4340 : Node* offset = node->InputAt(0);
4341 : Node* object = node->InputAt(1);
4342 29729 : Node* object_pattern = __ BitcastTaggedToWord(object);
4343 29729 : __ StoreField(AccessBuilder::ForExternalIntPtr(), offset, object_pattern);
4344 29729 : }
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 4527 : Node* EffectControlLinearizer::LowerLoadTypedElement(Node* node) {
4601 4527 : 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 4527 : __ 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 4527 : : __ UnsafePointerAdd(base, external);
4617 :
4618 : // Perform the actual typed element access.
4619 9054 : return __ LoadElement(AccessBuilder::ForTypedArrayElement(
4620 : array_type, true, LoadSensitivity::kCritical),
4621 9054 : storage, index);
4622 : }
4623 :
4624 4368 : void EffectControlLinearizer::LowerStoreTypedElement(Node* node) {
4625 4368 : 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 4368 : __ 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 4368 : : __ UnsafePointerAdd(base, external);
4642 :
4643 : // Perform the actual typed element access.
4644 8736 : __ StoreElement(AccessBuilder::ForTypedArrayElement(array_type, true),
4645 4368 : storage, index, value);
4646 4368 : }
4647 :
4648 326 : 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 326 : : DoubleMapParameterOf(node->op()));
4656 326 : Node* target_map = __ HeapConstant(target);
4657 :
4658 326 : if (IsSimpleMapChangeTransition(from, to)) {
4659 106 : __ StoreField(AccessBuilder::ForMap(), array, target_map);
4660 : } else {
4661 : // Instance migration, call out to the runtime for {array}.
4662 220 : Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
4663 : Runtime::FunctionId id = Runtime::kTransitionElementsKind;
4664 220 : auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
4665 220 : graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags);
4666 220 : __ Call(call_descriptor, __ CEntryStubConstant(1), array, target_map,
4667 : __ ExternalConstant(ExternalReference::Create(id)),
4668 220 : __ Int32Constant(2), __ NoContextConstant());
4669 : }
4670 326 : }
4671 :
4672 0 : Node* EffectControlLinearizer::IsElementsKindGreaterThan(
4673 : Node* kind, ElementsKind reference_kind) {
4674 396 : Node* ref_kind = __ Int32Constant(reference_kind);
4675 396 : 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 20 : 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 40 : Node* map = __ LoadField(AccessBuilder::ForMap(), array);
4902 : Node* kind;
4903 : {
4904 20 : Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map);
4905 20 : Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask);
4906 20 : Node* andit = __ Word32And(bit_field2, mask);
4907 20 : Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift);
4908 20 : kind = __ Word32Shr(andit, shift);
4909 : }
4910 :
4911 20 : auto do_store = __ MakeLabel();
4912 :
4913 20 : auto transition_smi_array = __ MakeDeferredLabel();
4914 20 : auto transition_double_to_fast = __ MakeDeferredLabel();
4915 : {
4916 : __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
4917 20 : &transition_smi_array);
4918 : __ GotoIf(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
4919 20 : &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 20 : TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS);
4927 : __ Goto(&do_store);
4928 : }
4929 :
4930 : __ Bind(&transition_double_to_fast); // deferred code.
4931 : {
4932 20 : TransitionElementsTo(node, array, HOLEY_DOUBLE_ELEMENTS, HOLEY_ELEMENTS);
4933 : __ Goto(&do_store);
4934 : }
4935 :
4936 : __ Bind(&do_store);
4937 :
4938 20 : Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array);
4939 : // Our ElementsKind is HOLEY_ELEMENTS.
4940 20 : ElementAccess access = AccessBuilder::ForFixedArrayElement(HOLEY_ELEMENTS);
4941 20 : Type value_type = ValueTypeParameterOf(node->op());
4942 20 : if (value_type.Is(Type::BooleanOrNullOrUndefined())) {
4943 16 : access.type = value_type;
4944 16 : access.write_barrier_kind = kNoWriteBarrier;
4945 : }
4946 20 : __ StoreElement(access, elements, index, value);
4947 20 : }
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 2554 : void EffectControlLinearizer::LowerRuntimeAbort(Node* node) {
5008 2554 : AbortReason reason = AbortReasonOf(node->op());
5009 2554 : Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
5010 : Runtime::FunctionId id = Runtime::kAbort;
5011 2554 : auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
5012 2554 : graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
5013 5108 : __ Call(call_descriptor, __ CEntryStubConstant(1),
5014 : jsgraph()->SmiConstant(static_cast<int>(reason)),
5015 : __ ExternalConstant(ExternalReference::Create(id)),
5016 2554 : __ Int32Constant(1), __ NoContextConstant());
5017 2554 : }
5018 :
5019 874 : Node* EffectControlLinearizer::LowerConvertReceiver(Node* node) {
5020 874 : ConvertReceiverMode const mode = ConvertReceiverModeOf(node->op());
5021 : Node* value = node->InputAt(0);
5022 : Node* global_proxy = node->InputAt(1);
5023 :
5024 874 : switch (mode) {
5025 : case ConvertReceiverMode::kNullOrUndefined: {
5026 : return global_proxy;
5027 : }
5028 : case ConvertReceiverMode::kNotNullOrUndefined: {
5029 808 : auto convert_to_object = __ MakeDeferredLabel();
5030 1616 : auto done_convert = __ MakeLabel(MachineRepresentation::kTagged);
5031 :
5032 : // Check if {value} is already a JSReceiver.
5033 1616 : __ GotoIf(ObjectIsSmi(value), &convert_to_object);
5034 : STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
5035 808 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
5036 : Node* value_instance_type =
5037 808 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
5038 808 : Node* check = __ Uint32LessThan(
5039 808 : value_instance_type, __ Uint32Constant(FIRST_JS_RECEIVER_TYPE));
5040 808 : __ 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 808 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
5047 : CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
5048 : auto call_descriptor = Linkage::GetStubCallDescriptor(
5049 808 : graph()->zone(), callable.descriptor(),
5050 808 : callable.descriptor().GetStackParameterCount(), flags, properties);
5051 : Node* native_context = __ LoadField(
5052 808 : AccessBuilder::ForJSGlobalProxyNativeContext(), global_proxy);
5053 1616 : Node* result = __ Call(call_descriptor, __ HeapConstant(callable.code()),
5054 808 : 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 66 : auto convert_to_object = __ MakeDeferredLabel();
5062 66 : auto convert_global_proxy = __ MakeDeferredLabel();
5063 132 : auto done_convert = __ MakeLabel(MachineRepresentation::kTagged);
5064 :
5065 : // Check if {value} is already a JSReceiver, or null/undefined.
5066 132 : __ GotoIf(ObjectIsSmi(value), &convert_to_object);
5067 : STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
5068 66 : Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
5069 : Node* value_instance_type =
5070 66 : __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
5071 66 : Node* check = __ Uint32LessThan(
5072 66 : value_instance_type, __ Uint32Constant(FIRST_JS_RECEIVER_TYPE));
5073 66 : __ 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 66 : __ GotoIf(__ WordEqual(value, __ UndefinedConstant()),
5079 66 : &convert_global_proxy);
5080 66 : __ GotoIf(__ WordEqual(value, __ NullConstant()), &convert_global_proxy);
5081 : Operator::Properties properties = Operator::kEliminatable;
5082 66 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
5083 : CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
5084 : auto call_descriptor = Linkage::GetStubCallDescriptor(
5085 66 : graph()->zone(), callable.descriptor(),
5086 66 : callable.descriptor().GetStackParameterCount(), flags, properties);
5087 : Node* native_context = __ LoadField(
5088 66 : AccessBuilder::ForJSGlobalProxyNativeContext(), global_proxy);
5089 132 : Node* result = __ Call(call_descriptor, __ HeapConstant(callable.code()),
5090 66 : 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 8222 : Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundUp(Node* node) {
5107 : // Nothing to be done if a fast hardware instruction is available.
5108 8222 : 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 175 : Node* EffectControlLinearizer::LowerFindOrderedHashMapEntry(Node* node) {
5438 175 : Node* table = NodeProperties::GetValueInput(node, 0);
5439 175 : Node* key = NodeProperties::GetValueInput(node, 1);
5440 :
5441 : {
5442 : Callable const callable =
5443 175 : Builtins::CallableFor(isolate(), Builtins::kFindOrderedHashMapEntry);
5444 175 : Operator::Properties const properties = node->op()->properties();
5445 : CallDescriptor::Flags const flags = CallDescriptor::kNoFlags;
5446 : auto call_descriptor = Linkage::GetStubCallDescriptor(
5447 175 : graph()->zone(), callable.descriptor(),
5448 175 : callable.descriptor().GetStackParameterCount(), flags, properties);
5449 525 : return __ Call(call_descriptor, __ HeapConstant(callable.code()), table,
5450 350 : 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
|