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