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